首页 文章

如何把这个传说放出情节

提问于
浏览
665

我有一系列20个图(不是子图)可以在一个图中制作 . 我希望传说能够超越盒子 . 与此同时,我不想改变轴,因为图形的大小减少了 . 请帮助我以下查询:

  • 我想将图例框保留在绘图区域之外 . (我希望传说位于情节区域的右侧) .

  • 无论如何,我减少了图例框内文本的字体大小,因此图例框的大小会很小 .

16 回答

  • 0

    Short Answer :在图例上调用draggable并以交互方式将其移动到任何您想要的位置:

    ax.legend().draggable()
    

    Long Answer :如果您更喜欢以交互方式/手动方式而不是以编程方式放置图例,则可以切换图例的可拖动模式,以便将其拖动到任意位置 . 请查看以下示例:

    import matplotlib.pylab as plt
    import numpy as np
    #define the figure and get an axes instance
    fig = plt.figure()
    ax = fig.add_subplot(111)
    #plot the data
    x = np.arange(-5, 6)
    ax.plot(x, x*x, label='y = x^2')
    ax.plot(x, x*x*x, label='y = x^3')
    ax.legend().draggable()
    plt.show()
    
  • 48

    你也可以试试 figlegend . 可以创建独立于任何Axes对象的图例 . 但是,您可能需要创建一些"dummy"路径以确保正确传递对象的格式 .

  • 1

    有很多方法可以做你想要的 . 要添加@inalis和@Navi已经说过的内容,可以使用 bbox_to_anchor 关键字参数将图例部分放在轴外和/或减小字体大小 .

    在考虑减小字体大小(这可能使事情难以阅读)之前,尝试将图例放在不同的地方:

    那么,让我们从一个通用的例子开始:

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.arange(10)
    
    fig = plt.figure()
    ax = plt.subplot(111)
    
    for i in xrange(5):
        ax.plot(x, i * x, label='$y = %ix$' % i)
    
    ax.legend()
    
    plt.show()
    

    alt text

    如果我们做同样的事情,但使用 bbox_to_anchor 关键字参数,我们可以稍微将图例移到轴边界之外:

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.arange(10)
    
    fig = plt.figure()
    ax = plt.subplot(111)
    
    for i in xrange(5):
        ax.plot(x, i * x, label='$y = %ix$' % i)
    
    ax.legend(bbox_to_anchor=(1.1, 1.05))
    
    plt.show()
    

    alt text

    同样,你可以使图例更加水平和/或将它放在图的顶部(我也打开圆角和一个简单的阴影):

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.arange(10)
    
    fig = plt.figure()
    ax = plt.subplot(111)
    
    for i in xrange(5):
        line, = ax.plot(x, i * x, label='$y = %ix$'%i)
    
    ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
              ncol=3, fancybox=True, shadow=True)
    plt.show()
    

    alt text

    或者,您可以缩小当前图的宽度,并将图例完全放在图的轴外:

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.arange(10)
    
    fig = plt.figure()
    ax = plt.subplot(111)
    
    for i in xrange(5):
        ax.plot(x, i * x, label='$y = %ix$'%i)
    
    # Shrink current axis by 20%
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
    
    # Put a legend to the right of the current axis
    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
    
    plt.show()
    

    alt text

    以类似的方式,您可以垂直缩小绘图,并将水平图例放在底部:

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.arange(10)
    
    fig = plt.figure()
    ax = plt.subplot(111)
    
    for i in xrange(5):
        line, = ax.plot(x, i * x, label='$y = %ix$'%i)
    
    # Shrink current axis's height by 10% on the bottom
    box = ax.get_position()
    ax.set_position([box.x0, box.y0 + box.height * 0.1,
                     box.width, box.height * 0.9])
    
    # Put a legend below current axis
    ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
              fancybox=True, shadow=True, ncol=5)
    
    plt.show()
    

    alt text

    看看matplotlib legend guide . 你也可以看一下plt.figlegend() . 无论如何,希望有所帮助!

  • 1

    只需在 plot() 调用之后调用 legend() 调用,如下所示:

    # matplotlib
    plt.plot(...)
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
    
    # Pandas
    df.myCol.plot().legend(loc='center left', bbox_to_anchor=(1, 0.5))
    

    结果看起来像这样:

    enter image description here

  • 117

    不知道你是否已经解决了你的问题...可能是的,但是......我只是在字符串'outside'中使用了该位置,就像在matlab中一样 . 我从matplotlib导入了pylab . 看到代码如下:

    from matplotlib as plt
    from matplotlib.font_manager import FontProperties
    ...
    ...
    t = A[:,0]
    sensors = A[:,index_lst]
    
    for i in range(sensors.shape[1]):
        plt.plot(t,sensors[:,i])
    
    plt.xlabel('s')
    plt.ylabel('°C')
    lgd = plt.legend(b,loc='center left', bbox_to_anchor=(1, 0.5),fancybox = True, shadow = True)
    

    Click to see the plot

  • 7

    如上所述,您还可以将图例放置在绘图中,或稍微偏离边缘 . 这是一个使用Plotly Python API的示例,使用IPython Notebook制作 . 我在团队中 .

    首先,您需要安装必要的软件包:

    import plotly
    import math
    import random
    import numpy as np
    

    然后,安装Plotly:

    un='IPython.Demo'
    k='1fw3zw2o13'
    py = plotly.plotly(username=un, key=k)
    
    
    def sin(x,n):
    sine = 0
    for i in range(n):
        sign = (-1)**i
        sine = sine + ((x**(2.0*i+1))/math.factorial(2*i+1))*sign
    return sine
    
    x = np.arange(-12,12,0.1)
    
    anno = {
    'text': '$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$',
    'x': 0.3, 'y': 0.6,'xref': "paper", 'yref': "paper",'showarrow': False,
    'font':{'size':24}
    }
    
    l = {
    'annotations': [anno], 
    'title': 'Taylor series of sine',
    'xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
    'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
    'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}
    }
    
    py.iplot([{'x':x, 'y':sin(x,1), 'line':{'color':'#e377c2'}, 'name':'$x\\\\$'},\
          {'x':x, 'y':sin(x,2), 'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
          {'x':x, 'y':sin(x,3), 'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
          {'x':x, 'y':sin(x,4), 'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)
    

    这将创建您的图形,并允许您有机会将图例保留在图表本身中 . 如果未设置,则图例的默认值是将其放置在图中,如此处所示 .

    enter image description here

    对于替代放置,您可以紧密对齐图形的边缘和图例的边框,并删除边框线以便更贴合 .

    enter image description here

    您可以使用代码或GUI移动和重新设置图例和图形的样式 . 要移动图例,可以使用以下选项通过指定x和y值<= 1来将图例放置在图表内.E.g:

    • {"x" : 0,"y" : 0} - 左下角

    • {"x" : 1, "y" : 0} - 右下角

    • {"x" : 1, "y" : 1} - 右上角

    • {"x" : 0, "y" : 1} - 左上角

    • {"x" :.5, "y" : 0} - 底部中心

    • {"x": .5, "y" : 1} - 顶级中心

    在这种情况下,我们选择右上角 legendstyle = {"x" : 1, "y" : 1} ,也在the documentation中描述:

    enter image description here

  • 3

    不完全是你要求的,但我发现它是同一问题的替代方案 . 让传奇半透明,如下:
    matplotlib plot with semi transparent legend and semitransparent text box

    这样做:

    fig = pylab.figure()
    ax = fig.add_subplot(111)
    ax.plot(x,y,label=label,color=color)
    # Make the legend transparent:
    ax.legend(loc=2,fontsize=10,fancybox=True).get_frame().set_alpha(0.5)
    # Make a transparent text box
    ax.text(0.02,0.02,yourstring, verticalalignment='bottom',
                         horizontalalignment='left',
                         fontsize=10,
                         bbox={'facecolor':'white', 'alpha':0.6, 'pad':10},
                         transform=self.ax.transAxes)
    
  • 48

    简答:您可以使用 bbox_to_anchor bbox_extra_artists bbox_inches='tight' .


    更长的答案:您可以使用 bbox_to_anchor 手动指定图例框的位置,正如其他人在答案中指出的那样 .

    但是,通常的问题是图例框被裁剪,例如:

    import matplotlib.pyplot as plt
    
    # data 
    all_x = [10,20,30]
    all_y = [[1,3], [1.5,2.9],[3,2]]
    
    # Plot
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(all_x, all_y)
    
    # Add legend, title and axis labels
    lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
    ax.set_title('Title')
    ax.set_xlabel('x label')
    ax.set_ylabel('y label')
    
    fig.savefig('image_output.png', dpi=300, format='png')
    

    enter image description here

    为了防止图例框被裁剪,当您保存图形时,您可以使用参数 bbox_extra_artistsbbox_inches 来询问 savefig 以在保存的图像中包含裁剪的元素:

    fig.savefig('image_output.png', bbox_extra_artists=(lgd,), bbox_inches='tight')

    示例(我只更改了最后一行,将2个参数添加到 fig.savefig() ):

    import matplotlib.pyplot as plt
    
    # data 
    all_x = [10,20,30]
    all_y = [[1,3], [1.5,2.9],[3,2]]
    
    # Plot
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(all_x, all_y)
    
    # Add legend, title and axis labels
    lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
    ax.set_title('Title')
    ax.set_xlabel('x label')
    ax.set_ylabel('y label')    
    
    fig.savefig('image_output.png', dpi=300, format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
    

    enter image description here

    我希望matplotlib本身允许传说框的外部位置为Matlab does

    figure
    x = 0:.2:12;
    plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
    hleg = legend('First','Second','Third',...
                  'Location','NorthEastOutside')
    % Make the text of the legend italic and color it brown
    set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])
    

    enter image description here

  • 73

    这些方面的东西对我有用 . 从Joe获取的一些代码开始,此方法修改窗口宽度以自动将图例放在图的右侧 .

    import matplotlib.pyplot as plt
    import numpy as np
    
    plt.ion()
    
    x = np.arange(10)
    
    fig = plt.figure()
    ax = plt.subplot(111)
    
    for i in xrange(5):
        ax.plot(x, i * x, label='$y = %ix$'%i)
    
    # Put a legend to the right of the current axis
    leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
    
    plt.draw()
    
    # Get the ax dimensions.
    box = ax.get_position()
    xlocs = (box.x0,box.x1)
    ylocs = (box.y0,box.y1)
    
    # Get the figure size in inches and the dpi.
    w, h = fig.get_size_inches()
    dpi = fig.get_dpi()
    
    # Get the legend size, calculate new window width and change the figure size.
    legWidth = leg.get_window_extent().width
    winWidthNew = w*dpi+legWidth
    fig.set_size_inches(winWidthNew/dpi,h)
    
    # Adjust the window size to fit the figure.
    mgr = plt.get_current_fig_manager()
    mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))
    
    # Rescale the ax to keep its original size.
    factor = w*dpi/winWidthNew
    x0 = xlocs[0]*factor
    x1 = xlocs[1]*factor
    width = box.width*factor
    ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])
    
    plt.draw()
    
  • 413

    这是另一种解决方案,类似于添加 bbox_extra_artistsbbox_inches ,您无需在 savefig 电话范围内拥有额外的艺术家 . 我想出了这个,因为我在函数中生成了大部分情节 .

    当你想要将它们添加到边界框时,你可以提前将它们添加到 Figure 's artists. Using something similar to Franck Dernoncourt' s answer above

    import matplotlib.pyplot as plt
    
    # data 
    all_x = [10,20,30]
    all_y = [[1,3], [1.5,2.9],[3,2]]
    
    # plotting function
    def gen_plot(x, y):
        fig = plt.figure(1)
        ax = fig.add_subplot(111)
        ax.plot(all_x, all_y)
        lgd = ax.legend( [ "Lag " + str(lag) for lag in all_x], loc="center right", bbox_to_anchor=(1.3, 0.5))
        fig.artists.append(lgd) # Here's the change
        ax.set_title("Title")
        ax.set_xlabel("x label")
        ax.set_ylabel("y label")
        return fig
    
    # plotting
    fig = gen_plot(all_x, all_y)
    
    # No need for `bbox_extra_artists`
    fig.savefig("image_output.png", dpi=300, format="png", bbox_inches="tight")
    

    Here's the generated plot.

  • 2

    要将图例放置在绘图区域之外,请使用legend()的loc和bbox_to_anchor关键字 . 例如,以下代码将图例放置在绘图区域的右侧:

    legend(loc="upper left", bbox_to_anchor=(1,1))
    

    有关详细信息,请参阅legend guide

  • 1378

    创建字体属性

    from matplotlib.font_manager import FontProperties
    
    fontP = FontProperties()
    fontP.set_size('small')
    legend([plot1], "title", prop=fontP)
    
  • 89

    这是一个来自matplotlib教程的例子here . 这是一个更简单的例子,但我为图例添加了透明度并添加了plt.show(),因此您可以将其粘贴到交互式shell中并获得结果:

    import matplotlib.pyplot as plt
    p1, = plt.plot([1, 2, 3])
    p2, = plt.plot([3, 2, 1])
    p3, = plt.plot([2, 3, 1])
    plt.legend([p2, p1, p3], ["line 1", "line 2", "line 3"]).get_frame().set_alpha(0.5)
    plt.show()
    
  • 13

    除了这里所有优秀的答案, matplotlibpylab 的较新版本可以 automatically determine where to put the legend without interfering with the plots .

    pylab.legend(loc='best')
    

    这将自动将图例放在图表之外!
    Compare the use of loc='best'

  • 0

    放置图例(bbox_to_anchor)

    使用plt.legendloc 参数将图例定位在轴的边界框内 .
    例如 . loc="upper right" 将图例放置在边界框的右上角,默认情况下,在轴坐标(或边界框符号 (x0,y0, width, height)=(0,0,1,1) )中从 (0,0)(1,1) 的范围 .

    要将图例放置在轴边界框之外,可以指定图例左下角的轴坐标的元组 (x0,y0) .

    plt.legend(loc=(1.04,0))
    

    但是,更通用的方法是使用 bbox_to_anchor 参数手动指定应放置图例的边界框 . 人们可以限制自己只提供bbox的 (x0,y0) 部分 . 这将创建一个零 Span 框,其中图例将按 loc 参数指定的方向展开 . 例如 .


    plt.legend(bbox_to_anchor=(1.04,1), loc="upper left")
    

    将图例放在轴外,使图例的左上角位于轴坐标的 (1.04,1) 位置 .

    下面给出了进一步的示例,其中还示出了诸如 modencols 之类的不同参数之间的相互作用 .

    l1 = plt.legend(bbox_to_anchor=(1.04,1), borderaxespad=0)
    l2 = plt.legend(bbox_to_anchor=(1.04,0), loc="lower left", borderaxespad=0)
    l3 = plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
    l4 = plt.legend(bbox_to_anchor=(0,1.02,1,0.2), loc="lower left",
                    mode="expand", borderaxespad=0, ncol=3)
    l5 = plt.legend(bbox_to_anchor=(1,0), loc="lower right", 
                    bbox_transform=fig.transFigure, ncol=3)
    l6 = plt.legend(bbox_to_anchor=(0.4,0.8), loc="upper right")
    

    有关如何将_412813_的4元组参数解释为 l4 的详细信息,请参见this question . mode="expand" 在4元组给出的边界框内水平扩展图例 . 有关垂直展开的图例,请参阅this question .

    有时,在图形坐标中指定边界框而不是轴坐标可能很有用 . 这在上面的示例 l5 中显示,其中 bbox_transform 参数用于将图例放在图的左下角 .

    后处理

    将图例放置在轴外部通常会导致不希望的情况,即它完全或部分位于图形画布之外 .

    这个问题的解决方案是:

    • Adjust the subplot parameters
      可以通过使用plt.subplots_adjust调整子图参数,使轴在图中占用较少的空间(从而为图例留出更多空间) . 例如 .
    plt.subplots_adjust(right=0.7)
    

    在图的右侧留下30%的空间,可以放置图例 .

    • Tight layout
      使用plt.tight_layout允许自动调整子图参数,使图中的元素紧贴图形边缘 . 不幸的是,在这种自动化中没有考虑图例,但我们可以提供一个矩形框,整个子图区域(包括标签)将适合 .
    plt.tight_layout(rect=[0,0,0.75,1])
    
    • Saving the figure with bbox_inches = "tight"
      参数 bbox_inches = "tight"plt.savefig可用于保存图形,使画布上的所有艺术家(包括图例)都适合保存的区域 . 如果需要,可自动调整图形大小 .
    plt.savefig("output.png", bbox_inches="tight")
    

    上述案例之间的比较:

    替代品

    A figure legend
    人们可以使用图例而不是轴,matplotlib.figure.Figure.legend . 这对于matplotlib版本> = 2.1特别有用,其中不需要特殊参数

    fig.legend(loc=7)
    

    为图中不同轴的所有艺术家创建一个图例 . 使用 loc 参数放置图例,类似于它放置在轴内的方式,但是参考整个图形 - 因此它会稍微自动地在轴外 . 剩下的就是调整子图,使图例和轴之间没有重叠 . 这里从上面的点"Adjust the subplot parameters"将是有帮助的 . 一个例子:

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = np.linspace(0,2*np.pi)
    colors=["#7aa0c4","#ca82e1" ,"#8bcd50","#e18882"]
    fig, axes = plt.subplots(ncols=2)
    for i in range(4):
        axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))
    
    fig.legend(loc=7)
    fig.tight_layout()
    fig.subplots_adjust(right=0.75)   
    plt.show()
    

    Legend inside dedicated subplot axes
    使用 bbox_to_anchor 的替代方法是将图例放置在其专用子图轴( lax )中 . 由于图例子图应小于图,我们可以在创建轴时使用 gridspec_kw={"width_ratios":[4,1]} . 我们可以隐藏轴 lax.axis("off") 但仍然放入图例 . 图例处理和标签需要通过 h,l = ax.get_legend_handles_labels() 从真实情节中获取,然后可以提供给 lax 子图中的图例, lax.legend(h,l) . 下面是一个完整的例子 .

    import matplotlib.pyplot as plt
    plt.rcParams["figure.figsize"] = 6,2
    
    fig, (ax,lax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios":[4,1]})
    ax.plot(x,y, label="y=sin(x)")
    ....
    
    h,l = ax.get_legend_handles_labels()
    lax.legend(h,l, borderaxespad=0)
    lax.axis("off")
    
    plt.tight_layout()
    plt.show()
    

    这会产生一个与上图相似的视图:

    我们也可以使用第一个轴放置图例,但使用图例轴的 bbox_transform

    ax.legend(bbox_to_anchor=(0,0,1,1), bbox_transform=lax.transAxes)
    lax.axis("off")
    

    在这种方法中,我们不需要从外部获取图例句柄,但我们需要指定 bbox_to_anchor 参数 .

    进一步阅读和注意事项:

    • 考虑matplotlib legend guide以及一些你想用传说做的其他东西的例子 .

    • 在回答这个问题时可以直接找到一些用于为饼图放置图例的示例代码:Python - Legend overlaps with the pie chart

    • loc 参数可以使用数字而不是字符串,这会使调用更短,但是,它们不是非常直观地相互映射 . 以下是参考的映射:

  • 51

    当我有一个巨大的传奇时,对我有用的解决方案是使用额外的空图像布局 . 在下面的示例中,我制作了4行,在底部我绘制了带有图例偏移的图像(bbox_to_anchor),但是它没有被剪切 .

    f = plt.figure()
    ax = f.add_subplot(414)
    lgd = ax.legend(loc='upper left', bbox_to_anchor=(0, 4), mode="expand", borderaxespad=0.3)
    ax.autoscale_view()
    plt.savefig(fig_name, format='svg', dpi=1200, bbox_extra_artists=(lgd,), bbox_inches='tight')
    

相关问题