Skip to content

Commit 7f9dea1

Browse files
committed
By default, don't change the figure face/edgecolor on savefig().
This seems to repeatedly confuse users.
1 parent 79b6106 commit 7f9dea1

File tree

8 files changed

+68
-67
lines changed

8 files changed

+68
-67
lines changed
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
:rc:`savefig.facecolor` and :rc:`savefig.edgecolor` now default to "auto"
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
This newly allowed value for :rc:`savefig.facecolor` and :rc:`savefig.edgecolor`,
5+
as well as the *facecolor* and *edgecolor* parameters to `.Figure.savefig`, means
6+
"use whatever facecolor and edgecolor the figure current has".
7+
8+
`.FigureCanvasPS.print_ps` and `.FigureCanvasPS.print_eps` no longer set the figure *facecolor* and *edgecolor*
9+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10+
11+
Modification of the figure facecolor and edgecolor are already handled by
12+
`.FigureCanvasBase.print_figure` (which is in charge of calling `.print_ps` or
13+
`.print_eps`). This behavior is consistent with the other backend printing
14+
methods (`.FigureCanvasPdf.print_pdf`, `.FigureCanvasSVG.print_svg`, etc.)

lib/matplotlib/backend_bases.py

+34-31
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
The base class for the messaging area.
3333
"""
3434

35-
from contextlib import contextmanager
35+
from contextlib import contextmanager, ExitStack
3636
from enum import IntEnum
3737
import functools
3838
import importlib
@@ -2001,32 +2001,35 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
20012001
can also be a file object on image backends
20022002
20032003
orientation : {'landscape', 'portrait'}, optional
2004-
only currently applies to PostScript printing.
2004+
Only currently applies to PostScript printing.
20052005
20062006
dpi : scalar, optional
2007-
the dots per inch to save the figure in; if None, use savefig.dpi
2007+
The dots per inch to save the figure in; if None, use
2008+
:rc:`savefig.dpi`.
20082009
2009-
facecolor : color or None, optional
2010-
the facecolor of the figure; if None, defaults to savefig.facecolor
2010+
facecolor : color or 'auto' or None, optional
2011+
The facecolor of the figure. If 'auto', use the current figure
2012+
facecolor. If None, use :rc:`savefig.facecolor`.
20112013
2012-
edgecolor : color or None, optional
2013-
the edgecolor of the figure; if None, defaults to savefig.edgecolor
2014+
edgecolor : color or 'auto' or None, optional
2015+
The edgecolor of the figure. If 'auto', use the current figure
2016+
edgecolor. If None, use :rc:`savefig.edgecolor`.
20142017
20152018
format : str, optional
2016-
when set, forcibly set the file format to save to
2019+
When set, forcibly set the file format to save to.
20172020
20182021
bbox_inches : str or `~matplotlib.transforms.Bbox`, optional
2019-
Bbox in inches. Only the given portion of the figure is
2020-
saved. If 'tight', try to figure out the tight bbox of
2021-
the figure. If None, use savefig.bbox
2022+
Bbox in inches. Only the given portion of the figure is saved. If
2023+
'tight', try to figure out the tight bbox of the figure. If None,
2024+
use :rc:`savefig.bbox`.
20222025
20232026
pad_inches : scalar, optional
2024-
Amount of padding around the figure when bbox_inches is
2025-
'tight'. If None, use savefig.pad_inches
2027+
Amount of padding around the figure when bbox_inches is 'tight'. If
2028+
None, use :rc:`savefig.pad_inches`.
20262029
20272030
bbox_extra_artists : list of `~matplotlib.artist.Artist`, optional
2028-
A list of extra artists that will be considered when the
2029-
tight bbox is calculated.
2031+
A list of extra artists that will be considered when the tight bbox
2032+
is calculated.
20302033
20312034
"""
20322035
if format is None:
@@ -2050,27 +2053,29 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
20502053
if dpi == 'figure':
20512054
dpi = getattr(self.figure, '_original_dpi', self.figure.dpi)
20522055

