Matplotlib中为多色图例添加填充图案(hatch)的问题
解决Matplotlib多色图例条目添加填充图案的问题
问题描述
基于现有代码实现Matplotlib多色图例条目时,尝试为图例添加//、xx这类填充图案但未成功,需求是让其中一个图例矩形带填充图案,另一个不带。尝试代码如下:
import matplotlib.pyplot as plt from matplotlib.collections import PatchCollection # define an object that will be used by the legend class MulticolorPatch(object): def __init__(self, colors): self.colors = colors # define a handler for the MulticolorPatch object class MulticolorPatchHandler(object): def legend_artist(self, legend, orig_handle, fontsize, handlebox): width, height = handlebox.width, handlebox.height patches = [] for i, c in enumerate(orig_handle.colors): patches.append( plt.Rectangle( [ width/len(orig_handle.colors) * i - handlebox.xdescent, -handlebox.ydescent ], width / len(orig_handle.colors), height, facecolor=c, edgecolor="black", linewidth=0.5, hatch='//' ) ) patch = PatchCollection(patches, match_original=True) handlebox.add_artist(patch) return patch # ------ choose some colors colors1 = ['r', 'g'] colors2 = ['b', 'y'] # ------ create a dummy-plot (just to show that it works) f, ax = plt.subplots() ax.plot([1,2,3,4,5], [1,4.5,2,5.5,3], c='g', lw=0.5, ls='--', label='... just a line') ax.scatter(range(len(colors1)), range(len(colors1)), c=colors1) ax.scatter([range(len(colors2))], [.5]*len(colors2), c=colors2, s=50) # ------ get the legend-entries that are already attached to the axis h, l = ax.get_legend_handles_labels() # ------ append the multicolor legend patches h.append(MulticolorPatch(colors1)) l.append("a nice multicolor legend patch") h.append(MulticolorPatch(colors2)) l.append("and another one") # ------ create the legend f.legend(h, l, loc='upper left', handler_map={MulticolorPatch: MulticolorPatchHandler()}, bbox_to_anchor=(.125,.875))
解决方案
问题出在两个核心点:原MulticolorPatch类没有存储填充图案的差异化参数,且PatchCollection的match_original=True会覆盖单个patch的hatch设置。修改步骤如下:
- 扩展MulticolorPatch类:新增
hatch参数,支持为每个补丁单独指定填充图案(默认None表示无图案) - 调整Handler逻辑:在创建矩形patch时读取对象的hatch参数,同时移除
PatchCollection的match_original参数,避免覆盖自定义设置
修改后的完整代码:
import matplotlib.pyplot as plt from matplotlib.collections import PatchCollection # 定义图例使用的多色补丁对象,新增hatch参数支持填充图案设置 class MulticolorPatch(object): def __init__(self, colors, hatch=None): self.colors = colors self.hatch = hatch # 定义多色补丁的图例处理器 class MulticolorPatchHandler(object): def legend_artist(self, legend, orig_handle, fontsize, handlebox): width, height = handlebox.width, handlebox.height patches = [] for i, c in enumerate(orig_handle.colors): patches.append( plt.Rectangle( [ width/len(orig_handle.colors) * i - handlebox.xdescent, -handlebox.ydescent ], width / len(orig_handle.colors), height, facecolor=c, edgecolor="black", linewidth=0.5, hatch=orig_handle.hatch # 使用当前补丁的hatch参数 ) ) # 移除match_original=True,避免覆盖自定义hatch设置 patch = PatchCollection(patches) handlebox.add_artist(patch) return patch # 选择颜色,为不同补丁指定是否带填充图案 colors1 = ['r', 'g'] colors2 = ['b', 'y'] # 创建示例图 f, ax = plt.subplots() ax.plot([1,2,3,4,5], [1,4.5,2,5.5,3], c='g', lw=0.5, ls='--', label='... just a line') ax.scatter(range(len(colors1)), range(len(colors1)), c=colors1) ax.scatter([range(len(colors2))], [.5]*len(colors2), c=colors2, s=50) # 获取已有图例条目 h, l = ax.get_legend_handles_labels() # 添加多色图例补丁:第一个带//填充,第二个无填充 h.append(MulticolorPatch(colors1, hatch='//')) l.append("带填充图案的多色图例") h.append(MulticolorPatch(colors2)) l.append("无填充图案的多色图例") # 创建图例 f.legend(h, l, loc='upper left', handler_map={MulticolorPatch: MulticolorPatchHandler()}, bbox_to_anchor=(.125,.875)) plt.show()
关键修改说明
- 给
MulticolorPatch添加hatch参数,实现不同图例条目填充图案的差异化配置 - 矩形patch的hatch属性从
orig_handle.hatch读取,而非固定写死,支持灵活设置 - 移除
PatchCollection的match_original=True,该参数会强制同步集合内所有patch的属性,导致自定义hatch被覆盖
内容的提问来源于stack exchange,提问作者Xavier Merino
相关产品推荐
相关产品推荐

