python interplay between axis('square') and set_xlim

前端 未结 1 768
臣服心动
臣服心动 2020-12-04 00:38

For a correlation plot I would like to have a plot that is optically square (same length of x and y in pixels) but also has a certain axis limit on x and y. I can get each o

相关标签:
1条回答
  • 2020-12-04 01:02

    An option to get square subplots is to set the subplot parameters such that the resulting subplots automatically adjust to be square. This is a little involved, because all the margins and spacings need to be taken into account.

    import matplotlib.pyplot as plt
    
    f, (ax1, ax2) = plt.subplots(1, 2)
    x = [1 , 4 , 6]
    y1 = [4, 7, 9]
    y2 = [20, 89, 99]
    
    def square_subplots(fig):
        rows, cols = ax1.get_subplotspec().get_gridspec().get_geometry()
        l = fig.subplotpars.left
        r = fig.subplotpars.right
        t = fig.subplotpars.top
        b = fig.subplotpars.bottom
        wspace = fig.subplotpars.wspace
        hspace = fig.subplotpars.hspace
        figw,figh = fig.get_size_inches()
    
        axw = figw*(r-l)/(cols+(cols-1)*wspace)
        axh = figh*(t-b)/(rows+(rows-1)*hspace)
        axs = min(axw,axh)
        w = (1-axs/figw*(cols+(cols-1)*wspace))/2.
        h = (1-axs/figh*(rows+(rows-1)*hspace))/2.
        fig.subplots_adjust(bottom=h, top=1-h, left=w, right=1-w)
    
    ax1.plot(x, y1, 'o')
    ax2.plot(x, y2, 'o')
    
    #f.tight_layout() # optionally call tight_layout first
    square_subplots(f)
    
    plt.show()
    

    The benefit here is to be able to freely zoom and autoscale. The drawback is that once the figure size changes, the subplot sizes are not square any more. To overcome this drawback, one may in addition register a callback on size changes of the figure.

    import matplotlib.pyplot as plt
    
    f, (ax1, ax2) = plt.subplots(1, 2)
    x = [1 , 4 , 6]
    y1 = [4, 7, 9]
    y2 = [20, 89, 99]
    
    class SquareSubplots():
        def __init__(self, fig):
            self.fig = fig
            self.ax = self.fig.axes[0]
            self.figw,self.figh = 0,0
            self.params = [self.fig.subplotpars.left,
                           self.fig.subplotpars.right,
                           self.fig.subplotpars.top,
                           self.fig.subplotpars.bottom,
                           self.fig.subplotpars.wspace,
                           self.fig.subplotpars.hspace]
            self.rows, self.cols = self.ax.get_subplotspec().get_gridspec().get_geometry()
            self.update(None)
            self.cid = self.fig.canvas.mpl_connect('resize_event', self.update)
    
    
        def update(self, evt):
            figw,figh = self.fig.get_size_inches()
            if self.figw != figw or self.figh != figh:
                self.figw = figw; self.figh = figh
                l,r,t,b,wspace,hspace = self.params
                axw = figw*(r-l)/(self.cols+(self.cols-1)*wspace)
                axh = figh*(t-b)/(self.rows+(self.rows-1)*hspace)
                axs = min(axw,axh)
                w = (1-axs/figw*(self.cols+(self.cols-1)*wspace))/2.
                h = (1-axs/figh*(self.rows+(self.rows-1)*hspace))/2.
                self.fig.subplots_adjust(bottom=h, top=1-h, left=w, right=1-w)
                self.fig.canvas.draw_idle()
    
    s = SquareSubplots(f)
    
    ax1.plot(x, y1, 'o')
    ax2.plot(x, y2, 'o')
    
    plt.show()
    

    The above solution works by restricting the space the subplot has inside of its grid. An opposite approach, where the size of the subplot is somehow fixed, would be shown in the answer to Create equal aspect (square) plot with multiple axes when data limits are different?.

    0 讨论(0)
提交回复
热议问题