10000 Deprecate JPEG-specific kwargs and rcParams to savefig. · matplotlib/matplotlib@c06dbda · GitHub
[go: up one dir, main page]

Skip to content

Commit c06dbda

Browse files
committed
Deprecate JPEG-specific kwargs and rcParams to savefig.
Saving Matplotlib figures to jpeg is generally not a great idea to start with (even at the default quality of 95 there are visible (faint) artefacts around sharp lines, and at quality=95 the files produced are bigger than the corresponding pngs anyways). We don't need to completely get rid of jpeg support, but we can at least simplify the code path (which otherwise also needs to be duplicated in mplcairo) and not have to document these jpeg-specific kwargs (in two places!). Note that users can still set them via `pil_kwargs`. The changes to _delete_parameter are so that we can write ``` @_delete_parameter(..., "foo") def f(**kwargs): ... ``` where `foo` actually only shows up in `kwargs`.
1 parent 2699c70 commit c06dbda

File tree

8 files changed

+58
-18
lines changed

8 files changed

+58
-18
lines changed

doc/api/next_api_changes/deprecations.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,12 @@ The *clear_temp* parameter and attribute of `.FileMovieWriter` is
211211
deprecated. In the future, files placed in a temporary directory (using
212212
``frame_prefix=None``, the default) will be cleared; files placed elsewhere
213213
will not.
214+
215+
JPEG options
216+
~~~~~~~~~~~~
217+
The *quality*, *optimize*, and *progressive* keyword arguments to
218+
`~.Figure.savefig`, which were only used when saving to JPEG, are deprecated.
219+
:rc:`savefig.jpeg_quality` is likewise deprecated.
220+
221+
Such options should now be directly passed to Pillow using
222+
``savefig(..., pil_kwargs={"quality": ..., "optimize": ..., "progressive": ...})``.

lib/matplotlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ def gen_candidates():
602602
_deprecated_remain_as_none = {
603603
'animation.avconv_path': ('3.3',),
604604
'animation.avconv_args': ('3.3',),
605+
'savefig.jpeg_quality': ('3.3',),
605606
}
606607

607608

lib/matplotlib/backends/backend_agg.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,12 @@ def print_to_buffer(self):
509509
# matches the dpi kwarg (if any).
510510

