Axes Class - Set Explicitly Size (Width/Height) of Axes in Given Units

Axes class - set explicitly size (width/height) of axes in given units

The axes size is determined by the figure size and the figure spacings, which can be set using figure.subplots_adjust(). In reverse this means that you can set the axes size by setting the figure size taking into acount the figure spacings:

import matplotlib.pyplot as plt

def set_size(w,h, ax=None):
""" w, h: width, height in inches """
if not ax: ax=plt.gca()
l = ax.figure.subplotpars.left
r = ax.figure.subplotpars.right
t = ax.figure.subplotpars.top
b = ax.figure.subplotpars.bottom
figw = float(w)/(r-l)
figh = float(h)/(t-b)
ax.figure.set_size_inches(figw, figh)

fig, ax=plt.subplots()

ax.plot([1,3,2])

set_size(5,5)

plt.show()

determine matplotlib axis size in pixels

This gives the width and height in inches.

bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height

That probably suffices for your purpose, but to get pixels, you can multiply by fig.dpi:

width *= fig.dpi
height *= fig.dpi

For example,

import matplotlib.pyplot as plt

def get_ax_size(ax):
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height
width *= fig.dpi
height *= fig.dpi
return width, height

fig, ax = plt.subplots()
print(get_ax_size(ax))
#(496.0, 384.00000000000006)

ax2 = plt.axes([0.3, 0.3, 0.7, 0.7])
print(get_ax_size(ax2))
# (448.0, 336.0)

To make an image of exactly that figure size, you have to remove whitespace between the figure and the axis:

import numpy as np
import matplotlib.pyplot as plt

def get_ax_size(ax):
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height
width *= fig.dpi
height *= fig.dpi
return width, height

data = np.arange(9).reshape((3, 3))
fig = plt.figure(figsize=(8,6), dpi=80)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(data, aspect='equal')
print(get_ax_size(ax))
# (640.0, 480.0)
plt.savefig('/tmp/test.png', dpi=80)

% identify /tmp/test.png
/tmp/test.png PNG 640x480 640x480+0+0 8-bit DirectClass 50.5KB 0.020u 0:00.020

display image with maximum width keeping an equal ratio

Found with a reading of Axes class - set explicitly size (width/height) of axes in given units
and the use of

set_adjustable('datalim')
import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(nrows=2, figsize=(8,8))
img = ax[0].imshow(np.random.random((10,10)), aspect='equal')
ax[0].set_adjustable('datalim')
line = ax[1].plot([12,34],[45,78])

Sample Image

Same width and height axis in matplotlib for every plot

Thanks @Jody. As your suggestion, I update my code as following. This work for me

max_range = np.array([x2-x1, y2-y1]).max()/2.0
axis.set_xlim((x1+x2)*0.5-max_range, (x1+x2)*0.5+max_range)
axis.set_ylim((y1+y2)*0.5-max_range, (y1+y2)*0.5+max_range)

Matplotlib set subplot axis size iteratively

You can create a new GridSpec specifying the height_ratios and then updating each axs position:

import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

# create figure
f, ax = plt.subplots(3, 1, figsize=(10,10))

# plot some data
ax[0].plot([1, 2, 3])
ax[1].plot([1, 0, 1])
ax[2].plot([1, 2, 20])

# adjust subplot sizes
gs = GridSpec(3, 1, height_ratios=[5, 2, 1])
for i in range(3):
ax[i].set_position(gs[i].get_position(f))

plt.show()

I asked a similar question before here. The use case was slightly different, but it might still be helpful.

How do I equalize the scales of the x-axis and y-axis?

Use Axes.set_aspect in the following manner:

from matplotlib import pyplot as plt
plt.plot(range(5))
plt.xlim(-3, 3)
plt.ylim(-3, 3)
ax = plt.gca()
ax.set_aspect('equal', adjustable='box')
plt.draw()

Specify axis-data margin in matplotlib

We can slightly adapt the function from Axes class - set explicitly size (width/height) of axes in given units
to add a line setting the axes margins.

import matplotlib.pyplot as plt

def set_size(w,h, ax=None, marg=(0.1, 0.1)):
""" w, h: width, height in inches """
if not ax: ax=plt.gca()
l = ax.figure.subplotpars.left
r = ax.figure.subplotpars.right
t = ax.figure.subplotpars.top
b = ax.figure.subplotpars.bottom
figw = float(w)/(r-l)
figh = float(h)/(t-b)
ax.figure.set_size_inches(figw, figh)
ax.margins(x=marg[0]/w, y=marg[1]/h)

And call it with

set_size(width, height, marg=(xmargin, ymargin))

where xmargin, ymargin are the margins in inches.

Aspect ratio (vs. size and position) of inset_axis of axes_divider host axes

As long as the figure is not drawn, the divider axes do not yet know their size. Therefore their bbox is just as large as the parent bbox. The inset_axes are therefore calculated in terms of the main axes size.

This is actually a more or less general rule: If you want to use .get_window_extent() on an artist, you need to make sure it has been drawn at least once prior to getting its extent.

To draw the figure,

plt.gcf().canvas.draw()

Complete code:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

base_ax = plt.subplot(111)

divider = make_axes_locatable(base_ax)
ax_right = divider.append_axes("right", size="20%", pad="1%")
ax_bottom = divider.append_axes("bottom", size="20%", pad="1%")

loc="upper left"
size = 20

plt.gcf().canvas.draw()
bbox = ax_right.get_window_extent()
ratio = bbox.width / bbox.height
inset_right_upper = inset_axes(
ax_right, width=str(size / ratio) + '%', height=str(size) + '%', loc=loc)

bbox = ax_bottom.get_window_extent()
ratio = bbox.width / bbox.height
inset_bottom_upper = inset_axes(
ax_bottom, width=str(size / ratio) + '%', height=str(size) + '%', loc=loc)

plt.show()

producing

Sample Image



Related Topics



Leave a reply



Submit