Matplotlib中分箱与标签不匹配及标签位置调整问询
解决Matplotlib图例分箱与标签不匹配的问题
问题根源
你定义的bins有8个边界值,会生成7个数据区间,但你给了8个labels,这就导致pd.cut报错——因为区间数量永远比边界值少1。要让颜色条的黑色分隔线精准落在分箱边界上,同时显示所有边界值作为标签,需要调整颜色条的刻度设置,而不是强行给pd.cut增加标签数量。
解决方案步骤
- 修正分箱标签:
pd.cut的labels长度必须等于区间数(即len(bins)-1),可以给每个区间设置描述性标签,或者直接用默认的区间对象。 - 使用
BoundaryNorm匹配分箱边界:替换原来的Normalize,让颜色映射完全对应你的分箱边界,确保颜色块和区间一一对应。 - 调整颜色条刻度:将颜色条的刻度设置为所有分箱边界值,让分隔线正好落在两个区间之间,同时显示所有边界值作为标签。
修改后的完整代码
import pandas as pd import geopandas as gpd import matplotlib.pyplot as plt from matplotlib.colors import BoundaryNorm data = { 'country': ['United States', 'China', 'India', 'Brazil', 'Australia'], 'LU (PDF)': [0.00000001, 0.0000001, 0.0000005, 0.000001, 0.00001] } fabio_country = pd.DataFrame(data) # 加载世界地图数据 world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) # 合并地图数据与自定义数据 world = world.merge(fabio_country, left_on='name', right_on='country', how='left') # 定义分箱边界 bins = [0, 0.000000001, 0.00000001, 0.0000001, 0.000001, 0.00001, 0.0001, 0.001] # 区间数为len(bins)-1,所以labels长度必须一致 labels = ['0~1e-9', '1e-9~1e-8', '1e-8~1e-7', '1e-7~1e-6', '1e-6~1e-5', '1e-5~1e-4', '1e-4~1e-3'] # 数据分箱 world['binned'] = pd.cut(world['LU (PDF)'], bins=bins, labels=labels, include_lowest=True) # 转换为罗宾逊投影 world = world.to_crs('ESRI:54030') # 绘图设置 fig, ax = plt.subplots(1, 1, figsize=(15, 10)) world.boundary.plot(ax=ax) # 创建匹配分箱边界的颜色映射和归一化对象 cmap = plt.get_cmap('OrRd', len(labels)) # BoundaryNorm直接使用分箱边界,确保颜色与区间完全对应 norm = BoundaryNorm(bins, cmap.N) world.plot(column='binned', ax=ax, legend=False, cmap=cmap, norm=norm, edgecolor='black') # 创建水平颜色条 sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) sm.set_array([]) cbar = plt.colorbar(sm, orientation='horizontal', fraction=0.046, pad=0.04) # 设置刻度为分箱边界,标签显示边界值 cbar.set_ticks(bins) cbar.set_ticklabels([str(b) for b in bins]) cbar.set_label('PDF') plt.title('土地利用导致的生物多样性损失(PDF)') plt.show()
关键说明
BoundaryNorm的作用:它会根据你提供的bins边界来划分颜色区间,每个区间对应一个颜色块,完美匹配pd.cut的分箱逻辑。- 颜色条刻度设置:
set_ticks(bins)让分隔线精准落在每个分箱边界上,set_ticklabels显示所有边界值,满足你“标签数量比分箱数多1”的需求。 - 分箱标签修正:原来的
labels长度和区间数一致,避免了pd.cut的报错,同时也能清晰标识每个区间的范围。
内容的提问来源于stack exchange,提问作者Natashaj
相关产品推荐
相关产品推荐

