Let's take this as a starting point based on: Specifying and saving a figure with exact size in pixels
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
h = int(sys.argv[1])
fig, ax = plt.subplots(nrows=2, ncols=1)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.savefig(
'main.png',
format='png',
dpi=h/fig.get_size_inches()[1],
facecolor='y',
)
which allows me to do:
./main.py 400 && identify main.png
to generate an image with the correct desired height of 400 pixels:
main.png PNG 533x400 533x400+0+0 8-bit sRGB 6058B 0.000u 0:00.000
However, there's a lot of empty space to the left and right of the plots. This space is due to the fixed aspect ratio of 1
that I also want (x and y data have the same sizes). We can confirm that by removing the set_aspect
calls, which gives a figure with reasonably sized margins:
but I want the 1/1 aspect ratio as well.
I've tried to remove this space with several methods from: Removing white space around a saved image in matplotlib but none gave what I wanted.
For example, if I add:
plt.savefig(bbox_inches='tight',
I get the desired image:
but the height is not 400 anymore as I want it to be:
main.png PNG 189x345 189x345+0+0 8-bit sRGB 4792B 0.000u 0:00.000
Or if I try instead to add:
plt.tight_layout(pad=0)
the height is correct, but it didn't remove the horizontal space:
One thing I could do is to explicitly set the width as in:
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
h = int(sys.argv[1])
w = int(sys.argv[2])
fig, ax = plt.subplots(nrows=2, ncols=1)
wi, hi = fig.get_size_inches()
fig.set_size_inches(hi*(w/h), hi)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.tight_layout(pad=1)
plt.savefig(
'main.png',
format='png',
dpi=h/hi,
facecolor='y',
)
and run that with:
./main.py 400 250 && identify main.png
where 250 is selected by trial and error, and that does give the exact pixel dimensions and good looking output:
but I'd rather not have to do the trial and error to find the value 250, I want that to be determined automatically by matplotlib.
This might be what matplotlib: Set width or height of figure without changing aspect ratio is asking, but it is hard to be sure without concrete examples.
Tested on matplotlib==3.2.2.