【问题标题】:How to add a string as the artist in matplotlib legend?如何在 matplotlib 图例中添加一个字符串作为艺术家?
【发布时间】:2015-01-26 06:32:55
【问题描述】:

我正在尝试在 python 图形中创建一个图例,其中艺术家是一个字符串(单个字母),然后对其进行标记。例如我想要下图的图例:

import numpy as np
import matplotlib.pyplot as plt
import string

N = 7
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 

plt.scatter(x, y, s=area, c=colors, alpha=0.5)
for i,j in enumerate(zip(x,y)):
    plt.annotate(list(string.ascii_uppercase)[i],xy=j)
plt.show()

传说是这样的:

A - 型号名称 A

B - 型号名称 B

C - 型号名称 C

D - 型号名称 D

等等。

我不知道该怎么做是将'A','B',....作为图例文本的艺术家。我可以看到您将如何使用线或补丁或类似的东西。但总的来说,有没有办法使用字符串作为艺术家而不是线条?

【问题讨论】:

    标签: python matplotlib legend legend-properties


    【解决方案1】:

    我认为没有文本的图例处理程序(请参阅可用列表 here)。但是你可以实现你自己的custom legend handler。这里我只是修改上面链接的例子:

    import matplotlib.pyplot as plt
    import matplotlib.text as mpl_text
    
    class AnyObject(object):
        def __init__(self, text, color):
            self.my_text = text
            self.my_color = color
    
    class AnyObjectHandler(object):
        def legend_artist(self, legend, orig_handle, fontsize, handlebox):
            print orig_handle
            x0, y0 = handlebox.xdescent, handlebox.ydescent
            width, height = handlebox.width, handlebox.height
            patch = mpl_text.Text(x=0, y=0, text=orig_handle.my_text, color=orig_handle.my_color, verticalalignment=u'baseline', 
                                    horizontalalignment=u'left', multialignment=None, 
                                    fontproperties=None, rotation=45, linespacing=None, 
                                    rotation_mode=None)
            handlebox.add_artist(patch)
            return patch
    
    obj_0 = AnyObject("A", "purple")
    obj_1 = AnyObject("B", "green")
    
    plt.legend([obj_0, obj_1], ['Model Name A', 'Model Name B'],
               handler_map={obj_0:AnyObjectHandler(), obj_1:AnyObjectHandler()})
    
    plt.show()
    

    【讨论】:

    • 感谢您的回复。当我运行上面的代码时,我得到:“TypeError:'AnyObjectHandler' 对象不可调用。”有什么建议是什么原因造成的?
    • @SeanElvidge:我的第一个猜测是你打错了.. 至少这是这种事情出现在 SO 上时的通常结果。我正在运行 mpl 版本 1.4.0。我将再次剪切并粘贴我的工作代码,以防我出错。
    • 我运行的是 mpl 版本 1.3.1。我刚刚更新到 1.4.2 并运行了您的代码,它运行良好!非常感谢。
    • 我已经玩了几天你的示例代码,但想不出/找到一种修改它以接受多个(不同)艺术家和标签的好方法。至少没有定义尽可能多的“AnyObjectHandler”(因为对象中的“文本”是硬编码的,如果我尝试将其设为关键字,则函数将停止工作)。您能否建议一种方法来制作以下图例:“A - 模型 A”、“B - 模型 B”?非常感谢您(持续)的帮助。
    • 传递给句柄的orig_handle就是要处理的对象。也就是说,处理程序可以从对象中获取信息并使用它来构建符号。我已经更新了我的示例以包含一些对象(尽管我将再次更新它以更改颜色)。
    【解决方案2】:

    解决方案将取决于您是否已经在图例中出现的坐标轴中有文本,或者这些文本是否独立于坐标轴中的任何内容。

    A.现有文本或注释

    如果坐标区中已有文本或注释,则可以将它们作为图例句柄提供。注册到Legend 类的新TextHandlerA 将这些Texts 作为输入。像往常一样,通过label 参数从艺术家那里获取相应的标签。

    import numpy as np
    import matplotlib.pyplot as plt
    import string
    
    from matplotlib.legend_handler import HandlerBase
    from matplotlib.text import Text, Annotation
    from matplotlib.legend import Legend
    
    
    class TextHandlerA(HandlerBase):
        def create_artists(self, legend, artist ,xdescent, ydescent,
                            width, height, fontsize, trans):
            tx = Text(width/2.,height/2, artist.get_text(), fontsize=fontsize,
                      ha="center", va="center", fontweight="bold")
            return [tx]
    
    Legend.update_default_handler_map({Text : TextHandlerA()})
    
    N = 7
    x = np.random.rand(N)*.7
    y = np.random.rand(N)*.7
    colors = np.random.rand(N)
    
    handles = list(string.ascii_uppercase) 
    labels = [f"Model Name {c}" for c in handles]
    
    fig, ax = plt.subplots()
    ax.scatter(x, y, s=100, c=colors, alpha=0.5)
    for i, xy in enumerate(zip(x, y)):
        ax.annotate(handles[i], xy=xy, label= labels[i])
    
    ax.legend(handles=ax.texts)
    plt.show()
    

    B.字符串列表中的图例。

    如果您希望图例条目本身不是轴中的文本,您可以从字符串列表创建它们。在这种情况下,TextHandlerB 将字符串作为输入。在这种情况下,需要使用两个字符串列表调用图例,一个用于句柄,一个用于标签。

    import numpy as np
    import matplotlib.pyplot as plt
    import string
    
    from matplotlib.legend_handler import HandlerBase
    from matplotlib.text import Text
    from matplotlib.legend import Legend
    
    
    class TextHandlerB(HandlerBase):
        def create_artists(self, legend, text ,xdescent, ydescent,
                            width, height, fontsize, trans):
            tx = Text(width/2.,height/2, text, fontsize=fontsize,
                      ha="center", va="center", fontweight="bold")
            return [tx]
    
    Legend.update_default_handler_map({str : TextHandlerB()})
    
    N = 7
    x = np.random.rand(N)*.7
    y = np.random.rand(N)*.7
    colors = np.random.rand(N)
    
    handles = list(string.ascii_uppercase)[:N] 
    labels = [f"Model Name {c}" for c in handles]
    
    fig, ax = plt.subplots()
    ax.scatter(x, y, s=100, c=colors, alpha=0.5)
    for i, xy in enumerate(zip(x, y)):
        ax.annotate(handles[i], xy=xy)
    
    ax.legend(handles=handles, labels=labels)
    plt.show()
    

    在这两种情况下,输出都是

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-14
      • 1970-01-01
      • 2019-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-19
      相关资源
      最近更新 更多