How to put the legend out of the plot

后端 未结 17 3195
时光说笑
时光说笑 2020-11-21 04:42

I have a series of 20 plots (not subplots) to be made in a single figure. I want the legend to be outside of the box. At the same time, I do not want to change the axes, a

相关标签:
17条回答
  • 2020-11-21 05:14

    Short answer: you can use bbox_to_anchor + bbox_extra_artists + bbox_inches='tight'.


    Longer answer: You can use bbox_to_anchor to manually specify the location of the legend box, as some other people have pointed out in the answers.

    However, the usual issue is that the legend box is cropped, e.g.:

    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

    In order to prevent the legend box from getting cropped, when you save the figure you can use the parameters bbox_extra_artists and bbox_inches to ask savefig to include cropped elements in the saved image:

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

    Example (I only changed the last line to add 2 parameters to 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

    I wish that matplotlib would natively allow outside location for the legend box as 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

    0 讨论(0)
  • 2020-11-21 05:16

    Short Answer: Invoke draggable on the legend and interactively move it wherever you want:

    ax.legend().draggable()
    

    Long Answer: If you rather prefer to place the legend interactively/manually rather than programmatically, you can toggle the draggable mode of the legend so that you can drag it to wherever you want. Check the example below:

    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()
    
    0 讨论(0)
  • 2020-11-21 05:17

    To place the legend outside the plot area, use loc and bbox_to_anchor keywords of legend(). For example, the following code will place the legend to the right of the plot area:

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

    For more info, see the legend guide

    0 讨论(0)
  • 2020-11-21 05:19

    Just call legend() call after the plot() call like this:

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

    Results would look something like this:

    enter image description here

    0 讨论(0)
  • 2020-11-21 05:21
    • You can make the legend text smaller by specifying set_size of FontProperties.
    • Resources:
      • Legend guide
      • matplotlib.legend
      • matplotlib.pyplot.legend
      • matplotlib.font_manager
        • set_size(self, size)
        • Valid font size are xx-small, x-small, small, medium, large, x-large, xx-large, larger, smaller, None
      • Real Python: Python Plotting With Matplotlib (Guide)
    import matplotlib.pyplot as plt
    from matplotlib.font_manager import FontProperties
    
    fontP = FontProperties()
    fontP.set_size('xx-small')
    
    p1, = plt.plot([1, 2, 3], label='Line 1')
    p2, = plt.plot([3, 2, 1], label='Line 2')
    plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', prop=fontP)
    

    • As noted by Mateen Ulhaq, fontsize='xx-small' also works, without importing FontProperties.
    plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', fontsize='xx-small')
    
    0 讨论(0)
  • 2020-11-21 05:21

    Not exactly what you asked for, but I found it's an alternative for the same problem. Make the legend semi-transparant, like so: matplotlib plot with semi transparent legend and semitransparent text box

    Do this with:

    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)
    
    0 讨论(0)
提交回复
热议问题