GeoPandas多子图:共享图例、坐标轴及控制图尺寸的实现方法
解决GeoPandas多子图共享坐标轴、图例及控制画布大小的问题
嘿,我来帮你搞定这个问题!你之前踩的坑都是因为没找对sharex/sharey的正确打开方式,还有多子图图例重复的问题,咱们一步步来修正:
先说说你之前的错误原因
plt.figure()根本没有sharex/sharey参数,这些是批量创建子图的plt.subplots()的专属参数,所以第一个调用会报错。- GeoPandas的
plot()方法不接受sharex/sharey,这些是Matplotlib坐标轴(Axes)的属性,不能直接传给绘图函数。 plt.subplot()的sharex/sharey需要指定要共享的坐标轴对象(比如sharex=axs[0,0]),而不是直接传True,不然会触发弱引用的错误。
正确的实现代码
下面是调整后的完整代码,我标注了关键修改点:
import pandas as pd import geopandas as gpd import matplotlib.pyplot as plt # 加载数据 world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) months = pd.DataFrame( ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], columns=['months'] ) # 关键1:用plt.subplots一次性创建所有子图,设置共享轴和画布大小 fig, axs = plt.subplots( nrows=4, ncols=3, sharex=True, sharey=True, # 这里设置共享x/y轴 figsize=(15, 12) # 控制整个画布的大小,按需调整 ) # 把二维的axs数组展平成一维,方便循环 axs_flat = axs.flatten() # 循环绘制每个子图 for idx, (month, ax) in enumerate(zip(months['months'], axs_flat)): # 绘制地图,注意只在最后一个子图添加图例(避免重复) plot = world.plot( column='pop_est', ax=ax, legend=(idx == 11), # 最后一个子图才显示图例 legend_kwds={'shrink': 0.6} # 调整图例大小,避免占空间 ) ax.set_title(month, fontsize=10) ax.set_aspect('equal', adjustable='datalim') # 设置整体标题 plt.suptitle('全球人口估算(按月份展示)', fontsize=14, y=1.02) # 调整子图间距,避免标题和子图重叠 plt.tight_layout() plt.show()
额外优化:更美观的共享图例
如果觉得最后一个子图的图例挤,也可以把图例单独放到画布右侧,这样所有子图共享一个全局图例:
import pandas as pd import geopandas as gpd import matplotlib.pyplot as plt world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) months = pd.DataFrame( ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], columns=['months'] ) fig, axs = plt.subplots(4, 3, sharex=True, sharey=True, figsize=(15, 12)) axs_flat = axs.flatten() # 先绘制第一个子图,获取颜色映射对象 first_plot = world.plot(column='pop_est', ax=axs_flat[0]) axs_flat[0].set_title(months['months'][0], fontsize=10) axs_flat[0].set_aspect('equal', adjustable='datalim') # 绘制剩下的子图,不添加图例 for idx in range(1, 12): world.plot(column='pop_est', ax=axs_flat[idx], legend=False) axs_flat[idx].set_title(months['months'][idx], fontsize=10) axs_flat[idx].set_aspect('equal', adjustable='datalim') # 创建全局共享图例 fig.colorbar(first_plot.collections[0], ax=axs, orientation='vertical', shrink=0.8, label='人口估算') plt.suptitle('全球人口估算(按月份展示)', fontsize=14, y=1.02) plt.tight_layout() plt.show()
这样做的好处是图例统一在右侧,不会占用子图的空间,视觉上更整洁。
内容的提问来源于stack exchange,提问作者Stücke
相关产品推荐
相关产品推荐

