0

I use savefig from Matplotlib to get an Image from a figure, and this image is modified with PIL after that. I also want to remove every padding.

My problem is that the final size of the image is smaller than expected. For example:

  • Size = (8, 10)
  • DPI = 300
  • We expect a width of 300*8=2400
  • But we get a width of 2310

Following this link (https://stackoverflow.com/a/24399985/374458) I've added plt.tight_layout() and it works better. But the size is still smaller than expected. I think it's because of the padding which is not 0 before calling savefig (pad_inches default seems to be 0.1).

How can a get an image with the right size?

Here is a code sample:

from PIL import Image
import matplotlib.pyplot as plt
import io

SIZE_X = 8
SIZE_Y = 10
IMAGE_DPI = 300

fig, ax = plt.subplots(figsize=(SIZE_X, SIZE_Y), dpi=IMAGE_DPI)
ax.set_axis_off()

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

buffer = io.BytesIO()
plt.tight_layout()
plt.savefig(buffer, dpi=IMAGE_DPI, ax=ax, format='png', bbox_inches='tight', pad_inches=0, transparent=True)
buffer.seek(0)
image = Image.open(buffer)


print('Expected: ', (SIZE_X * IMAGE_DPI, SIZE_Y * IMAGE_DPI))
print('Figure size: ', (fig.get_figwidth() * fig.get_dpi(), fig.get_figheight() * fig.get_dpi()))
print('Image Size: ', image.size)

plt.close(fig)
del fig
del buffer

Output:

Expected:  (2400, 3000)
Figure size:  (2400.0, 3000.0)
Image Size:  (2310, 2910)

NB: With the code below I get the right image size but I don't manage to make transparency work.

image = Image.frombytes("RGBA", fig.canvas.get_width_height(), bytes(fig.canvas.get_renderer().buffer_rgba()))
Nicolas
  • 1,812
  • 3
  • 19
  • 43
  • 1
    You should remove `bbox_inches='tight'` from `savefig(...)` if you don't want `savefig` to remove any padding. Also note that `plt.tight_layout()` has a parameter `pad=` which defaults to `1.08` (measured in fraction of font size). – JohanC Feb 20 '23 at 17:16

1 Answers1

0

I finally found a solution. We ned to set the padding as I suspected, and I thought it wasn't possible. But this works:

plt.subplots_adjust(left=0, right=1, top=1, bottom=0)

Any other solution is very welcome! (making frombytes work with transparency maybe?)

Nicolas
  • 1,812
  • 3
  • 19
  • 43