【问题标题】:Table legend in matplotlibmatplotlib 中的表格图例
【发布时间】:2016-12-03 11:53:15
【问题描述】:

我想在 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()

它会产生这样的情节:

但我想像这里一样绘制复杂的图例:

我也尝试用table 函数做图例,但我无法将补丁对象放入表格中到单元格的正确位置。

【问题讨论】:

  • 我不肯定,但我相信在this 问题的公认答案中有一个例子可以做到这一点。或者它至少可以为你指明正确的方向?
  • 不,在那个例子中,每个标记都有自己的标签。
  • 是的,但是你可以在那里放空字符串。我实际上是在寻找我以前在这里看到的另一个例子(有人写了一个美丽的传说),但我无法找到它。只是一个想法,因为我认为那个使用了空字符串。抱歉,我找不到它...
  • 是的,我也试过了。结果很丑:i.imgur.com/JHbNt3z.png
  • 没有顶级的可配置方式来做到这一点。执行此操作的工具在那里(处理程序创建工具、布局框 hpackers / vpackers 等)但作为替代方案会很有趣(并且至少在我们的文档中最终会是一件好事)图例实现。

标签: python matplotlib legend


【解决方案1】:

这个解决方案是否足够接近您的喜好?它受到 Ricardo 的回答的启发,但我只为每一列使用了一个图例对象,然后使用 title-keyword 设置每一列的标题。为了将标记放在每列的中心,我使用了带有负值的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()

编辑

也许这会更好。你仍然需要调整一些东西,但是 bbox 的对齐问题已经解决了。

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

【讨论】:

  • 很难正确放置这个图例,因为锚不自动计算
  • 是的,也注意到了...请参阅我编辑的答案。我没有使用多个标签,而是用一个标签替换了所有内容。现在唯一需要做的调整是使用titlehandletextpad-value 的内部间距。这样更好吗?
【解决方案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()

【讨论】:

    【解决方案3】:

    我改进了@pathoren 的答案,根据图例的 bbox 坐标自动循环定位图例。此代码允许显示复杂图例的所有所需边界线:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      • 2016-11-22
      相关资源
      最近更新 更多