2053-
# Remove the figure manager, if any, to avoid resizing the GUI widget.
2054-
# Some code (e.g. Figure.show) differentiates between having *no*
2055-
# manager and a *None* manager, which should be fixed at some point,
2056-
# but this should be fine.
2057-
with cbook._setattr_cm(self, _is_saving=True, manager=None), \
2058-
cbook._setattr_cm(self.figure, dpi=dpi):
2059-
2056+
with ExitStack() as stack:
2057+
# Remove the figure manager, if any, to avoid resizing the GUI
2058+
# widget. Some code (e.g. Figure.show) differentiates between
2059+
# having *no* manager and a *None* manager, which should be fixed
2060+
# at some point, but this should be fine.
2061+
stack.enter_context(
2062+
cbook._setattr_cm(self, _is_saving=True, manager=None))
2063+
stack.enter_context(cbook._setattr_cm(self.figure, dpi=dpi))
20602064
if facecolor is None:
20612065
facecolor = rcParams['savefig.facecolor']
2066+
if not cbook._str_equal(facecolor, 'auto'):
2067+
stack.callback(
2068+
self.figure.set_facecolor, self.figure.get_facecolor())
2069+
self.figure.set_facecolor(facecolor)
20622070
if edgecolor is None:
20632071
edgecolor = rcParams['savefig.edgecolor']
2064-
2065-
origfacecolor = self.figure.get_facecolor()
2066-
origedgecolor = self.figure.get_edgecolor()
2067-
2068-
self.figure.set_facecolor(facecolor)
2069-
self.figure.set_edgecolor(edgecolor)
2072+
if not cbook._str_equal(edgecolor, 'auto'):
2073+
stack.callback(
2074+
self.figure.set_edgecolor, self.figure.get_edgecolor())
2075+
self.figure.set_edgecolor(edgecolor)
20702076

