Matplotlib图例中的字幕

9

我正在使用matplotlib进行一些绘图,我有一个图例告诉观众这些点是由哪些传感器记录的。有多种类型的多个传感器,我希望在图例中有副标题告诉观众每组传感器的类型。我有一个可行的解决方案,但它有点像黑客,如下所示:

enter image description here

当创建图例时,它接受两个重要的参数:一个图例标记列表和一个图例标签列表。我的当前解决方案是将副标题标记设置为带有白色轮廓的白色框,并且让副标题标签被两个换行符包围。看起来还不错,但如果副标题没有缩进,它会更加专业。我尝试过两种解决方法,一种是将副标题的标记设置为无,另一种是将副标题的标记设置为所需的副标题字符串,而其标签为空字符串。都没有奏效。有人有经验吗?非常感谢。

这是我找到的最接近的:https://dev59.com/LGEi5IYBdhLWcg3wJpgl#21571063 - cphlewis
您有没有考虑手动编辑SVG呢?这是最后的选择,但是除非您有很多图形,否则手动编辑比寻找编程解决方案要快得多。 - runDOSrun
2个回答

11

我能想到的最好方法就是为字符串创建一个自定义处理程序。

import matplotlib.pyplot as plt
import matplotlib.text as mtext


class LegendTitle(object):
    def __init__(self, text_props=None):
        self.text_props = text_props or {}
        super(LegendTitle, self).__init__()

    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        title = mtext.Text(x0, y0, r'\underline{' + orig_handle + '}', usetex=True, **self.text_props)
        handlebox.add_artist(title)
        return title


[line1] = plt.plot(range(10))
[line2] = plt.plot(range(10, 0, -1), 'o', color='red')
plt.legend(['Title 1', line1, 'Title 2', line2], ['', 'Line 1', '', 'Line 2'],
           handler_map={basestring: LegendTitle({'fontsize': 18})})

plt.show()

output

我以http://matplotlib.org/users/legend_guide.html中的示例为基础。


我非常兴奋地想要运行您的解决方案;它看起来相当棒。不幸的是,当我尝试在我的机器上运行它时,它会产生以下错误:RuntimeError: LaTeX无法处理以下字符串:'\\underline{'。你有什么想法? - Jabberwock Stomp
1
我通过将 r'\underline{' + orig_handle + '}' 更改为 orig_handle,并且删除 usetex = True,使其正常工作。它不会被下划线标出,但完全可以使用! - Jabberwock Stomp
1
我非常喜欢这个解决方案。此外,用户JabberwockStomp的评论对我很有帮助。由于我正在使用Python 3而不是Python 2,所以我必须将handler_map = {basestring:LegendTitle({'fontsize':18})}替换为handler_map = {str:LegendTitle({'fontsize':18})} - user5415068

1

这里是一个简化版的Python 3代码,不需要LaTeX。它基于seaborn documentation中的一个简单图表,但也适用于matplotlib。

import seaborn as sns
flights = sns.load_dataset("flights")
sns.lineplot(data=flights, x="year", y="passengers", hue="month")

所以要添加字幕,你可以使用这段代码。

# Seaborn example
import seaborn as sns
flights = sns.load_dataset("flights")
g = sns.lineplot(data=flights, x="year", y="passengers", hue="month")

# Here is where the magic happens
h,l = g.get_legend_handles_labels()

import matplotlib.pyplot as plt
import matplotlib.text as mtext


class LegendTitle(object):
    def __init__(self, text_props=None):
        self.text_props = text_props or {}
        super(LegendTitle, self).__init__()

    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        title = mtext.Text(x0, y0, orig_handle,  **self.text_props)
        handlebox.add_artist(title)
        return title


# ['','2nd Title'], and ['',''] is a hackish to leave some 
# space between the titles
g.legend(['1st Title'] + h[:6] + ['','2nd Title'] + h[6:12], 
          ['']         + l[:6] + ['','']          + l[6:12],
           handler_map={str: LegendTitle({'fontsize': 16})},
          bbox_to_anchor=(1, 1)
        )

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接