2016-07-28 110 views
10

我想在matplotlib中创建一个复杂的图例。我做了下面的代码matplotlib中的表格图例

import matplotlib.pylab as plt 
import numpy as np 

N = 25 
y = np.random.randn(N) 
x = np.arange(N) 

y2 = np.random.randn(25) 

# serie A 
p1a, = plt.plot(x, y,  "ro", ms=10, mfc="r", mew=2, mec="r") 
p1b, = plt.plot(x[:5], y[:5] , "w+", ms=10, mec="w", mew=2) 
p1c, = plt.plot(x[5:10], y[5:10], "w*", ms=10, mec="w", mew=2) 

# serie B 
p2a, = plt.plot(x, y2,  "bo", ms=10, mfc="b", mew=2, mec="b") 
p2b, = plt.plot(x[15:20], y2[15:20] , "w+", ms=10, mec="w", mew=2) 
p2c, = plt.plot(x[10:15], y2[10:15], "w*", ms=10, mec="w", mew=2) 


plt.legend([p1a, p2a, (p1a, p1b), (p2a,p2b), (p1a, p1c), (p2a,p2c)], 
["No prop", "No prop", "Prop +", "Prop +", "Prop *", "Prop *"], ncol=3, numpoints=1) 

plt.show() 

它生产的情节那样: enter image description here

但我想绘制复杂的传奇喜欢这里:

enter image description here

我也试着做table函数的传说,但我不能将一个修补程序对象放到表格中的适当位置的单元格。

+0

