Matplotlib savefig with a legend outside the plot

后端 未结 3 867
天涯浪人
天涯浪人 2020-12-05 17:29

Reading the following article, I managed to put a legend outside plot.

  • How to put the legend out of the plot

code:

import matplo         


        
相关标签:
3条回答
  • 2020-12-05 17:54

    The problem is that when you plot dynamically, matplotlib determines the borders automatically to fit all your objects. When you save a file, things are not being done automatically, so you need to specify the size of your figure, and then the bounding box of your axes object. Here is how to correct your code:

    import matplotlib.pyplot as pyplot
    
    x = [0, 1, 2, 3, 4]
    y = [xx*xx for xx in x]
    
    fig = pyplot.figure(figsize=(3,3))
    ax  = fig.add_subplot(111)
    
    #box = ax.get_position()
    #ax.set_position([0.3, 0.4, box.width*0.3, box.height])
    # you can set the position manually, with setting left,buttom, witdh, hight of the axis
    # object
    ax.set_position([0.1,0.1,0.5,0.8])
    ax.plot(x, y)
    leg = ax.legend(['abc'], loc = 'center left', bbox_to_anchor = (1.0, 0.5))
    
    fig.savefig('aaa.png')
    
    0 讨论(0)
  • 2020-12-05 18:02

    Although this method works with legend, it seems not to be working well with figlegend when there are multiple subplots and we want a single overall legend. figlegend still get cropped when savefig. I just pasted my temporary solution below in case someone faces such a case.

    import matplotlib.pyplot as plt
    
    para = {
        ## this parameter will indicate the position of
        ## subplot within figure, but will not be shown
        ## if using bbox_inches='tight' when saving
        'figure.subplot.top': 0.5
    }
    #plt.rcParams.update(para)
    
    fig = plt.figure()
    
    ax=fig.add_subplot(221)
    ## only needed when what to manually control
    ## subplot ration
    #ax.set_position([0.1,0.6,0.5, 0.4])
    ax.plot([1,1,1])
    
    
    ax=fig.add_subplot(222)
    #ax.set_position([0.7,0.6,0.5, 0.4])
    ax.plot([2,2,2])
    
    ax=fig.add_subplot(223)
    #ax.set_position([0.1,0.1,0.5, 0.4])
    ax.plot([3,3,3])
    
    
    ax=fig.add_subplot(224)
    #ax.set_position([0.7,0.1,0.5, 0.4])
    p1, = ax.plot([4,4,4])
    p2, = ax.plot([2,3,2])
    
    ## figlegend does not work fine with tight bbox
    ## the legend always get cropped by this option
    ## even add bbox extra will not help
    ## had to use legend, and manually adjust it to
    ## arbitary position such as (0.3, 2.5)
    
    ## http://matplotlib.org/users/tight_layout_guide.html
    ## according to this link, tight layout is only
    ## an experimental feature, might not support figlegend
    
    #lgd = plt.figlend(
    lgd = plt.legend(
        [p1,p2],
        ['a', 'b'],
        ## by default, legend anchor to axis, but can
        ## also be anchored to arbitary position
        ## positions within [1,1] would be within the figure
        ## all numbers are ratio by default
    
        bbox_to_anchor=(-0.1, 2.5),
    
        ## loc indicates the position within the figure
        ## it is defined consistent to the same Matlab function 
        loc='center',
    
        ncol=2
        #mode="expand",
        #borderaxespad=0.
        )
    
    
    
    #plt.show()
    
    plt.savefig('temp.png', bbox_inches='tight')#, bbox_extra_artist=[lgd])
    
    0 讨论(0)
  • 2020-12-05 18:03

    If all else fails, I use Inkscape's bounding-box features to deal with what I would call persistent bugs in matplotlib's output. If you're running GNU/Linux, just save whatever Matplotlib gives you as a pdf, and then send it to the following

    def tightBoundingBoxInkscape(pdffile,use_xvfb=True):
        """Makes POSIX-specific OS calls. Preferably, have xvfb installed, to avoid any GUI popping up in the background. If it fails anyway, could always resort to use_xvfb=False, which will allow some GUIs to show as they carry out the task 
          pdffile: the path for a PDF file, without its extension
        """
        usexvfb='xvfb-run '*use_xvfb
        import os
        assert not pdffile.endswith('.pdf')
        os.system("""
           inkscape -f %(FN)s.pdf -l %(FN)s_tmp.svg
           inkscape -f %(FN)s_tmp.svg --verb=FitCanvasToDrawing \
                                       --verb=FileSave \
                                       --verb=FileQuit
          inkscape -f %(FN)s_tmp.svg -A %(FN)s-tightbb.pdf
    """%{'FN':pdffile}
    
    0 讨论(0)
提交回复
热议问题