20712077
if bbox_inches is None:
20722078
bbox_inches = rcParams['savefig.bbox']
2073-
20742079
if bbox_inches:
20752080
if bbox_inches == "tight":
20762081
renderer = _get_renderer(
@@ -2108,8 +2113,6 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21082113
if bbox_inches and restore_bbox:
21092114
restore_bbox()
21102115

2111-
self.figure.set_facecolor(origfacecolor)
2112-
self.figure.set_edgecolor(origedgecolor)
21132116
self.figure.set_canvas(self)
21142117
return result
21152118

lib/matplotlib/backends/backend_agg.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,10 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False,
587587
# The image is "pasted" onto a white background image to safely
588588
# handle any transparency
589589
image = Image.fromarray(np.asarray(self.buffer_rgba()))
590-
rgba = mcolors.to_rgba(rcParams['savefig.facecolor'])
591-
color = tuple([int(x * 255) for x in rgba[:3]])
590+
facecolor = rcParams["savefig.facecolor"]
591+
if cbook._str_equal(facecolor, "auto"):
592+
facecolor = self.figure.get_facecolor()
593+
color = tuple(int(x * 255) for x in mcolors.to_rgb(facecolor))
592594
background = Image.new('RGB', image.size, color)
593595
background.paste(image, image)
594596
if pil_kwargs is None:

lib/matplotlib/backends/backend_ps.py

-16
Original file line numberDiff line numberDiff line change
@@ -921,11 +921,6 @@ def _print_figure(
921921
bbox = (llx, lly, urx, ury)
922922

923923
# generate PostScript code for the figure and store it in a string
924-
origfacecolor = self.figure.get_facecolor()
925-
origedgecolor = self.figure.get_edgecolor()
926-
self.figure.set_facecolor(facecolor)
927-
self.figure.set_edgecolor(edgecolor)
928-
929924
if dryrun:
930925
class NullWriter:
931926
def write(self, *args, **kwargs):
@@ -946,9 +941,6 @@ def write(self, *args, **kwargs):
946941
if dryrun: # return immediately if dryrun (tightbbox=True)
947942
return
948943

949-
self.figure.set_facecolor(origfacecolor)
950-
self.figure.set_edgecolor(origedgecolor)
951-
952944
# check for custom metadata
953945
if metadata is not None and 'Creator' in metadata:
954946
creator_str = metadata['Creator']
@@ -1117,11 +1109,6 @@ def _print_figure_tex(
11171109
bbox = (llx, lly, urx, ury)
11181110

11191111
# generate PostScript code for the figure and store it in a string
1120-
origfacecolor = self.figure.get_facecolor()
1121-
origedgecolor = self.figure.get_edgecolor()
1122-
self.figure.set_facecolor(facecolor)
1123-
self.figure.set_edgecolor(edgecolor)
1124-
11251112
if dryrun:
11261113
class NullWriter:
11271114
def write(self, *args, **kwargs):
@@ -1142,9 +1129,6 @@ def write(self, *args, **kwargs):
11421129
if dryrun: # return immediately if dryrun (tightbbox=True)
11431130
return
11441131

1145-
self.figure.set_facecolor(origfacecolor)
1146-
self.figure.set_edgecolor(origedgecolor)
1147-
11481132
# check for custom metadata
11491133
if metadata is not None and 'Creator' in metadata:
11501134
creator_str = metadata['Creator']

lib/matplotlib/figure.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -2116,13 +2116,13 @@ def savefig(self, fname, *, transparent=None, **kwargs):
21162116
progressive JPEG file. Applicable only if *format* is jpg or
21172117
jpeg, ignored otherwise. Is *False* by default.
21182118
2119-
facecolor : color or None, optional
2120-
The facecolor of the figure; if *None*, defaults to
2121-
:rc:`savefig.facecolor`.
2119+
facecolor : color or 'auto' or None, optional
2120+
The facecolor of the figure. If 'auto', use the current figure
2121+
facecolor. If None, use :rc:`savefig.facecolor`.
21222122
2123-
edgecolor : color or None, optional
2124-
The edgecolor of the figure; if *None*, defaults to
2125-
:rc:`savefig.edgecolor`
2123+
edgecolor : color or 'auto' or None, optional
2124+
The edgecolor of the figure. If 'auto', use the current figure
2125+
edgecolor. If None, use :rc:`savefig.edgecolor`.
21262126
21272127
orientation : {'landscape', 'portrait'}
21282128
Currently only supported by the postscript backend.
@@ -2197,9 +2197,6 @@ def savefig(self, fname, *, transparent=None, **kwargs):
21972197
patch.get_edgecolor()))
21982198
patch.set_facecolor('none')
21992199
patch.set_edgecolor('none')
2200-
else:
2201-
kwargs.setdefault('facecolor', rcParams['savefig.facecolor'])
2202-
kwargs.setdefault('edgecolor', rcParams['savefig.edgecolor'])
22032200

22042201
if frameon:
22052202
original_frameon = self.patch.get_visible()

lib/matplotlib/image.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1525,9 +1525,10 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
15251525
pil_kwargs["pnginfo"] = pnginfo
15261526
if format in ["jpg", "jpeg"]:
15271527
format = "jpeg" # Pillow doesn't recognize "jpg".
1528-
color = tuple(
1529-
int(x * 255)
1530-
for x in mcolors.to_rgb(rcParams["savefig.facecolor"]))
1528+
facecolor = rcParams["savefig.facecolor"]
1529+
if cbook._str_equal(facecolor, "auto"):
1530+
facecolor = rcParams["figure.facecolor"]
1531+
color = tuple(int(x * 255) for x in mcolors.to_rgb(facecolor))
15311532
background = Image.new("RGB", pil_shape, color)
15321533
background.paste(image, image)
15331534
image = background

lib/matplotlib/rcsetup.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,13 @@ def validator(s):
297297

298298
def validate_color_or_inherit(s):
299299
"""Return a valid color arg."""
300-
if s == 'inherit':
300+
if cbook._str_equal(s, 'inherit'):
301301
return s
302302
return validate_color(s)
303303

304304

305305
def validate_color_or_auto(s):
306-
if s == 'auto':
306+
if cbook._str_equal(s, 'auto'):
307307
return s
308308
return validate_color(s)
309309

@@ -1326,8 +1326,8 @@ def _validate_linestyle(ls):
13261326

13271327
## Saving figure's properties
13281328
'savefig.dpi': ['figure', validate_dpi], # DPI
1329-
'savefig.facecolor': ['white', validate_color],
1330-
'savefig.edgecolor': ['white', validate_color],
1329+
'savefig.facecolor': ['auto', validate_color_or_auto],
1330+
'savefig.edgecolor': ['auto', validate_color_or_auto],
13311331
'savefig.frameon': [True, validate_bool],
13321332
'savefig.orientation': ['portrait', validate_orientation],
13331333
'savefig.jpeg_quality': [95, validate_int],

matplotlibrc.template

+2-2
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,8 @@
642642
## e.g., you may want a higher resolution, or to make the figure
643643
## background white
644644
#savefig.dpi : figure ## figure dots per inch or 'figure'
645-
#savefig.facecolor : white ## figure facecolor when saving
646-
#savefig.edgecolor : white ## figure edgecolor when saving
645+
#savefig.facecolor : auto ## figure facecolor when saving
646+
#savefig.edgecolor : auto ## figure edgecolor when saving
647647
#savefig.format : png ## {png, ps, pdf, svg}
648648
#savefig.bbox : standard ## {tight, standard}
649649
## 'tight' is incompatible with pipe-based animation

0 commit comments

Comments
 (0)