我还不能肯定,但我相信这正是做在接受的答案为[这里]为例(HTTP ://stackoverflow.com/questions/21570007/custom-legend-in-matplotlib)问题。或者它至少可以让你指向正确的方向? – Ajean

+0

不,在这个例子中,每个标记都有自己的标签。 – Serenity

+0

没错,但你可以在那里放空弦。我实际上是在寻找一个我以前在这里看到过的不同例子(有人写了一个美丽的传说),但我无法追踪它。只是一个想法,因为我认为一个使用空字符串。对不起,我找不到它... – Ajean

回答

3

这是解决方案足够接近自己的喜好?它的灵感来自于里卡多的回答,但我只用了每个列的一个图例对象,然后利用关键字设置每个列的标题。要把标记放在每列的中心,我用handletextpad以负值将它向后推。没有传说给个别的线路。我还必须在标题字符串中插入一些空格,以便在屏幕上绘制时看起来同样大。

现在我还注意到,当保存图形时,需要对图例框的确切位置进行额外的调整,但是因为我想你可能想要在代码中调整更多的东西,无论如何我都会为你保留它。您可能还需要玩handletextpad,以使它们“完美”对齐。

import matplotlib.pylab as plt 
import numpy as np 
plt.close('all') 

N = 25 
y = np.random.randn(N) 
x = np.arange(N) 

y2 = np.random.randn(25) 

# serie A 
p1a, = plt.plot(x, y,  "ro", ms=10, mfc="r", mew=2, mec="r") 
p1b, = plt.plot(x[:5], y[:5] , "w+", ms=10, mec="w", mew=2) 
p1c, = plt.plot(x[5:10], y[5:10], "w*", ms=10, mec="w", mew=2) 

# serie B 
p2a, = plt.plot(x, y2,  "bo", ms=10, mfc="b", mew=2, mec="b") 
p2b, = plt.plot(x[15:20], y2[15:20] , "w+", ms=10, mec="w", mew=2) 
p2c, = plt.plot(x[10:15], y2[10:15], "w*", ms=10, mec="w", mew=2) 

line_columns = [ 
       p1a, p2a, 
       (p1a, p1b), (p2a, p2b), 
       (p1a, p1c), (p2a, p2c) 
       ] 


leg1 = plt.legend(line_columns[0:2], ['', ''], ncol=1, numpoints=1, 
        title='No prop', handletextpad=-0.4, 
        bbox_to_anchor=[0.738, 1.]) 
leg2 = plt.legend(line_columns[2:4], ['', ''], ncol=1, numpoints=1, 
        title=' Prop + ', handletextpad=-0.4, 
        bbox_to_anchor=[0.87, 1.]) 
leg3 = plt.legend(line_columns[4:6], ['', ''], ncol=1, numpoints=1, 
        title=' Prop * ', handletextpad=-0.4, 
        bbox_to_anchor=[0.99, 1.]) 

plt.gca().add_artist(leg1) 
plt.gca().add_artist(leg2) 
plt.gca().add_artist(leg3) 

plt.gcf().show() 

enter image description here

编辑

也许这将更好地工作。你仍然需要调整一些东西,但是bbox的对齐问题已经消失了。

leg = plt.legend(line_columns, ['']*len(line_columns), 
      title='No Prop Prop + Prop *', 
      ncol=3, numpoints=1, handletextpad=-0.5) 

enter image description here

+0

很难把这个传说正确的,因为锚点不计算自动设置 – Serenity

+0

是的,也请注意......请看我编辑的答案。我用一个标签替换了所有标签,而不是使用多个标签。现在唯一需要做的调整就是使用'title'和'handletextpad'值的内部空格。这是否更好? – pathoren

+0

很好,很漂亮。谢谢。 – Serenity

2

似乎没有标准的方法,而不是这里可用的一些技巧。

值得一提的是,你应该检查最适合你的大小bbox因子。

我能找到到目前为止最好的,也许是一个可以带你到一个更好的解决方案:

N = 25 
y = np.random.randn(N) 
x = np.arange(N) 

y2 = np.random.randn(25) 

# Get current size 
fig_size = list(plt.rcParams["figure.figsize"]) 

# Set figure width to 12 and height to 9 
fig_size[0] = 12 
fig_size[1] = 12 
plt.rcParams["figure.figsize"] = fig_size 

# serie A 
p1a, = plt.plot(x, y,  "ro", ms=10, mfc="r", mew=2, mec="r") 
p1b, = plt.plot(x[:5], y[:5] , "w+", ms=10, mec="w", mew=2) 
p1c, = plt.plot(x[5:10], y[5:10], "w*", ms=10, mec="w", mew=2) 

# serie B 
p2a, = plt.plot(x, y2,  "bo", ms=10, mfc="b", mew=2, mec="b") 
p2b, = plt.plot(x[15:20], y2[15:20] , "w+", ms=10, mec="w", mew=2) 
p2c, = plt.plot(x[10:15], y2[10:15], "w*", ms=10, mec="w", mew=2) 

v_factor = 1. 
h_factor = 1. 

leg1 = plt.legend([(p1a, p1a)], ["No prop"], bbox_to_anchor=[0.78*h_factor, 1.*v_factor]) 
leg2 = plt.legend([(p2a, p2a)], ["No prop"], bbox_to_anchor=[0.78*h_factor, .966*v_factor]) 

leg3 = plt.legend([(p2a,p2b)], ["Prop +"], bbox_to_anchor=[0.9*h_factor, 1*v_factor]) 
leg4 = plt.legend([(p1a, p1b)], ["Prop +"], bbox_to_anchor=[0.9*h_factor, .966*v_factor]) 

leg5 = plt.legend([(p1a, p1c)], ["Prop *"], bbox_to_anchor=[1.*h_factor, 1.*v_factor]) 
leg6 = plt.legend([(p2a,p2c)], ["Prop *"], bbox_to_anchor=[1.*h_factor, .966*v_factor]) 

plt.gca().add_artist(leg1) 
plt.gca().add_artist(leg2) 
plt.gca().add_artist(leg3) 
plt.gca().add_artist(leg4) 
plt.gca().add_artist(leg5) 
plt.gca().add_artist(leg6) 
plt.show() 

enter image description here

1

我根据BBOX传说的坐标提高@pathoren到位置传说的答案在一个周期自动。此代码允许显示了复杂的传奇的一切所需的边界线:

import matplotlib.pylab as plt 
import numpy as np 
plt.close('all') 

# test data 
N = 25 
y = np.random.randn(N) 
x = np.arange(N) 
y2 = np.random.randn(25) 

# serie A 
p1a, = plt.plot(x, y, "ro", ms=10, mfc="r", mew=2, mec="r") 
p1b, = plt.plot(x[:5], y[:5], "w+", ms=10, mec="w", mew=2) 
p1c, = plt.plot(x[5:10], y[5:10], "w*", ms=10, mec="w", mew=2) 
# serie B 
p2a, = plt.plot(x, y2, "bo", ms=10, mfc="b", mew=2, mec="b") 
p2b, = plt.plot(x[15:20], y2[15:20], "w+", ms=10, mec="w", mew=2) 
p2c, = plt.plot(x[10:15], y2[10:15], "w*", ms=10, mec="w", mew=2) 

# legend handlers 
columns = [p1a, p2a, 
(p1a, p1b), (p2a, p2b), 
(p1a, p1c), (p2a, p2c)] 

ax = plt.gca() 
fig = plt.gcf() 
legs = [] 
# set the first legend in desired position 
leg = plt.legend(columns[0:2], ['', ''], ncol=1, numpoints=1, 
borderaxespad=0., title='No prop.', framealpha=.75, 
facecolor='w', edgecolor='k', loc=2, fancybox=None) 
ax.add_artist(leg) 
fig.canvas.draw() 
plt.pause(1.e-3) 

# get bbox postion of 1st legend to calculate 
# postion of 2nd and 3rd legends according to loc 
for i,si in enumerate(['+','*']): 
    bbox = leg.get_window_extent().inverse_transformed(ax.transAxes) 
    # next legends 
    leg = plt.legend(columns[(i+1)*2:(i+1)*2+2], ['', ''], ncol=1, numpoints=1, 
    title='Prop. '+si, framealpha=.75, borderaxespad=.0, 
    bbox_to_anchor=(bbox.x1-bbox.height*.08, bbox.y0, bbox.width, bbox.height), 
    facecolor='w', edgecolor='k') 
    ax.add_artist(leg) 
    fig.canvas.draw() 
    plt.pause(1.e-3) 

plt.show() 

enter image description here