5

我正在尝试在 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',....作为图例文本的艺术家。我可以看到您将如何使用线或补丁,或类似的东西。但总的来说,有没有办法使用字符串作为艺术家,而不是说,一条线?

4

2 回答 2

15

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

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()

在此处输入图像描述

于 2014-11-27T16:23:36.620 回答
9

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

A. 现有文本或注释

如果轴中已经有文本或注释,则可以将它们作为图例的句柄提供。TextHandlerA注册到Legend该类的 new将这些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()

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

在此处输入图像描述

于 2019-08-28T17:51:53.497 回答