Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
476 views
in Technique[技术] by (71.8m points)

matplotlib - python interplay between axis('square') and set_xlim

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 of the 2 separately but not at the same time:

import matplotlib.pyplot as plt

f, (ax1, ax2) = plt.subplots(1, 2)
x = [1 , 4 , 6]
y1 = [4, 7, 9]
y2 = [20, 89, 99]

ax1.plot(x, y1, 'o')
ax2.plot(x, y2, 'o')

myXlim = [0, 8]
ax1.set_xlim(myXlim)
ax2.set_xlim(myXlim)

ax1.axis('square')
ax2.axis('square')
# limit is gone here

ax1.set_xlim(myXlim)
ax2.set_xlim(myXlim)
# square is gone here

plt.show()

If I just use the ax1.set_xlim(myXlim) (and not square) then I can manually adjust the window size to get what I want but how can I do this automatically?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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?.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...