Python | 基于栅格数据绘制空间分布、频率分布和剖面图

职场   2024-12-31 08:07   陕西  
各位同学大家好,昨天我们分享了如何使用 Python 绘制简单的空间分布图,Python | 基于栅格数据绘制空间分布图。根据同学们的需求,今天我们将进一步介绍如何绘制频率分布直方图和剖面图。
一、相关图片
给大家展示一些顶刊中的相关图片,帮助大家更好地理解这些图表的应用:
https://doi.org/10.1111/gcb.15373
https://doi.org/10.3390/rs16132368
https://doi.org/10.1073/pnas.2120662119
https://doi.org/10.1073/pnas.2300981120

https://doi.org/10.1080/17538947.2024.2404232
在这些图中,空间分布图能帮助我们清晰地看到数据在不同地区的分布情况,直观揭示各地的数据差异;频率分布图展示了数据的整体分布模式,让我们了解数据值的高低及其分布范围;而剖面图则通过展示某条线上的数据变化,帮助我们理解数据在特定方向上的变化趋势。今天,我们将结合自己的研究内容,绘制类似的图片,给大家提供参考。
二、Python代码
这是我们输出的效果图:
代码的第一行已经提供了示例数据的百度网盘链接,大家可以下载并运行。代码已经尽量简化,容易理解。大家只需更改以下几个部分即可:16行栅格数据的输入路径、26行栅格数据的有效值范围、53行图标题、69和79行图例刻度、74行图例标题、83行剖面图刻度和130行图片输出路径。
#示例数据 https://pan.baidu.com/s/1kCV24MVFyXtKfnVtds_iKQ?pwd=dec3 提取码: dec3import matplotlibmatplotlib.use('TkAgg')import numpy as npimport rasterioimport matplotlib.pyplot as pltimport cartopy.crs as ccrsimport cartopy.feature as cfeaturefrom cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
# 配置字体plt.rcParams['font.sans-serif'] = ['Times New Roman']plt.rcParams['axes.unicode_minus'] = False
# 栅格数据路径tif_path = r"D:\PML_WUE等\出图\空间分布\T_ET_MEAN.tif"
with rasterio.open(tif_path) as src: data = src.read(1) # 读取第一个波段数据 lon_min, lat_min, lon_max, lat_max = src.bounds # 获取地理范围 transform = src.transform # 获取仿射变换参数
data = np.flipud(data)
# 去除异常值data[data > 1] = np.nandata[data <= 0] = np.nan
# 检查数据范围print(f"数据范围:最小值={np.nanmin(data)}, 最大值={np.nanmax(data)}")
# 生成经纬度网格lon = np.linspace(lon_min, lon_max, data.shape[1])lat = np.linspace(lat_min, lat_max, data.shape[0])
# 裁剪纬度范围为 -60 到 90lat_mask = (lat >= -60) & (lat <= 90)lat = lat[lat_mask]data = data[lat_mask, :]
lon, lat = np.meshgrid(lon, lat)
# 计算随纬度变化的平均值lat_mean = np.nanmean(data, axis=1)
# 绘图函数# 绘图函数def plot_combined(): fig = plt.figure(figsize=(12, 6))
# 空间分布图 ax_map = fig.add_axes([0.05, 0.1, 0.6, 0.6], projection=ccrs.PlateCarree()) ax_map.set_title('Annual average of T/ET', loc='left', fontsize=16)
# 设置显示范围(-60到90纬度) ax_map.set_extent([lon_min, lon_max, -60, 90], crs=ccrs.PlateCarree())
# 添加海岸线并加粗边框 ax_map.add_feature(cfeature.COASTLINE.with_scale('110m'), linewidth=0.9)
# 设置经纬度刻度 ax_map.set_xticks(np.arange(-180, 181, 60), crs=ccrs.PlateCarree()) ax_map.set_yticks(np.arange(-60, 91, 30), crs=ccrs.PlateCarree()) ax_map.xaxis.set_major_formatter(LongitudeFormatter()) ax_map.yaxis.set_major_formatter(LatitudeFormatter()) ax_map.tick_params(labelsize=10)
# 绘制等值线图 levels = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] contour = ax_map.contourf(lon, lat, data, levels=levels, cmap='RdYlGn', extend='both', transform=ccrs.PlateCarree())
# 设置图例 cbar = plt.colorbar(contour, ax=ax_map, orientation='horizontal', pad=0.08, aspect=50, format='%.2f') cbar.set_label('T/ET', fontsize=18) cbar.ax.tick_params(labelsize=14) cbar.set_ticks([0,0.2,0.4,0.6,0.8,1])
# 剖面图 ax_profile = fig.add_axes([0.65, 0.237, 0.08, 0.463]) # 确保与空间分布图对齐 ax_profile.plot(lat_mean, lat, color='black', linewidth=0.8) # 颜色改为黑色
# 设置剖面图样式 ax_profile.set_xlim(0, 1) ax_profile.set_ylim(-60, 90) ax_profile.grid(True, linestyle='--', alpha=0.5)
# 去除纵坐标刻度和注释 ax_profile.yaxis.set_visible(False)
# 去除标题 ax_profile.set_title('')
# 横坐标保留刻度但设置字体大小为10号 ax_profile.tick_params(axis='x', labelsize=10)
# 频数分布直方图 ax_hist = fig.add_axes([0.08, 0.25, 0.1, 0.25]) # 左侧直方图位置,高度为 1/4,宽度为 1/3 flattened_data = data.flatten() flattened_data = flattened_data[~np.isnan(flattened_data)] # 去除 NaN
# 计算频数和相对百分比 counts, bin_edges = np.histogram(flattened_data, bins=levels) percentages = counts / counts.sum() * 100 # 百分比
# 计算固定宽度 bar_width = (levels[1] - levels[0]) # 每个柱子的宽度相等
# 绘制柱子并上色 for i in range(len(levels) - 1): ax_hist.bar( levels[i] + bar_width / 2, percentages[i], width=bar_width, color=plt.cm.RdYlGn((levels[i] + levels[i + 1]) / 2 / max(levels)), edgecolor='black', align='center' # 确保柱子居中对齐 ) # 在柱子顶部垂直标注百分比 ax_hist.text( levels[i] + bar_width / 2, percentages[i] + 0.5, # 偏移量调整位置 f"{percentages[i]:.1f}%", ha='center', va='bottom', fontsize=8, rotation=90 # 文字垂直显示 )
# 设置直方图样式 ax_hist.set_xlim(levels[0], levels[-1]) ax_hist.axis('off') # 去掉坐标轴、刻度和边框
# 保存图片 # 保存图片 plt.savefig( r'D:\PML_WUE等\出图\空间分布\gzh_t_et.jpg', dpi=300, bbox_inches='tight', pad_inches=0.01 ) plt.show()
plot_combined()
三、写在最后
今天是2024年最后一天,想借此机会做个年度总结,和大家聊聊我们这一年的努力与收获,以及和大家共同走过的路。
公众号成立之初,我们的初衷很简单,分享一些处理好的遥感数据,如植被、水文、气象、土地利用、土壤、社会经济、城市空气质量和地形地貌等,希望为大家的科研和学习提供便利。但后面我们逐渐意识到,单纯分享数据不仅面临版权风险,对大家长期的科研成长帮助也有限。于是我们开始专注于分享基于ArcGIS、Python、MATLAB、R和GEE等工具进行数据处理的方法和代码。我们结合自身经验,力求用通俗易懂的方式,帮助大家从零开始掌握这些技能。

