Aspect Ratio in Subplots With Various Y-Axes: 3 Answers
Aspect Ratio in Subplots With Various Y-Axes: 3 Answers
Home
Aspect ratio in subplots with various y-axes Ask Question
PUBLIC Asked 7 years, 11 months ago Active 3 years ago Viewed 11k times
Stack Overflow
I would like the following code to produce 4 subplots of the same size with a common aspect ratio
Tags The Overflow Blog
between the size of x-axis and y-axis set by me. Referring to the below example, I would like all of
Users 9 the subplots look exactly like the first one (upper left). What is wrong right now is that the size of Podcast 307: Owning the code, from
the y-axis is correlated with its largest value. That is the behaviour I want to avoid. integration to delivery
FIND A JOB
Building momentum in our transition to a
Jobs
import matplotlib.pyplot as plt product led SaaS company
Companies 5 import numpy as np
Featured on Meta
def main():
TEAMS What’s this?
fig = plt.figure(1, [5.5, 3]) Opt-in alpha test for a new Stacks editor
Free 30 Day Trial
for i in range(1,5):
fig.add_subplot(221+i-1, adjustable='box', aspect=1) 2020: a year in moderation
plt.plot(np.arange(0,(i)*4,i))
Hot Meta Posts
plt.show()
Linked
Related
fig, axes = plt.subplots(nrows=2, ncols=2, sharey=True, sharex=True) What is the minimum amount of votes needed in
for i, ax in enumerate(axes.flat, start=1): both Chambers of Congress to send an Admission
ax.set(aspect=1) to the Union resolution to the President?
ax.plot(np.arange(0, i * 4, i)) Could double jeopardy protect a murderer who
bribed the judge and jury to be declared not guilty?
plt.show()
Calculating the Angular Momentum of a planet
Edit: Sorry, I'm still a bit confused. Do you want something like this?
plt.show()
Okay, I think I finally understand your question. We both meant entirely different things by "aspect
ratio".
In matplotlib, the aspect ratio of the plot refers to the relative scales of the data limits. In other
words, if the aspect ratio of the plot is 1, a line with a slope of one will appear at 45 degrees. You
were assuming that the aspect ratio applied to the outline of the axes and not the data plotted on
the axes.
You just want the outline of the subplots to be square. (In which case, they all have different aspect
ratios, as defined by matplotlib.)
In that case, you need a square figure. (There are other ways, but just making a square figure is far
simpler. Matplotlib axes fill up a space that is proportional to the size of the figure they're in.)
# The key here is the figsize (it needs to be square). The position and size of
# axes in matplotlib are defined relative to the size of the figure.
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8,8))
# By default, subplots leave a bit of room for tick labels on the left.
# We'll remove it so that the axes are perfectly square.
fig.subplots_adjust(left=0.1)
plt.show()
Share Edit Follow edited Feb 18 '13 at 4:36 answered Feb 16 '13 at 15:34
Joe Kington
231k 60 543 442
Hi Joe! Thanks for the attention to my question. I am sorry for the confusion. Neither of your 2 options
provides exactly what I am looking for. The first option is the closest though. It would be perfect if each
one of subplots had its own limit of y-axis. That is what matplotlib does automatically. For instance, the
following: (in the next message) produces the look that I want, but I would also like to control the aspect
ratio of those subplots (one aspect ratio for all of them) – user2077647 Feb 16 '13 at 19:38
code: import matplotlib.pyplot as plt import numpy as np def main(): fig = plt.figure(1, [5.5, 3]) for i in
range(1,5): fig.add_subplot(221+i-1) plt.plot(np.arange(0,(i)*4,i)) plt.show() – user2077647 Feb 16 '13 at
19:41
I have added the picture this code produces in my original question – user2077647 Feb 16 '13 at 19:45
Hi Joe, almost there! This is perfect except I would like all of the suplots have the x-axes limits to be from
0 to 3. That picture I included in the original question is everything I want but with wrong aspect ratio
between axes. So right now it is something like 1/2 but I am looking for 1/1. – user2077647 Feb 17 '13 at
19:18
Sorry, I'm still confused... The aspect ratio can't be constant if neither the limits or size of the axes change.
You seem to be asking for plots that are the exact same size, have the same aspect ratio, the same x-axis
limits, but different y-axis limits. That's impossible, by definition. I think I'm just misunderstanding your
question... – Joe Kington Feb 17 '13 at 23:58
Combing the answer of Joe Kington with new pythonic style for shared axes square subplots in
matplotlib? and another post that I am afraid I cannot find it again, I made a code for precisely
2 setting the ratio of the box to a given value.
Let desired_box_ratioN indicate the desired ratio between y and x sides of the box.
temp_inverse_axis_ratioN is the ratio between x and y sides of the current plot; since 'aspect' is the
ratio between y and x scale (and not axes), we need to set aspect to desired_box_ratioN *
temp_inverse_axis_ratioN.
desired_box_ratioN = 1
for i, ax in enumerate(axes.flat, start=1):
ax.plot(np.arange(0, i * 4, i))
temp_inverse_axis_ratioN = abs( (ax.get_xlim()[1] - ax.get_xlim()[0])/(ax.get_ylim()[1] - ax.get_ylim()[0]) )
ax.set(aspect = desired_box_ratioN * temp_inverse_axis_ratioN, adjustable='box-forced')
plt.show()
Share Edit Follow edited May 23 '17 at 10:28 answered Aug 4 '14 at 14:47
Community ♦ Igor Fobia
1 1 649 8 20
add a comment
The theory
1 Different coordinate systems exists in matplotlib. The differences between different coordinate
systems can really confuse a lot of people. What the OP want is aspect ratio in display coordinate
but ax.set_aspect() is setting the aspect ratio in data coordinate. Their relationship can be
formulated as:
aspect = 1.0/dataRatio*dispRatio
where, aspect is the argument to use in set_aspect method, dataRatio is aspect ratio in data
coordinate and dispRatio is your desired aspect ratio in display coordinate.
The practice
There is a get_data_ratio method which we can use to make our code more concise. A work
code snippet is shown below:
dispRatio = 0.5
for i, ax in enumerate(axes.flat, start=1):
ax.plot(np.arange(0, i * 4, i))
ax.set(aspect=1.0/ax.get_data_ratio()*dispRatio, adjustable='box-forced')
plt.show()
I have also written a detailed post about all this stuff here.
Share Edit Follow edited Jan 8 '18 at 2:13 answered Jan 8 '18 at 2:02
jdhao
11.8k 7 74 132
I have tried to follow your tutorial, which is very clear, however, it does not work when the y-axis has a log
scale, any ideas on widening the x-axis while keeping y-axis on log scale? – seanysull Feb 19 '19 at 15:05
Sorry, I am not sure. Maybe you can open a new question here on Stack Overflow based on that post. –
jdhao Feb 19 '19 at 16:47
add a comment
Your Answer
Links Images Styling/Headers Lists Blockquotes Code HTML Tables Advanced help
Not the answer you're looking for? Browse other questions tagged python matplotlib or ask your own
question.
STACK OVERFLOW PRODUCTS COMPANY STACK EXCHANGE Blog Facebook Twitter LinkedIn Instagram
NETWORK
Questions Teams About
Technology
Jobs Talent Press
Life / Arts
Developer Jobs Directory Advertising Work Here
Culture / Recreation
Salary Calculator Enterprise Legal
Science
Help Privacy Policy
Other
Mobile Terms of Service
site design / logo © 2021 Stack Exchange Inc; user contributions
Disable Responsiveness Contact Us licensed under cc by-sa. rev 2021.1.27.38425