511511
@cbook._delete_parameter("3.2", "dryrun")
512+
@cbook._delete_parameter("3.3", "quality",
513+
alternative="pil_kwargs={'quality': ...}")
514+
@cbook._delete_parameter("3.3", "optimize",
515+
alternative="pil_kwargs={'optimize': ...}")
516+
@cbook._delete_parameter("3.3", "progressive",
517+
alternative="pil_kwargs={'progressive': ...}")
512518
def print_jpg(self, filename_or_obj, *args, dryrun=False, pil_kwargs=None,
513519
**kwargs):
514520
"""
@@ -525,14 +531,17 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False, pil_kwargs=None,
525531
The image quality, on a scale from 1 (worst) to 95 (best).
526532
Values above 95 should be avoided; 100 disables portions of
527533
the JPEG compression algorithm, and results in large files
528-
with hardly any gain in image quality.
534+
with hardly any gain in image quality. This parameter is
535+
deprecated.
529536
530537
optimize : bool, default: False
531538
Whether the encoder should make an extra pass over the image
532-
in order to select optimal encoder settings.
539+
in order to select optimal encoder settings. This parameter is
540+
deprecated.
533541
534542
progressive : bool, default: False
535543
Whether the image should be stored as a progressive JPEG file.
544+
This parameter is deprecated.
536545
537546
pil_kwargs : dict, optional
538547
Additional keyword arguments that are passed to
@@ -552,7 +561,16 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False, pil_kwargs=None,
552561
for k in ["quality", "optimize", "progressive"]:
553562
if k in kwargs:
554563
pil_kwargs.setdefault(k, kwargs[k])
555-
pil_kwargs.setdefault("quality", rcParams["savefig.jpeg_quality"])
564+
if "quality" not in pil_kwargs:
565+
quality = pil_kwargs["quality"] = \
566+
dict.__getitem__(rcParams, "savefig.jpeg_quality")
567+
if quality not in [0, 75, 95]: # default qualities.
568+
cbook.warn_deprecated(
569+
"3.3", name="savefig.jpeg_quality", obj_type="rcParam",
570+
addendum="Set the quality using "
571+
"`pil_kwargs={'quality': ...}`; the future default "
572+
"quality will be 75, matching the default of Pillow and "
573+
"libjpeg.")
556574
pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi))
557575
return background.save(
558576
filename_or_obj, format='jpeg', **pil_kwargs)

lib/matplotlib/backends/backend_wx.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -898,8 +898,8 @@ def _print_image(self, filename, filetype, *args, **kwargs):
898898
# are saving a JPEG, convert the wx.Bitmap to a wx.Image,
899899
# and set the quality.
900900
if filetype == wx.BITMAP_TYPE_JPEG:
901-
jpeg_quality = kwargs.get('quality',
902-
rcParams['savefig.jpeg_quality'])
901+
jpeg_quality = kwargs.get(
902+
'quality', dict.__getitem__(rcParams, 'savefig.jpeg_quality'))
903903
image = self.bitmap.ConvertToImage()
904904
image.SetOption(wx.IMAGE_OPTION_QUALITY, str(jpeg_quality))
905905

lib/matplotlib/cbook/deprecation.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def __repr__(self):
307307
_deprecated_parameter = _deprecated_parameter_class()
308308

309309

310-
def _delete_parameter(since, name, func=None):
310+
def _delete_parameter(since, name, func=None, **kwargs):
311311
"""
312312
Decorator indicating that parameter *name* of *func* is being deprecated.
313313
@@ -329,10 +329,12 @@ def func(used_arg, other_arg, unused, more_args): ...
329329
"""
330330

331331
if func is None:
332-
return functools.partial(_delete_parameter, since, name)
332+
return functools.partial(_delete_parameter, since, name, **kwargs)
333333

334334
signature = inspect.signature(func)
335-
assert name in signature.parameters, (
335+
kw_name = next((param.name for param in signature.parameters.values()
336+
if param.kind == inspect.Parameter.VAR_KEYWORD), None)
337+
assert name in signature.parameters or kw_name, (
336338
f"Matplotlib internal error: {name!r} must be a parameter for "
337339
f"{func.__name__}()")
338340
func.__signature__ = signature.replace(parameters=[
@@ -341,17 +343,23 @@ def func(used_arg, other_arg, unused, more_args): ...
341343
for param in signature.parameters.values()])
342344

343345
@functools.wraps(func)
344-
def wrapper(*args, **kwargs):
345-
arguments = func.__signature__.bind(*args, **kwargs).arguments
346+
def wrapper(*f_args, **f_kwargs):
347+
arguments = func.__signature__.bind(*f_args, **f_kwargs).arguments
346348
# We cannot just check `name not in arguments` because the pyplot
347349
# wrappers always pass all arguments explicitly.
348-
if name in arguments and arguments[name] != _deprecated_parameter:
350+
if any(name in d and d[name] != _deprecated_parameter
351+
for d in [arguments, arguments.get(kw_name, {})]):
352+
addendum = (
353+
f"If any parameter follows {name!r}, they should be passed as "
354+
f"keyword, not positionally.")
355+
if kwargs.get("addendum"):
356+
kwargs["addendum"] += " " + addendum
357+
else:
358+
kwargs["addendum"] = addendum
349359
warn_deprecated(
350-
since, message=f"The {name!r} parameter of {func.__name__}() "
351-
f"is deprecated since Matplotlib {since} and will be removed "
352-
f"%(removal)s. If any parameter follows {name!r}, they "
353-
f"should be pass as keyword, not positionally.")
354-
return func(*args, **kwargs)
360+
since, name=name, obj_type=f"parameter of {func.__name__}()",
361+
**kwargs)
362+
return func(*f_args, **f_kwargs)
355363

356364
return wrapper
357365

lib/matplotlib/figure.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,17 +2074,23 @@ def savefig(self, fname, *, transparent=None, **kwargs):
20742074
the JPEG compression algorithm, and results in large files
20752075
with hardly any gain in image quality.
20762076
2077+
This parameter is deprecated.
2078+
20772079
optimize : bool, default: False
20782080
Applicable only if *format* is 'jpg' or 'jpeg', ignored otherwise.
20792081
20802082
Whether the encoder should make an extra pass over the image
20812083
in order to select optimal encoder settings.
20822084
2085+
This parameter is deprecated.
2086+
20832087
progressive : bool, default: False
20842088
Applicable only if *format* is 'jpg' or 'jpeg', ignored otherwise.
20852089
20862090
Whether the image should be stored as a progressive JPEG file.
20872091
2092+
This parameter is deprecated.
2093+
20882094
facecolor : color, default: :rc:`savefig.facecolor`
20892095
The facecolor of the figure.
20902096

lib/matplotlib/mpl-data/stylelib/classic.mplstyle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,6 @@ savefig.bbox : standard # 'tight' or 'standard'.
419419
# e.g. setting animation.writer to ffmpeg will not work,
420420
# use ffmpeg_file instead
421421
savefig.pad_inches : 0.1 # Padding to be used when bbox is set to 'tight'
422-
savefig.jpeg_quality: 95 # when a jpeg is saved, the default quality parameter.
423422
savefig.transparent : False # setting that controls whether figures are saved with a
424423
# transparent background by default
425424
savefig.orientation : portrait

matplotlibrc.template

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,6 @@
649649
# e.g. setting animation.writer to ffmpeg will not work,
650650
# use ffmpeg_file instead
651651
#savefig.pad_inches: 0.1 # Padding to be used when bbox is set to 'tight'
652-
#savefig.jpeg_quality: 95 # when a jpeg is saved, the default quality parameter.
653652
#savefig.directory: ~ # default directory in savefig dialog box,
654653
# leave empty to always use current working directory
3B11 655654
#savefig.transparent: False # setting that controls whether figures are saved with a

0 commit comments

Comments
 (0)
0