如何用seaborn或matplotlib绘制带95%CI的分作物分年份产量误差点图
实现方案说明
完全可以通过Seaborn+Matplotlib实现目标可视化效果,无需额外复杂依赖,核心是逐行匹配绘制对应图表元素,再按规则做色彩分层。
核心实现逻辑
- 为每个
Crop类别分配独立的基础主色调,保证不同作物的视觉区分度 - 对同一
Crop下的不同Year,在对应主色基础上调整明度生成深浅渐变的同系色彩,实现同作物下年份的视觉区分 - 逐行绘制对应元素:绘制从
Lower CI到Upper CI的垂直区间竖线,竖线两端加短横杠标记区间端点,再在Yield对应位置绘制实心圆点标记均值 - 对同Crop下的不同Year做轻微横轴位置错位,避免区间元素重叠遮挡
可直接运行的示例代码
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from matplotlib.colors import to_rgb, to_hex # 构造匹配给定结构的示例数据集 df = pd.DataFrame({ "Region": ["Argentina"]*4, "Year": [2017.0, 2018.0, 2019.0, 2020.0], "Crop": ["Soya", "Soya", "Soya", "Maize"], "Yield": [2770.885366, 3442.598073, 3472.638859, 6203.009997], "Lower CI": [2647.711922, 3375.280283, 3415.621142, 6020.164203], "Upper CI": [2937.259244, 3512.806645, 3536.144550, 6387.457295] }) def generate_shade_color(base_hex, shade_factor): """基于基础主色生成不同深浅的同系色彩,shade_factor取值0-1,数值越大颜色越深""" r, g, b = to_rgb(base_hex) return to_hex((r*shade_factor, g*shade_factor, b*shade_factor)) # 定义不同作物的基础主色 crop_base_palette = { "Soya": "#2c7fb8", "Maize": "#d95f0e" } # 预计算每个样本对应的配色和横轴位置 color_lookup = {} x_pos_lookup = {} grouped_crop_years = df.groupby("Crop")["Year"].unique() current_base_x = 0 group_offset = 1.2 within_group_step = 0.25 for crop, year_list in grouped_crop_years.items(): sorted_years = sorted(year_list) for year_idx, year in enumerate(sorted_years): # 同组内颜色从浅到深按年份排序渐变 shade_level = 0.4 + (year_idx / max(len(sorted_years)-1, 1)) * 0.6 color_lookup[(crop, year)] = generate_shade_color(crop_base_palette[crop], shade_level) # 同组内横轴轻微错位避免遮挡 x_pos_lookup[(crop, year)] = current_base_x + year_idx * within_group_step current_base_x += group_offset # 开始绘图 plt.figure(figsize=(8,5), dpi=120) for _, row in df.iterrows(): current_crop = row["Crop"] current_year = row["Year"] x = x_pos_lookup[(current_crop, current_year)] c = color_lookup[(current_crop, current_year)] # 绘制垂直置信区间线 plt.plot([x, x], [row["Lower CI"], row["Upper CI"]], color=c, linewidth=2) # 绘制区间两端的短横帽 cap = 0.1 plt.plot([x-cap, x+cap], [row["Lower CI"], row["Lower CI"]], color=c, linewidth=2) plt.plot([x-cap, x+cap], [row["Upper CI"], row["Upper CI"]], color=c, linewidth=2) # 绘制均值圆点 plt.scatter(x, row["Yield"], color=c, s=40, zorder=10) # 设置横轴刻度,将作物标签放在对应组的中心位置 xticks = [] xtick_labels = [] current_base_x = 0 for crop, year_list in grouped_crop_years.items(): n_years = len(year_list) group_center = current_base_x + (n_years-1)*within_group_step/2 xticks.append(group_center) xtick_labels.append(crop) current_base_x += group_offset plt.xticks(xticks, xtick_labels) plt.ylabel("作物产量") plt.title("分作物产量均值及95%置信区间") sns.despine() plt.tight_layout() plt.show()
效果适配说明
- 不同作物的主色差异明显,同作物下的年份色彩深浅沿时间线渐变,可快速区分不同时间的统计值
- 图表元素和参考样式完全匹配:垂直竖线对应95%置信区间的上下跨度,两端带短横标记区间边界,中间圆点为Yield均值
- 横轴错位逻辑可根据数据量调整偏移步长,避免多组数据重叠
内容的提问来源于stack exchange,提问作者user308827
相关产品推荐
相关产品推荐

