使用Matplotlib barh创建相邻子图:间距与图例问题求助
Matplotlib复刻图表的问题解决建议
问题描述
我尝试用Matplotlib复刻目标图表,但遇到两个问题:
- 第一个子图(Alcohol部分)的条形间距无法按预期调整
- 生成的图例没有显示所有指定标签(比如"Minor Change"无法正常显示)
以下是我尝试的代码:
import matplotlib.pyplot as plt import numpy as np #This style looks the best plt.style.use('default') #Sizes the plot nicely to see in python plt.figure(figsize=(10,6)) labels_alcohol = ['Borchers et al.', 'Donnelly et al.'] values_alcohol = [24, 1] labels_formalin = ['Wang and Feng', 'van Haaren et al.', 'Borchers et al.', 'Gustafson et al.', 'Ebacher et al.'] values_formalin = [3, 3, 24, 52, 52] fig, axs = plt.subplots(2, 1, sharex=True) # Remove vertical space between axes fig.subplots_adjust(hspace=0) # Plot each graph, and manually set the y tick values axs[0].barh(labels_alcohol[0], values_alcohol[0], color='white', label='No Change', hatch="\\", edgecolor="black", height=0.2) axs[0].barh(labels_alcohol[1], values_alcohol[1], color='white', label='Major Change', hatch="x", edgecolor="black", height=0.2) axs[0].set_ylabel('Alcohol') axs[1].barh(labels_formalin[0], values_formalin[0], color='white', label='_No Change', hatch="\\", edgecolor="black", height=0.8) axs[1].barh(labels_formalin[1], values_formalin[1], color='white', label='_Major Change', hatch="x", edgecolor="black", height=0.8) axs[1].barh(labels_formalin[2], values_formalin[2], color='white', label='Minor Change', hatch="o", edgecolor="black", height=0.8) axs[1].barh(labels_formalin[3], values_formalin[3], color='white', label='_No Change', hatch="\\", edgecolor="black", height=0.8) axs[1].barh(labels_formalin[4], values_formalin[4], color='white', label='_No Change', hatch="\\", edgecolor="black", height=0.8) axs[1].set_ylabel('Formalin') plt.xlabel('Weeks Stored') plt.legend() plt.savefig("Storage Protocol Plot.pdf") plt.show()
解决方案
1. 修复第一个子图的条形间距问题
直接给barh传入标签会让Matplotlib自动分配y轴位置,间距不好控制。改用手动指定y轴位置的方式,通过调整height参数和y轴刻度来控制间距:
- 用
np.arange()生成每个条形的y轴索引 - 设置合适的
height值(比如0.6),让条形之间保留适当空白 - 用
set_yticks()把索引映射回原始标签
2. 修复图例显示不全问题
- Matplotlib会忽略以下划线开头的标签(如
_No Change),但重复标签也只会显示一次,所以只在第一次出现每个图例项时设置正常标签,后续重复项设置下划线开头的标签即可 - 统一从两个子图中收集图例项,避免遗漏
修改后的完整代码
import matplotlib.pyplot as plt import numpy as np plt.style.use('default') fig, axs = plt.subplots(2, 1, sharex=True, figsize=(10,6)) fig.subplots_adjust(hspace=0) # 处理Alcohol子图(第一个子图) labels_alcohol = ['Borchers et al.', 'Donnelly et al.'] values_alcohol = [24, 1] y_alcohol = np.arange(len(labels_alcohol)) # 设置height控制条形粗细,间接调整间距 axs[0].barh(y_alcohol, values_alcohol, color='white', edgecolor="black", height=0.6) # 单独设置每个条形的hatch和标签(仅第一次出现时设置有效标签) axs[0].patches[0].set_hatch("\\") axs[0].patches[0].set_label('No Change') axs[0].patches[1].set_hatch("x") axs[0].patches[1].set_label('Major Change') # 映射y轴刻度到标签 axs[0].set_yticks(y_alcohol) axs[0].set_yticklabels(labels_alcohol) axs[0].set_ylabel('Alcohol') # 处理Formalin子图(第二个子图) labels_formalin = ['Wang and Feng', 'van Haaren et al.', 'Borchers et al.', 'Gustafson et al.', 'Ebacher et al.'] values_formalin = [3, 3, 24, 52, 52] y_formalin = np.arange(len(labels_formalin)) axs[1].barh(y_formalin, values_formalin, color='white', edgecolor="black", height=0.6) # 逐个设置hatch和标签(重复项用下划线开头避免重复图例) axs[1].patches[0].set_hatch("\\") axs[1].patches[0].set_label('_No Change') axs[1].patches[1].set_hatch("x") axs[1].patches[1].set_label('_Major Change') axs[1].patches[2].set_hatch("o") axs[1].patches[2].set_label('Minor Change') axs[1].patches[3].set_hatch("\\") axs[1].patches[3].set_label('_No Change') axs[1].patches[4].set_hatch("\\") axs[1].patches[4].set_label('_No Change') # 映射y轴刻度到标签 axs[1].set_yticks(y_formalin) axs[1].set_yticklabels(labels_formalin) axs[1].set_ylabel('Formalin') plt.xlabel('Weeks Stored') # 收集所有有效图例项并显示 handles, labels = plt.gca().get_legend_handles_labels() # 去重(确保每个标签只显示一次) unique_labels = dict(zip(labels, handles)) plt.legend(unique_labels.values(), unique_labels.keys()) plt.savefig("Storage Protocol Plot.pdf") plt.show()
额外优化建议
- 如果需要更精确的条形间距,可以调整
y_alcohol的数值(比如加/减偏移量) - 可以通过
fig.subplots_adjust()的left参数调整左侧空白,避免标签被截断
内容的提问来源于stack exchange,提问作者Nicholas Daras
相关产品推荐
相关产品推荐