这样的改变,既是对初衷的延续,也源于一种责任感。我们深知,很多同学在读研期间,因为环境或时间的限制,没能系统学习到真正实用的科研技能,而这些能力却是未来科研与工作的核心竞争力。我们希望通过自己的努力和天赋,让大家掌握这些方法,也让更多人感受到遥感的魅力与乐趣。

这一年,有不少广告商联系我们,希望投放广告,但我们始终坚持拒绝商业化合作,也从未搞过“点赞转发”“流量收割”这样的套路。

当然了,我们并非那么伟大。团队的收入主要来自于会员服务,包括为大家处理数据、提供教程,以及作图和论文指导。服务过的会员中,大多数都逐渐掌握了数据处理、代码编写和作图能力,甚至发表了高水平的研究成果。看到大家从初学到成长,再到独立完成科研,我们感到无比欣慰,也深知自己的付出没有白费。

这一年,我们经常起早贪黑,研读文献,编写代码,处理数据,力求每篇内容都是干货。包括此刻,我们早早到达工位,简单扒拉两口早饭,又投入到明天内容的准备中。在这里,我想对伙伴们说一声:你们辛苦了

展望2025年,我们依然会秉持初心,致力于推动遥感数据处理的普及与应用,帮助更多人掌握工具,解决实际问题,找到科研的乐趣,爱上遥感。未来的路充满挑战,我们会继续专注内容,做好服务,传递热爱。

最后,祝大家身体健康,科研顺利!我们2025年再见,一起加油!


GIS遥感数据处理应用
会员:数据处理,ArcGIS/Python/MATLAB/R/GEE教学,指导作图和论文。
 最新文章