Philo
Philo

Reputation: 103

How to set same aspect ratio for subplots in matplotlib

I want to have a row of subplots with the same aspect ratio. Let's say I want to plot two different functions that have different extents on the y axis.

There seem to be lots of questions on this but the examples seem to conveniently have the same axes for all subplots. In any case none that I found were helpful to me.

I've tried the following

import numpy as np
import matplotlib.pyplot as plt

xdata = np.arange(0,2,.01)
ydata1 = xdata
ydata2 = xdata ** 2

fig, ax = plt.subplots(1,2)

ax[0].plot(xdata,ydata1)
ax[1].plot(xdata,ydata2)

ax[0].set_aspect(.5)
ax[1].set_aspect(.5)
plt.show(fig)

plots

However, matplotlib appears to be using the x and y axis data to determine the aspect ratio and because the y axes have different extents the subplots come out different. This is super weird to me. How do I make them the same physical aspect ratio?

I guess one can try extracting the the limits for each subplot and calculate the right aspect ratio individually but this seems to be a very roundabout way and I would expect such a basic functionality as making all subplots look the same to be built in.

EDIT So what I want is for both subplots to have the same aspect ratio in the human sense, that is that the ratio of the width of the figure to the height is the same for both. For example in Mathematica I would achieve this by simply setting the AspectRatio attribute:

xdata = Range[0, 2, .01];
ydata1 = {#, #} & /@ xdata;
ydata2 = {#, #^2} & /@ xdata;
fig = GraphicsRow[
   ListLinePlot[#, AspectRatio -> 1/GoldenRatio, Frame -> True, 
      ImageSize -> 300] & /@ {ydata1, ydata2}];
Export["fig.png", fig]

Made by Mathematica

Upvotes: 1

Views: 4658

Answers (2)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339052

The question isn't entirely clear on what the desired outcome is. Possibly you want to have a fixed data aspect with out changing the axes?

import numpy as np
import matplotlib.pyplot as plt

xdata = np.arange(0,2,.01)
ydata1 = xdata
ydata2 = xdata ** 2

fig, ax = plt.subplots(1,2)

ax[0].plot(xdata,ydata1)
ax[1].plot(xdata,ydata2)

ax[0].set_aspect(.5, adjustable="datalim")
ax[1].set_aspect(.5, adjustable="datalim")
plt.show()

enter image description here

Upvotes: 1

soyapencil
soyapencil

Reputation: 629

Short answer: use the figsize keyword argument when making subplots:

import numpy as np
import matplotlib.pyplot as plt

xdata = np.arange(0,2,.01)
ydata1 = xdata
ydata2 = xdata ** 2

fig = plt.figure(figsize=(10,6))
ax = fig.subplots(1,2)

ax[0].plot(xdata,ydata1)
ax[1].plot(xdata,ydata2)

# Squares
ax[0].plot([0,1,1,0],[0,0,1,1])
ax[1].plot([0,1,1,0],[0,0,1,1])

plt.show(fig)

figsize is a tuple in inches, with the first element as the width in the x-direction, the second element as the width in the y-direction.

It applies to the whole figure; you will need to tweak it to get a suitable shape for your subplots.

enter image description here

Longer answer: .set_aspect(num) sets the y-axis to x-axis ratio for each plot.

So, when you used .set_aspect(.5) on each axis, you told matplotlib to reconfigure each axis such that the y-axis is 0.5 times as big as the x-axis. This means that a 1x1 square actually looks like a rectangle on each plot:

import numpy as np
import matplotlib.pyplot as plt

xdata = np.arange(0,2,.01)
ydata1 = xdata
ydata2 = xdata ** 2

fig, ax = plt.subplots(1,2)

ax[0].plot(xdata,ydata1)
ax[1].plot(xdata,ydata2)

# Squares
ax[0].plot([0,1,1,0],[0,0,1,1])
ax[1].plot([0,1,1,0],[0,0,1,1])

ax[0].set_aspect(.5)
ax[1].set_aspect(.5)
plt.show(fig)

That's why your plots are different shapes; the axis limits are different, but you've set the size of shapes on both plots to be the same.

enter image description here

Upvotes: 2

Related Questions