Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
480 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 Reply

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...