如何用Python绘制分3组每组含2子组的带颜色箱线图?
解决方案:自定义位置或调整Seaborn参数实现分组箱线图
要实现你需要的「3个大区域、每个区域含2个紧挨着的不同颜色子箱线」的效果,核心是控制箱线的x轴位置和宽度,下面提供两种可行方案:
方案一:Matplotlib手动指定位置(精准控制间隙)
手动设置每个箱线的x坐标,让同一区域的两个箱线紧密排列,不同区域之间留出间隔,完全消除子区域的间隙。
完整代码
import matplotlib.pyplot as plt import numpy as np # 你的原始数据 year_2050_model1 = [50.2, 45, 55] year_2050_shift_model1 = np.array(year_2050_model1) + 1.5 year_2100_model1 = [45, 43, 46] year_2100_shift_model1 = np.array(year_2100_model1) + 1.5 year_2050_model2 = [56.2, 49, 53] year_2050_shift_model2 = np.array(year_2050_model2) + 1.5 year_2100_model2 = [43, 48, 41] year_2100_shift_model2 = np.array(year_2100_model2) + 1.5 historical = [50, 49, 55] observed = [54, 46, 58] # 1. 整理数据:按「区域-子区域」分组 data_list = [ # 区域1:基准 historical, observed, # 区域2:Model1(合并2050/2100的原数据、偏移数据) year_2050_model1 + year_2100_model1, year_2050_shift_model1.tolist() + year_2100_shift_model1.tolist(), # 区域3:Model2(同理) year_2050_model2 + year_2100_model2, year_2050_shift_model2.tolist() + year_2100_shift_model2.tolist() ] # 2. 指定每个箱线的x位置:同一区域的两个箱线紧挨着,区域间留间隙 positions = [0, 0.4, 1.5, 1.9, 3, 3.4] box_width = 0.35 # 单个箱线宽度,确保两个子箱线总宽度小于区域间隔 colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'] # 子区域对应颜色 # 3. 绘制箱线图 plt.figure(figsize=(10, 6)) box_plot = plt.boxplot(data_list, positions=positions, widths=box_width, patch_artist=True) # 设置箱线颜色 for patch, color in zip(box_plot['boxes'], colors): patch.set_facecolor(color) # 4. 设置x轴刻度与标签(对应3个大区域) plt.xticks([0.2, 1.7, 3.2], ['基准', 'Model1', 'Model2']) # 添加图例 legend_patches = [ plt.matplotlib.patches.Patch(color='#1f77b4', label='Historical'), plt.matplotlib.patches.Patch(color='#ff7f0e', label='Observed'), plt.matplotlib.patches.Patch(color='#2ca02c', label='Model1 原模型'), plt.matplotlib.patches.Patch(color='#d62728', label='Model1 偏移模型'), plt.matplotlib.patches.Patch(color='#9467bd', label='Model2 原模型'), plt.matplotlib.patches.Patch(color='#8c564b', label='Model2 偏移模型') ] plt.legend(handles=legend_patches, bbox_to_anchor=(1.05, 1), loc='upper left') plt.ylabel('数值') plt.title('分组箱线图') plt.tight_layout() plt.show()
关键说明
- 通过
positions参数精准控制每个箱线的x坐标,同一区域的两个箱线间距设为0.4(小于区域间的1.1间隔),实现紧密排列。 patch_artist=True允许自定义箱线填充色,解决颜色区分问题。
方案二:Seaborn调整参数简化实现
如果习惯用Seaborn,可通过调整dodge(子箱线间距)和width(组宽度)参数,消除子区域间隙,代码更简洁。
完整代码
import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import numpy as np # 你的原始数据 year_2050_model1 = [50.2, 45, 55] year_2050_shift_model1 = np.array(year_2050_model1) + 1.5 year_2100_model1 = [45, 43, 46] year_2100_shift_model1 = np.array(year_2100_model1) + 1.5 year_2050_model2 = [56.2, 49, 53] year_2050_shift_model2 = np.array(year_2050_model2) + 1.5 year_2100_model2 = [43, 48, 41] year_2100_shift_model2 = np.array(year_2100_model2) + 1.5 historical = [50, 49, 55] observed = [54, 46, 58] # 1. 整理成长格式DataFrame(Seaborn偏好的格式) data = { '数值': [], '子区域': [], '大区域': [] } # 填充基准区域数据 data['数值'].extend(historical + observed) data['子区域'].extend(['Historical']*3 + ['Observed']*3) data['大区域'].extend(['基准']*6) # 填充Model1区域数据 data['数值'].extend(year_2050_model1 + year_2100_model1 + year_2050_shift_model1.tolist() + year_2100_shift_model1.tolist()) data['子区域'].extend(['Model1 原模型']*6 + ['Model1 偏移模型']*6) data['大区域'].extend(['Model1']*12) # 填充Model2区域数据 data['数值'].extend(year_2050_model2 + year_2100_model2 + year_2050_shift_model2.tolist() + year_2100_shift_model2.tolist()) data['子区域'].extend(['Model2 原模型']*6 + ['Model2 偏移模型']*6) data['大区域'].extend(['Model2']*12) df = pd.DataFrame(data) # 2. 绘制箱线图,调整参数消除间隙 plt.figure(figsize=(10, 6)) sns.boxplot( data=df, x='大区域', y='数值', hue='子区域', dodge=0.8, # 子箱线间距,设为接近1可消除间隙 width=0.6 # 每组总宽度,配合dodge实现紧密排列 ) plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.ylabel('数值') plt.title('分组箱线图') plt.tight_layout() plt.show()
关键说明
dodge=0.8让同一大区域内的两个子箱线几乎紧贴,width=0.6控制每组的整体宽度,避免跨区域重叠。- 长格式DataFrame更符合Seaborn的设计逻辑,便于后续扩展数据。
内容的提问来源于stack exchange,提问作者vgarza
相关产品推荐
相关产品推荐

