基于Python实现大规模光栅人口数据可视化( 二 )

此代码块将输出以下的视觉效果:

基于Python实现大规模光栅人口数据可视化

文章插图
欧洲的人口分布图(作者本人提供的图片)
此绘制中,使用“火”色图似乎是一个行业标准,这是有充分理由的;然而,如果你想把事情搞混,你可以在链接https://colorcet.holoviz.org/处找到其他配色方案,并使用类似于下面的编程方式:
#创建数据着色器画布cvs = ds.Canvas(plot_width=size, plot_height=int(asp*size))raster = cvs.raster(data_array_c)# 绘制图像cmap = palette["bmw"]img = tf.shade(raster, how="eq_hist", cmap=cmap)img = tf.set_background(img, "black")img此代码块输出以下形式的视觉效果:
基于Python实现大规模光栅人口数据可视化

文章插图
欧洲的人口分布图另一种色图(作者本人提供的图片)
2.3.可视化全球人口数据到此,我们已经取得了全球人口数据,但如果你手边仅有一台普通的电脑,仍然想以100米的分辨率可视化整个世界 , 那该怎么办呢?我将在这里向您展示的解决方法非常简单——我将整个光栅图像分割成大约一百个较小的片断 。这样一来,我的计算机就可以一个接一个地很好地处理它们,然后使用一些图像处理技巧将它们合并到一个图像文件中 。
然而,在继续介绍之前,还有一个细节需要说明 。我们可以通过以下方式对XArray数组降低采样率——然而,我找不到一个合适的降低尺度的方法来处理整个数据集 。此外 , 我不想失去准确性,希望看到整个数据集的真实面貌 。
# 对数据进行降低采样率的快速方法downsampling_factor = 20downsampled_data_array = data_array.coarsen(x=downsampling_factor, y=downsampling_factor).mean()downsampled_data_array最后的输出结果不错,不亚于之前绘制的data_array:
基于Python实现大规模光栅人口数据可视化

文章插图
为了实现将整个光栅图像分割为网格段,首先 , 获取其边界并将N定义为步长 。然后,创建图像片段边界列表 。
minx = float(data_array.x.min().values)maxx = float(data_array.x.max().values)miny = float(data_array.y.min().values)maxy = float(data_array.y.max().values)N = 10xstep = (maxx-minx) / Nystep = (maxy-miny) / Nxsteps = list(np.arange(minx, maxx, xstep)) ysteps = list(np.arange(miny, maxy, ystep))现在,在每个x和y步骤上迭代,并创建每个图像片段,其中每个图像文件都以其在原始网格中的位置命名 。此循环可能需要一段时间 。
import osfoldout = 'world_map_image_segments'if not os.path.exists(foldout): os.makedirs(foldout)for idx_x, x_coord in enumerate(xsteps): for idx_y, y_coord in enumerate(ysteps): if not os.path.exists(foldout+'/'+str(idx_x)+'_'+str(idx_y)+'.png'): data_array_c = data_array.rio.clip_box( minx=x_coord, miny=y_coord, maxx=x_coord+xstep, maxy=y_coord+ystep) data_array_c = xr.DataArray(data_array_c)[0] data_array_c = data_array_c.fillna(0) data_array_c = data_array_c.where(data_array_c > 0) data_array_c = data_array_c.compute() data_array_c = np.flip(data_array_c, 0) size = 2000 asp = data_array_c.shape[0] / data_array_c.shape[1] cvs = ds.Canvas(plot_width=size, plot_height=int(asp*size)) raster = cvs.raster(data_array_c) cmap = palette["fire"] img = tf.shade(raster, how="eq_hist", cmap=cmap) img = tf.set_background(img, "black") pil_image = img.to_pil() pil_image.save(foldout+'/'+str(idx_x)+'_'+str(idx_y)+ '.png') print('SAVED: ', x_coord, y_coord, y_coord+xstep,y_coord+ystep)最后,如果我们拥有所有的图像片段 , 我们可以使用以下函数快速地把它们组合到一起 。对于这段代码,我还要求ChatGPT提供一些提示来加快速度,但和往常一样,这个过程也需要一些手动调整 。
from PIL import Imagedef find_dimensions(image_dir): max_x = 0 max_y = 0 for filename in os.listdir(image_dir): if filename.endswith(".png"): x, y = map(int, os.path.splitext(filename)[0].split("_")) max_x = max(max_x, x) max_y = max(max_y, y) return max_x + 1, max_y + 1 image_dir = foldoutsegment_width = sizesegment_height = int(asp*size)# 确定大图像的尺寸large_image_width, large_image_height = find_dimensions(image_dir)# 创建一个空的大图像(白色背景)large_image = Image.new("RGB", (large_image_width * segment_width, large_image_height * segment_height), "black")# 循环浏览各个图像片段并将它们粘贴到大图像中for filename in sorted(os.listdir(image_dir)): if filename.endswith(".png"): x, y = map(int, os.path.splitext(filename)[0].split("_")) segment_image = Image.open(os.path.join(image_dir, filename)) x_offset = x * segment_width y_offset = large_image_height * segment_height-1*y * segment_height large_image.paste(segment_image, (x_offset, y_offset))# 保存合并后的大图像large_image.save("global_population_map.png")


推荐阅读