From b20fd2fa170c95ed3f872997556284c07c084b80 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 16 Dec 2017 01:14:57 -0800 Subject: [PATCH] Deprecate savefig.facecolor, savefig.edgecolor, and savefig.transparent. They cause a number of complications for print_figure (which needs to temporarily switch the figure and axes face and edge colors) that are unnecessary (the user can directly set the color they wish (including transparent) on the figure patch instead; an rcParam is even available for that purpose). --- doc/api/api_changes/2017-12-16-AL.rst | 12 +++++++ lib/matplotlib/__init__.py | 36 +++++++++++++------ lib/matplotlib/backend_bases.py | 16 +++++---- lib/matplotlib/backends/backend_agg.py | 7 ++-- .../backends/web_backend/nbagg_uat.ipynb | 6 ++-- lib/matplotlib/figure.py | 36 +++++++++---------- .../mpl-data/stylelib/_classic_test.mplstyle | 7 +--- .../mpl-data/stylelib/classic.mplstyle | 4 --- .../stylelib/dark_background.mplstyle | 4 --- .../stylelib/fivethirtyeight.mplstyle | 3 -- .../mpl-data/stylelib/grayscale.mplstyle | 4 --- lib/matplotlib/tests/test_image.py | 22 +++++------- matplotlibrc.template | 4 --- tutorials/intermediate/tight_layout_guide.py | 2 +- 14 files changed, 80 insertions(+), 83 deletions(-) create mode 100644 doc/api/api_changes/2017-12-16-AL.rst diff --git a/doc/api/api_changes/2017-12-16-AL.rst b/doc/api/api_changes/2017-12-16-AL.rst new file mode 100644 index 000000000000..21d0b65549d4 --- /dev/null +++ b/doc/api/api_changes/2017-12-16-AL.rst @@ -0,0 +1,12 @@ +Deprecation of savefig-time modification of the figure patch face and edge colors +````````````````````````````````````````````````````````````````````````````````` + +The ``facecolor``, ``edgecolor``, and ``transparent`` keyword arguments to +`~.Figure.savefig` and `~.FigureCanvasBase.print_figure`, and the associated +``savefig.facecolor``, ``savefig.edgecolor``, and ``savefig.transparent`` +rcParams, have been deprecated. As a replacement for the first two +options, directly set the facecolor and edgecolor of the figure patch +(``figure.patch``), or set the ``figure.facecolor`` and ``figure.edgecolor`` +rcParams. As a replacement for ``transparent``, set both the figure +patch color and the axes patch color to transparent, or likewise set the +corresponding rcParams. diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 9f777dedcf7e..d73bb7ee01f5 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -848,7 +848,13 @@ def gen_candidates(): _obsolete_set = {'plugins.directory', 'text.dvipnghack'} # The following may use a value of None to suppress the warning. -_deprecated_set = {'axes.hold'} # do NOT include in _all_deprecated +# Do NOT include in _all_deprecated. +_deprecated_set = { + 'axes.hold', + 'savefig.facecolor', + 'savefig.edgecolor', + 'savefig.transparent', +} _all_deprecated = set(itertools.chain( _deprecated_ignore_map, _deprecated_map, _obsolete_set)) @@ -977,9 +983,11 @@ def rc_params(fail_on_error=False): if not os.path.exists(fname): # this should never happen, default in mpl-data should always be found message = 'could not find rc file; returning defaults' - ret = RcParams([(key, default) for key, (default, _) in - six.iteritems(defaultParams) - if key not in _all_deprecated]) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=mplDeprecation) + ret = RcParams([(key, default) for key, (default, _) in + six.iteritems(defaultParams) + if key not in _all_deprecated]) warnings.warn(message) return ret @@ -1116,9 +1124,11 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): return config_from_file iter_params = six.iteritems(defaultParams) - config = RcParams([(key, default) for key, (default, _) in iter_params - if key not in _all_deprecated]) - config.update(config_from_file) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=mplDeprecation) + config = RcParams([(key, default) for key, (default, _) in iter_params + if key not in _all_deprecated]) + config.update(config_from_file) if config['datapath'] is None: config['datapath'] = get_data_path() @@ -1155,9 +1165,11 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): rcParamsOrig = rcParams.copy() -rcParamsDefault = RcParams([(key, default) for key, (default, converter) in - six.iteritems(defaultParams) - if key not in _all_deprecated]) +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=mplDeprecation) + rcParamsDefault = RcParams([(key, default) for key, (default, converter) in + six.iteritems(defaultParams) + if key not in _all_deprecated]) rcParams['ps.usedistiller'] = checkdep_ps_distiller( rcParams['ps.usedistiller']) @@ -1253,7 +1265,9 @@ def rcdefaults(): the default style. """ rcParams.clear() - rcParams.update(rcParamsDefault) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=mplDeprecation) + rcParams.update(rcParamsDefault) def rc_file_defaults(): diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 9909634b89e2..8a4c3b53a60a 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2125,12 +2125,6 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None, dpi : scalar, optional the dots per inch to save the figure in; if None, use savefig.dpi - facecolor : color spec or None, optional - the facecolor of the figure; if None, defaults to savefig.facecolor - - edgecolor : color spec or None, optional - the edgecolor of the figure; if None, defaults to savefig.edgecolor - format : str, optional when set, forcibly set the file format to save to @@ -2172,8 +2166,18 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None, if facecolor is None: facecolor = rcParams['savefig.facecolor'] + else: + cbook.warn_deprecated( + "2.2", + "The 'facecolor' kwarg is deprecated; set the figure's " + "facecolor ('figure.patch.facecolor') instead") if edgecolor is None: edgecolor = rcParams['savefig.edgecolor'] + else: + cbook.warn_deprecated( + "2.2", + "The 'edgecolor' kwarg is deprecated; set the figure's " + "edgecolor ('figure.patch.edgecolor') instead") origDPI = self.figure.dpi origfacecolor = self.figure.get_facecolor() diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 16ffdbbf8aac..e7c5634aafc5 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -562,12 +562,9 @@ def print_jpg(self, filename_or_obj, *args, **kwargs): buf, size = self.print_to_buffer() if kwargs.pop("dryrun", False): return - # The image is "pasted" onto a white background image to safely - # handle any transparency + # Paste image onto a white background to handle transparency. image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) - rgba = mcolors.to_rgba(rcParams['savefig.facecolor']) - color = tuple([int(x * 255.0) for x in rgba[:3]]) - background = Image.new('RGB', size, color) + background = Image.new('RGB', size, (255, 255, 255)) background.paste(image, image) options = {k: kwargs[k] for k in ['quality', 'optimize', 'progressive', 'dpi'] diff --git a/lib/matplotlib/backends/web_backend/nbagg_uat.ipynb b/lib/matplotlib/backends/web_backend/nbagg_uat.ipynb index 83e8235d187b..aa6b582fe3a1 100644 --- a/lib/matplotlib/backends/web_backend/nbagg_uat.ipynb +++ b/lib/matplotlib/backends/web_backend/nbagg_uat.ipynb @@ -399,8 +399,7 @@ "\n", "### UAT 15 - Figure face colours\n", "\n", - "The nbagg honours all colours appart from that of the figure.patch. The two plots below should produce a figure with a red background. There should be no yellow figure." - ] + "The nbagg honours all colours appart from that of the figure.patch. The two plots below should produce a figure with a red background." }, { "cell_type": "code", @@ -411,8 +410,7 @@ "outputs": [], "source": [ "import matplotlib\n", - "matplotlib.rcParams.update({'figure.facecolor': 'red',\n", - " 'savefig.facecolor': 'yellow'})\n", + "matplotlib.rcParams.update({'figure.facecolor': 'red'})\n", "plt.figure()\n", "plt.plot([3, 2, 1])\n", "\n", diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index b56c67b3c054..c95e2b025395 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1811,12 +1811,6 @@ def savefig(self, fname, **kwargs): the value ``savefig.dpi`` in the matplotlibrc file. If 'figure' it will set the dpi to be the value of the figure. - facecolor : color spec or None, optional - the facecolor of the figure; if None, defaults to savefig.facecolor - - edgecolor : color spec or None, optional - the edgecolor of the figure; if None, defaults to savefig.edgecolor - orientation : {'landscape', 'portrait'} not supported on all backends; currently only on postscript output @@ -1829,15 +1823,6 @@ def savefig(self, fname, **kwargs): One of the file extensions supported by the active backend. Most backends support png, pdf, ps, eps and svg. - transparent : bool - If *True*, the axes patches will all be transparent; the - figure patch will also be transparent unless facecolor - and/or edgecolor are specified via kwargs. - This is useful, for example, for displaying - a plot on top of a colored background on a web page. The - transparency of these patches will be restored to their - original values upon exit of this function. - frameon : bool If *True*, the figure patch will be colored, if *False*, the figure background will be transparent. If not provided, the @@ -1859,6 +1844,24 @@ def savefig(self, fname, **kwargs): """ kwargs.setdefault('dpi', rcParams['savefig.dpi']) frameon = kwargs.pop('frameon', rcParams['savefig.frameon']) + + if "transparent" in kwargs: + cbook.warn_deprecated( + "2.2", + "The 'transparent' kwarg is deprecated; set the figure's and " + "axes' facecolor ('figure.patch.facecolor', 'axes.patch." + "facecolor') to fully transparent ('none') instead") + if "facecolor" in kwargs: + cbook.warn_deprecated( + "2.2", + "The 'facecolor' kwarg is deprecated; set the figure's " + "facecolor ('figure.patch.facecolor') instead") + if "edgecolor" in kwargs: + cbook.warn_deprecated( + "2.2", + "The 'edgecolor' kwarg is deprecated; set the figure's " + "edgecolor ('figure.patch.edgecolor') instead") + transparent = kwargs.pop('transparent', rcParams['savefig.transparent']) @@ -1872,9 +1875,6 @@ def savefig(self, fname, **kwargs): patch.get_edgecolor())) patch.set_facecolor('none') patch.set_edgecolor('none') - else: - kwargs.setdefault('facecolor', rcParams['savefig.facecolor']) - kwargs.setdefault('edgecolor', rcParams['savefig.edgecolor']) if frameon: original_frameon = self.get_frameon() diff --git a/lib/matplotlib/mpl-data/stylelib/_classic_test.mplstyle b/lib/matplotlib/mpl-data/stylelib/_classic_test.mplstyle index 70071b47b41e..bad3c778fe2d 100644 --- a/lib/matplotlib/mpl-data/stylelib/_classic_test.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/_classic_test.mplstyle @@ -294,14 +294,13 @@ legend.facecolor : inherit # legend background color (when 'inherit' uses legend.edgecolor : inherit # legend edge color (when 'inherit' uses axes.edgecolor) - ### FIGURE # See http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure figure.titlesize : medium # size of the figure title figure.titleweight : normal # weight of the figure title figure.figsize : 8, 6 # figure size in inches figure.dpi : 80 # figure dots per inch -figure.facecolor : 0.75 # figure facecolor; 0.75 is scalar gray +figure.facecolor : w # figure facecolor figure.edgecolor : w # figure edgecolor figure.autolayout : False # When True, automatically adjust subplot # parameters to make the plot fit the figure @@ -408,8 +407,6 @@ path.sketch : None # May be none, or a 3-tuple of the form (scale, length, # e.g., you may want a higher resolution, or to make the figure # background white savefig.dpi : 100 # figure dots per inch -savefig.facecolor : w # figure facecolor when saving -savefig.edgecolor : w # figure edgecolor when saving savefig.format : png # png, ps, pdf, svg savefig.bbox : standard # 'tight' or 'standard'. # 'tight' is incompatible with pipe-based animation @@ -418,8 +415,6 @@ savefig.bbox : standard # 'tight' or 'standard'. # use ffmpeg_file instead savefig.pad_inches : 0.1 # Padding to be used when bbox is set to 'tight' savefig.jpeg_quality: 95 # when a jpeg is saved, the default quality parameter. -savefig.transparent : False # setting that controls whether figures are saved with a - # transparent background by default savefig.frameon : True savefig.orientation : portrait diff --git a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle index 493cc15d7f28..ba9dae72d097 100644 --- a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle @@ -410,8 +410,6 @@ path.sketch : None # May be none, or a 3-tuple of the form (scale, length, # e.g., you may want a higher resolution, or to make the figure # background white savefig.dpi : 100 # figure dots per inch -savefig.facecolor : w # figure facecolor when saving -savefig.edgecolor : w # figure edgecolor when saving savefig.format : png # png, ps, pdf, svg savefig.bbox : standard # 'tight' or 'standard'. # 'tight' is incompatible with pipe-based animation @@ -420,8 +418,6 @@ savefig.bbox : standard # 'tight' or 'standard'. # use ffmpeg_file instead savefig.pad_inches : 0.1 # Padding to be used when bbox is set to 'tight' savefig.jpeg_quality: 95 # when a jpeg is saved, the default quality parameter. -savefig.transparent : False # setting that controls whether figures are saved with a - # transparent background by default savefig.frameon : True savefig.orientation : portrait diff --git a/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle b/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle index a8b754005bfd..6ab5a28b8b2c 100644 --- a/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle @@ -17,7 +17,3 @@ grid.color: white figure.facecolor: black figure.edgecolor: black - -savefig.facecolor: black -savefig.edgecolor: black - diff --git a/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle b/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle index 738db39f5f80..00df066544b8 100644 --- a/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle @@ -31,9 +31,6 @@ ytick.minor.size: 0 font.size:14.0 -savefig.edgecolor: f0f0f0 -savefig.facecolor: f0f0f0 - figure.subplot.left: 0.08 figure.subplot.right: 0.95 figure.subplot.bottom: 0.07 diff --git a/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle b/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle index 6a1114e40698..d65ddccfee07 100644 --- a/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle @@ -23,7 +23,3 @@ figure.facecolor: 0.75 figure.edgecolor: white image.cmap: gray - -savefig.facecolor: white -savefig.edgecolor: white - diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index ca3443a78445..4ab9b20b69df 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -523,20 +523,16 @@ def test_jpeg_alpha(): plt.figimage(im) - buff = io.BytesIO() - with rc_context({'savefig.facecolor': 'red'}): - plt.savefig(buff, transparent=True, format='jpg', dpi=300) + buf = io.BytesIO() + plt.savefig(buf, transparent=True, format='jpg', dpi=300) + buf.seek(0) + image = Image.open(buf) - buff.seek(0) - image = Image.open(buff) - - # If this fails, there will be only one color (all black). If this - # is working, we should have all 256 shades of grey represented. - num_colors = len(image.getcolors(256)) - assert 175 <= num_colors <= 185 - # The fully transparent part should be red. - corner_pixel = image.getpixel((0, 0)) - assert corner_pixel == (254, 0, 0) + # If this fails, there will be only one color (all black). If this is + # working, we should have all 256 shades of grey represented. + assert len(image.getcolors(256)) == 256 + # The fully transparent part should be white. + assert image.getpixel((0, 0)) == (255, 255, 255) def test_nonuniformimage_setdata(): diff --git a/matplotlibrc.template b/matplotlibrc.template index 7ac32f71cf8d..e1518d1d23a6 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -507,8 +507,6 @@ backend : $TEMPLATE_BACKEND # e.g., you may want a higher resolution, or to make the figure # background white #savefig.dpi : figure # figure dots per inch or 'figure' -#savefig.facecolor : white # figure facecolor when saving -#savefig.edgecolor : white # figure edgecolor when saving #savefig.format : png # png, ps, pdf, svg #savefig.bbox : standard # 'tight' or 'standard'. # 'tight' is incompatible with pipe-based animation @@ -519,8 +517,6 @@ backend : $TEMPLATE_BACKEND #savefig.jpeg_quality: 95 # when a jpeg is saved, the default quality parameter. #savefig.directory : ~ # default directory in savefig dialog box, # leave empty to always use current working directory -#savefig.transparent : False # setting that controls whether figures are saved with a - # transparent background by default # tk backend params #tk.window_focus : False # Maintain shell focus for TkAgg diff --git a/tutorials/intermediate/tight_layout_guide.py b/tutorials/intermediate/tight_layout_guide.py index b3cbb0861113..f938d2a16c90 100644 --- a/tutorials/intermediate/tight_layout_guide.py +++ b/tutorials/intermediate/tight_layout_guide.py @@ -24,7 +24,7 @@ import matplotlib.pyplot as plt import numpy as np -plt.rcParams['savefig.facecolor'] = "0.8" +plt.rcParams['figure.facecolor'] = "0.8" def example_plot(ax, fontsize=12):