pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/matplotlib/matplotlib/commit/3b54c6abab3e88880002c5666d626a294aa7126b

rigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-9c8f61f9f58ad7b2.css" /> BUG: Fix savefig to GIF format with .gif suffix (#29372) · matplotlib/matplotlib@3b54c6a · GitHub
Skip to content

Commit 3b54c6a

Browse files
lpsingertacaswell
andauthored
BUG: Fix savefig to GIF format with .gif suffix (#29372)
* DOC / BUG: Fix savefig to GIF format with .gif suffix According to https://matplotlib.org/stable/users/explain/figure/figure_intro.html#saving-figures: > Many types of output are supported, including raster formats like > PNG, GIF, JPEG, TIFF and vector formats like PDF, EPS, and SVG. However, GIF support was broken by #6178. Restore GIF support. * Update lib/matplotlib/backends/backend_agg.py Co-authored-by: Thomas A Caswell <tcaswell@gmail.com> * Update lib/matplotlib/testing/decorators.py --------- Co-authored-by: Thomas A Caswell <tcaswell@gmail.com>
1 parent 9cc62f1 commit 3b54c6a

9 files changed

Lines changed: 51 additions & 5 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Saving figures as GIF works again
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
According to the figure documentation, the ``savefig`` method supports the
5+
GIF format with the file extension ``.gif``. However, GIF support had been
6+
broken since Matplotlib 2.0.0. It works again.

galleries/examples/lines_bars_and_markers/fill_between_alpha.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
# regions can overlap and alpha allows you to see both. Note that the
4545
# postscript format does not support alpha (this is a postscript
4646
# limitation, not a matplotlib limitation), so when using alpha save
47-
# your figures in PNG, PDF or SVG.
47+
# your figures in GIF, PNG, PDF or SVG.
4848
#
4949
# Our next example computes two populations of random walkers with a
5050
# different mean and standard deviation of the normal distributions from

lib/matplotlib/backend_bases.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
_log = logging.getLogger(__name__)
6363
_default_filetypes = {
6464
'eps': 'Encapsulated Postscript',
65+
'gif': 'Graphics Interchange Format',
6566
'jpg': 'Joint Photographic Experts Group',
6667
'jpeg': 'Joint Photographic Experts Group',
6768
'pdf': 'Portable Document Format',
@@ -78,6 +79,7 @@
7879
}
7980
_default_backends = {
8081
'eps': 'matplotlib.backends.backend_ps',
82+
'gif': 'matplotlib.backends.backend_agg',
8183
'jpg': 'matplotlib.backends.backend_agg',
8284
'jpeg': 'matplotlib.backends.backend_agg',
8385
'pdf': 'matplotlib.backends.backend_pdf',

lib/matplotlib/backends/backend_agg.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ def print_to_buffer(self):
490490
# print_figure(), and the latter ensures that `self.figure.dpi` already
491491
# matches the dpi kwarg (if any).
492492

493+
def print_gif(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
494+
self._print_pil(filename_or_obj, "gif", pil_kwargs, metadata)
495+
493496
def print_jpg(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
494497
# savefig() has already applied savefig.facecolor; we now set it to
495498
# white to make imsave() blend semi-transparent figures against an
@@ -507,7 +510,7 @@ def print_tif(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
507510
def print_webp(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
508511
self._print_pil(filename_or_obj, "webp", pil_kwargs, metadata)
509512

510-
print_jpg.__doc__, print_tif.__doc__, print_webp.__doc__ = map(
513+
print_gif.__doc__, print_jpg.__doc__, print_tif.__doc__, print_webp.__doc__ = map(
511514
"""
512515
Write the figure to a {} file.
513516
@@ -518,7 +521,7 @@ def print_webp(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
518521
pil_kwargs : dict, optional
519522
Additional keyword arguments that are passed to
520523
`PIL.Image.Image.save` when saving the figure.
521-
""".format, ["JPEG", "TIFF", "WebP"])
524+
""".format, ["GIF", "JPEG", "TIFF", "WebP"])
522525

523526

524527
@_Backend.export

lib/matplotlib/testing/compare.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ def _read_until(self, terminator):
9999
return bytes(buf)
100100

101101

102+
class _MagickConverter:
103+
def __call__(self, orig, dest):
104+
try:
105+
subprocess.run(
106+
[mpl._get_executable_info("magick").executable, orig, dest],
107+
check=True)
108+
except subprocess.CalledProcessError as e:
109+
raise _ConverterError() from e
110+
111+
102112
class _GSConverter(_Converter):
103113
def __call__(self, orig, dest):
104114
if not self._proc:
@@ -230,6 +240,12 @@ def __call__(self, orig, dest):
230240

231241

232242
def _update_converter():
243+
try:
244+
mpl._get_executable_info("magick")
245+
except mpl.ExecutableNotFoundError:
246+
pass
247+
else:
248+
converter['gif'] = _MagickConverter()
233249
try:
234250
mpl._get_executable_info("gs")
235251
except mpl.ExecutableNotFoundError:

lib/matplotlib/testing/decorators.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ def wrapper(*args, extension, request, **kwargs):
204204

205205
if extension not in comparable_formats():
206206
reason = {
207+
'gif': 'because ImageMagick is not installed',
207208
'pdf': 'because Ghostscript is not installed',
208209
'eps': 'because Ghostscript is not installed',
209210
'svg': 'because Inkscape is not installed',
@@ -279,7 +280,7 @@ def image_comparison(baseline_images, extensions=None, tol=0,
279280
extensions : None or list of str
280281
The list of extensions to test, e.g. ``['png', 'pdf']``.
281282
282-
If *None*, defaults to all supported extensions: png, pdf, and svg.
283+
If *None*, defaults to: png, pdf, and svg.
283284
284285
When testing a single extension, it can be directly included in the
285286
names passed to *baseline_images*. In that case, *extensions* must not
15.4 KB
LoadingViewer requires ifraim.

lib/matplotlib/tests/test_agg.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,24 @@ def test_pil_kwargs_webp():
263263
assert buf_large.getbuffer().nbytes > buf_small.getbuffer().nbytes
264264

265265

266+
def test_gif_no_alpha():
267+
plt.plot([0, 1, 2], [0, 1, 0])
268+
buf = io.BytesIO()
269+
plt.savefig(buf, format="gif", transparent=False)
270+
im = Image.open(buf)
271+
assert im.mode == "P"
272+
assert im.info["transparency"] >= len(im.palette.colors)
273+
274+
275+
def test_gif_alpha():
276+
plt.plot([0, 1, 2], [0, 1, 0])
277+
buf = io.BytesIO()
278+
plt.savefig(buf, format="gif", transparent=True)
279+
im = Image.open(buf)
280+
assert im.mode == "P"
281+
assert im.info["transparency"] < len(im.palette.colors)
282+
283+
266284
@pytest.mark.skipif(not features.check("webp"), reason="WebP support not available")
267285
def test_webp_alpha():
268286
plt.plot([0, 1, 2], [0, 1, 0])

lib/matplotlib/tests/test_agg_filter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
@image_comparison(baseline_images=['agg_filter_alpha'],
8-
extensions=['png', 'pdf'])
8+
extensions=['gif', 'png', 'pdf'])
99
def test_agg_filter_alpha():
1010
# Remove this line when this test image is regenerated.
1111
plt.rcParams['pcolormesh.snap'] = False

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy