Skip to content

[Bug]: savefig() cannot save a PNG image 43200x21600 #26751

Closed as not planned
Closed as not planned

Description

@AgilentGCMS

Bug summary

I am trying to plot some data on a map at high resolution, and I think I've come across a limit on the size of the image pyplot.savefig can save. When I save a 21600x10800 image, it works. However, when I try to save 43200x21600 image, it only saves half the image, always exactly half. According to my calculation, a 43200x21600 RGB image without any compression should occupy 2.6 GB, which is large but well within the 32 GB memory of my computer. I would like to know if a size limit is encoded somewhere for savefig, and if there's a way to bypass it. The image displays fine on my screen, just doesn't save to PNG.

Code for reproduction

from matplotlib import pyplot as plt
import numpy as np

# make a checkerboard array of +1 and -1 for plotting
A = np.zeros((90,180))
for i in range(90):
    for j in range(180):
        A[i,j] = (-1)**i * (-1)**j

# create a large canvas
fig = plt.figure(figsize=(24,12))
ax = plt.axes([0.,0.,1.,1.])
ax.axis('off')

# plot and save
ax.imshow(A, vmin=-1, vmax=1, cmap=plt.cm.coolwarm, interpolation='none')
plt.savefig('image_43200.png', dpi=1800) # 24x12 inch image at 1800 dpi = 43200x21600

Actual outcome

No matter what I plot, savefig saves exactly half the image, always the left half. This is what the image looks like opened in GIMP.

Expected outcome

On screen, this is what the image looks like, which is correct. I would expect the saved image to look like this as well.

Additional information

No response

Operating system

MacOS Ventura 13.5.2

Matplotlib Version

3.7.2

Matplotlib Backend

MacOSX

Python version

3.11.4

Jupyter version

No response

Installation

Linux package manager

Activity

  1. scottshambaugh commented on Sep 12, 2023

    @scottshambaugh
    Contributor

    Thank you for reporting! This looks like a duplicate of #26368 to me, closing this thread to consolidate discussion over there.

  2. AgilentGCMS commented on Sep 12, 2023

    @AgilentGCMS
    Author

    I will defer to experts on whether this is a duplicate of #26368 or not, but I see at least one difference between the two bugs. For #26368 the image does not render at all. For this bug, the image does render on the screen but doesn't save.

  3. jklymak commented on Sep 12, 2023

    @jklymak
    Member

    It doesn't save because you make it 18^2 =324 times larger when trying to save. Our backend Agg renderer has a limit of 2^15 = 32_768 pixels in each dimension, which your 24" side is violating.

  4. AgilentGCMS commented on Sep 12, 2023

    @AgilentGCMS
    Author

    @jklymak Ah I see.

    1. Is this a hard limit that cannot be overcome?
    2. If so, perhaps savefig should raise an error instead of silently saving a wrong image?
  5. AgilentGCMS commented on Sep 12, 2023

    @AgilentGCMS
    Author

    I don't actually need to display that image interactively. If I simply need to create that image and save it to a PNG file, is there a way to not use Agg?

  6. oscargus commented on Sep 12, 2023

    @oscargus
    Member

    You may want to try MPL-Cairo https://github.com/matplotlib/mplcairo

    It seems like there are some limitations there as well, but it may work.

    (Showing it or not is not really part of the equation as there are two different rendering processes and the really big one fails.)

  7. AgilentGCMS commented on Sep 16, 2023

    @AgilentGCMS
    Author

    So... I just tried mplcairo, turns out that has size limitations as well. I don't know what that limit is, but when I tried to save the same image with the mplcairo backend, I got this error:

    File ~/packages/macports/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/mplcairo/base.py:63, in GraphicsContextRendererCairo.__init__(self, width, height, dpi)
         60 def __init__(self, width, height, dpi):
         61     # Hide the overloaded constructors used by from_pycairo_ctx and
         62     # _for_fmt_output.
    ---> 63     _mplcairo.GraphicsContextRendererCairo.__init__(
         64         self, width, height, dpi)
         65     RendererBase.__init__(self)
    
    ValueError: invalid value (typically too big) for the size of the input (surface, pattern, etc.)
  8. jklymak commented on Sep 16, 2023

    @jklymak
    Member

    Larger images would require going into agg or cairo, forking them and upping the allowed sizes from 16 bits to 32 bits. Not impossible, but the use case is hard to understand. What are you planning to do with such a huge image?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions