8000 Group figure.subplot.* rc to a single rcParam. · matplotlib/matplotlib@8ce5600 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8ce5600

Browse files
committed
Group figure.subplot.* rc to a single rcParam.
The idea is to make it easier to restore a figure's subplotparams to the rc-provided defaults. Specifically, this can now be done with fig.subplots_adjust(**rcParams["figure.subplot"]) or fig.subplots_adjust(**dict(rcParams["figure.subplot"], left=...)) if some values need to be overridden. Also make Figure.clf() restore the subplotsparams to these rc-provided defaults (that is the original motivation for the change). Note that this PR runs into a limitation of the rcParams API: it would be nicer if the validators took the rcParams as parameters (e.g. implicitly by being methods of the RcParams class), so that they can actually depend on another key in the same instance.
1 parent 9ec4b95 commit 8ce5600

File tree

12 files changed

+95
-61
lines changed

12 files changed

+95
-61
lines changed

doc/api/next_api_changes/2018-02-15-AL-deprecations.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,7 @@ The following classes, methods, functions, and attributes are deprecated:
3636
- ``text.Annotation.arrow``,
3737

3838
The following rcParams are deprecated:
39+
40+
- ``figure.subplot.left``, ``figure.subplot.right``, etc (instead, set the
41+
single ``figure.subplot`` rcParam to the appropriate dict value).
3942
- ``pgf.debug`` (the pgf backend relies on logging),

lib/matplotlib/__init__.py

Lines changed: 5 additions & 0 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,11 @@ def __getitem__(self, key):
906906
mplDeprecation)
907907
return None
908908

909+
elif key.startswith('figure.subplot.'):
910+
cbook.warn_deprecated(
911+
"3.0",
912+
"{} is deprecated; use figure.subplot instead".format(key))
913+
909914
val = dict.__getitem__(self, key)
910915
if inverse_alt is not None:
911916
return inverse_alt(val)

lib/matplotlib/cbook/deprecation.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def _generate_deprecation_message(
4848

4949
def warn_deprecated(
5050
since, message='', name='', alternative='', pending=False,
51-
obj_type='attribute', addendum='', *, removal=''):
51+
obj_type='attribute', addendum='', *, removal='', stacklevel=2):
5252
"""
5353
Used to display deprecation warning in a standard way.
5454
@@ -88,6 +88,9 @@ def warn_deprecated(
8888
addendum : str, optional
8989
Additional text appended directly to the final message.
9090
91+
stacklevel : int, optional
92+
The stack level used by the `warnings.warn` call.
93+
9194
Examples
9295
--------
9396
@@ -100,7 +103,7 @@ def warn_deprecated(
100103
"""
101104
message = _generate_deprecation_message(
102105
since, message, name, alternative, pending, obj_type, removal=removal)
103-
warnings.warn(message, mplDeprecation, stacklevel=2)
106+
warnings.warn(message, mplDeprecation, stacklevel=stacklevel)
104107

105108

106109
def deprecated(since, message='', name='', alternative='', pending=False,

lib/matplotlib/figure.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -228,20 +228,18 @@ def reset():
228228
self.hspace = thishspace
229229

230230
if self.validate:
231-
if self.left >= self.right:
231+
if not self.left < self.right:
232232
reset()
233-
raise ValueError('left cannot be >= right')
234-
235-
if self.bottom >= self.top:
233+
raise ValueError('One must have right < left')
234+
if not self.bottom < self.top:
236235
reset()
237-
raise ValueError('bottom cannot be >= top')
236+
raise ValueError('One must have bottom < top')
238237

239238
def _update_this(self, s, val):
240239
if val is None:
241240
val = getattr(self, s, None)
242241
if val is None:
243-
key = 'figure.subplot.' + s
244-
val = rcParams[key]
242+
val = rcParams['figure.subplot'][s]
245243

246244
setattr(self, s, val)
247245

@@ -1406,8 +1404,11 @@ def clf(self, keep_observers=False):
14061404
"""
14071405
Clear the figure.
14081406
1409-
Set *keep_observers* to True if, for example,
1410-
a gui widget is tracking the axes in the figure.
1407+
Parameters
1408+
----------
1409+
keep_observers : bool, optional
1410+
Set *keep_observers* to True if, for example,
1411+
a gui widget is tracking the axes in the figure.
14111412
"""
14121413
self.suppressComposite = None
14131414
self.callbacks = cbook.CallbackRegistry()
@@ -1429,6 +1430,7 @@ def clf(self, keep_observers=False):
14291430
if not keep_observers:
14301431
self._axobservers = []
14311432
self._suptitle = None
1433+
self.subplotpars.update(**rcParams['figure.subplot'])
14321434
if self.get_constrained_layout():
14331435
layoutbox.nonetree(self._layoutbox)
14341436
self.stale = True

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -307,16 +307,8 @@ figure.autolayout : False # When True, automatically adjust subplot
307307
# parameters to make the plot fit the figure
308308
figure.frameon : True
309309

310-
# The figure subplot parameters. All dimensions are a fraction of the
311-
# figure width or height
312-
figure.subplot.left : 0.125 # the left side of the subplots of the figure
313-
figure.subplot.right : 0.9 # the right side of the subplots of the figure
314-
figure.subplot.bottom : 0.1 # the bottom of the subplots of the figure
315-
figure.subplot.top : 0.9 # the top of the subplots of the figure
316-
figure.subplot.wspace : 0.2 # the amount of width reserved for space between subplots,
317-
# expressed as a fraction of the average axis width
318-
figure.subplot.hspace : 0.2 # the amount of height reserved for space between subplots,
319-
# expressed as a fraction of the average axis height
310+
# The figure subplot parameters (see matplotlib.figure.SubplotParams).
311+
figure.subplot : {"left": 0.125, "right": 0.9, "bottom": 0.1, "top": 0.9, "wspace": 0.2, "hspace": 0.2}
320312

321313
### IMAGES
322314
image.aspect : equal # equal | auto | a number

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -311,16 +311,8 @@ figure.autolayout : False # When True, automatically adjust subplot
311311
# parameters to make the plot fit the figure
312312
figure.frameon : True
313313

314-
# The figure subplot parameters. All dimensions are a fraction of the
315-
# figure width or height
316-
figure.subplot.left : 0.125 # the left side of the subplots of the figure
317-
figure.subplot.right : 0.9 # the right side of the subplots of the figure
318-
figure.subplot.bottom : 0.1 # the bottom of the subplots of the figure
319-
figure.subplot.top : 0.9 # the top of the subplots of the figure
320-
figure.subplot.wspace : 0.2 # the amount of width reserved for space between subplots,
321-
# expressed as a fraction of the average axis width
322-
figure.subplot.hspace : 0.2 # the amount of height reserved for space between subplots,
323-
# expressed as a fraction of the average axis height
314+
# The figure subplot parameters (see matplotlib.figure.SubplotParams).
315+
figure.subplot : {"left": 0.125, "right": 0.9, "bottom": 0.1, "top": 0.9, "wspace": 0.2, "hspace": 0.2}
324316

325317
### IMAGES
326318
image.aspect : equal # equal | auto | a number

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,5 @@ font.size:14.0
3434
savefig.edgecolor: f0f0f0
3535
savefig.facecolor: f0f0f0
3636

37-
figure.subplot.left: 0.08
38-
figure.subplot.right: 0.95
39-
figure.subplot.bottom: 0.07
37+
figure.subplot : {"left": 0.08, "right": 0.95, "bottom": 0.07}
4038
figure.facecolor: f0f0f0

lib/matplotlib/rcsetup.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@
1515
"""
1616
import six
1717

18+
import ast
1819
from collections import Iterable, Mapping
1920
from functools import reduce
2021
import operator
2122
import os
22-
import warnings
2323
import re
24+
import warnings
2425

2526
from matplotlib import cbook
26-
from matplotlib.cbook import mplDeprecation, deprecated, ls_mapper
27-
from matplotlib.fontconfig_pattern import parse_fontconfig_pattern
2827
from matplotlib.colors import is_color_like
28+
from matplotlib.fontconfig_pattern import parse_fontconfig_pattern
2929

3030
# Don't let the original cycler collide with our validating cycler
3131
from cycler import Cycler, cycler as ccycler
@@ -926,7 +926,8 @@ def validate_webagg_address(s):
926926
# ls_mapper, and a list of possible strings read from Line2D.set_linestyle
927927
_validate_named_linestyle = ValidateInStrings(
928928
'linestyle',
929-
[*ls_mapper.keys(), *ls_mapper.values(), 'None', 'none', ' ', ''],
929+
[*cbook.ls_mapper.keys(), *cbook.ls_mapper.values(),
930+
'None', 'none', ' ', ''],
930931
ignorecase=True)
931932

932933

@@ -971,6 +972,45 @@ def _validate_linestyle(ls):
971972
"sequence.".format(ls))
972973

973974

975+
def _validate_subplot(s):
976+
d = ast.literal_eval(s) if isinstance(s, str) else s
977+
try:
978+
# These imports must be delayed because they are not available at
979+
# startup (so we just assume that the default we provide ourselves are
980+
# valid).
981+
from matplotlib import rcParams
982+
from matplotlib.figure import SubplotParams
983+
except ImportError:
984+
pass
985+
else:
986+
d = {**rcParams["figure.subplot"], **d}
987+
SubplotParams(**d)
988+
for key, value in d.items():
989+
dict.__setitem__(rcParams, "figure.subplot.{}".format(key), value)
990+
return d
991+
992+
993+
def _validate_subplot_key(key):
994+
def validator(s):
995+
val = ast.literal_eval(s) if isinstance(s, str) else s
996+
try:
997+
# See above re: delayed imports.
998+
from matplotlib import rcParams
999+
from matplotlib.figure import SubplotParams
1000+
except ImportError:
1001+
pass
1002+
else:
1003+
cbook.warn_deprecated(
1004+
"3.0", "figure.subplot.{} is deprecated; set the "
1005+
"corresponding key in figure.subplot instead.".format(key),
1006+
stacklevel=4)
1007+
d = {**rcParams["figure.subplot"], key: val}
1008+
SubplotParams(**d)
1009+
dict.__setitem__(rcParams, "figure.subplot", d)
1010+
return val
1011+
return validator
1012+
1013+
9741014
# a map from key -> value, converter
9751015
defaultParams = {
9761016
'backend': ['Agg', validate_backend], # agg is certainly
@@ -1317,18 +1357,16 @@ def _validate_linestyle(ls):
13171357
'figure.autolayout': [False, validate_bool],
13181358
'figure.max_open_warning': [20, validate_int],
13191359

1320-
'figure.subplot.left': [0.125, ValidateInterval(0, 1, closedmin=True,
1321-
closedmax=True)],
1322-
'figure.subplot.right': [0.9, ValidateInterval(0, 1, closedmin=True,
1323-
closedmax=True)],
1324-
'figure.subplot.bottom': [0.11, ValidateInterval(0, 1, closedmin=True,
1325-
closedmax=True)],
1326-
'figure.subplot.top': [0.88, ValidateInterval(0, 1, closedmin=True,
1327-
closedmax=True)],
1328-
'figure.subplot.wspace': [0.2, ValidateInterval(0, 1, closedmin=True,
1329-
closedmax=False)],
1330-
'figure.subplot.hspace': [0.2, ValidateInterval(0, 1, closedmin=True,
1331-
closedmax=False)],
1360+
'figure.subplot': [{'left': 0.125, 'right': 0.9,
1361+
'bottom': 0.11, 'top': 0.88,
1362+
'wspace': 0.2, 'hspace': 0.2},
1363+
_validate_subplot],
1364+
'figure.subplot.left': [0.125, _validate_subplot_key('left')],
1365+
'figure.subplot.right': [0.9, _validate_subplot_key('right')],
1366+
'figure.subplot.bottom': [0.11, _validate_subplot_key('bottom')],
1367+
'figure.subplot.top': [0.88, _validate_subplot_key('top')],
1368+
'figure.subplot.wspace': [0.2, _validate_subplot_key('wspace')],
1369+
'figure.subplot.hspace': [0.2, _validate_subplot_key('hspace')],
13321370

13331371
# do constrained_layout.
13341372
'figure.constrained_layout.use': [False, validate_bool],

lib/matplotlib/testing/decorators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def _do_cleanup(original_units_registry, original_settings):
3131
plt.close('all')
3232

3333
mpl.rcParams.clear()
34-
mpl.rcParams.update(original_settings)
34+
dict.update(mpl.rcParams, original_settings)
3535
matplotlib.units.registry.clear()
3636
matplotlib.units.registry.update(original_units_registry)
3737
warnings.resetwarnings() # reset any warning filters set in tests

lib/matplotlib/tests/test_figure.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,11 @@ def test_fspath(fmt, tmpdir):
383383
# All the supported formats include the format name (case-insensitive)
384384
# in the first 100 bytes.
385385
assert fmt.encode("ascii") in file.read(100).lower()
386+
387+
388+
def test_clf_subplotpars():
389+
fig = plt.figure()
390+
orig_subplot_vars = vars(fig.subplotpars).copy()
391+
fig.subplots_adjust(left=0.1)
392+
fig.clf()
393+
assert vars(fig.subplotpars) == orig_subplot_vars

lib/matplotlib/tests/test_rcparams.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ def test_if_rctemplate_is_up_to_date():
476476
continue
477477
if k in deprecated:
478478
continue
479-
if "verbose" in k:
479+
if "verbose" in k or "figure.subplot." in k:
480480
continue
481481
found = False
482482
for line in rclines:

matplotlibrc.template

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -436,15 +436,8 @@ backend : $TEMPLATE_BACKEND
436436
#figure.max_open_warning : 20 ## The maximum number of figures to open through
437437
## the pyplot interface before emitting a warning.
438438
## If less than one this feature is disabled.
439-
## The figure subplot parameters. All dimensions are a fraction of the
440-
#figure.subplot.left : 0.125 ## the left side of the subplots of the figure
441-
#figure.subplot.right : 0.9 ## the right side of the subplots of the figure
442-
#figure.subplot.bottom : 0.11 ## the bottom of the subplots of the figure
443-
#figure.subplot.top : 0.88 ## the top of the subplots of the figure
444-
#figure.subplot.wspace : 0.2 ## the amount of width reserved for space between subplots,
445-
## expressed as a fraction of the average axis width
446-
#figure.subplot.hspace : 0.2 ## the amount of height reserved for space between subplots,
447-
## expressed as a fraction of the average axis height
439+
## The figure subplot parameters (see matplotlib.figure.SubplotParams).
440+
#figure.subplot : {"left": 0.125, "right": 0.9, "bottom": 0.1, "top": 0.9, "wspace": 0.2, "hspace": 0.2}
448441

449442
## Figure layout
450443
#figure.autolayout : False ## When True, automatically adjust subplot

0 commit comments

Comments
 (0)
0