From fc18909dd0541a9555e1356e8f89361fe29cbdd3 Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Fri, 5 Nov 2021 15:48:11 -0500 Subject: [PATCH 1/7] Updated figure to have getters and setters for all constructor arguments. refactored layout setting. added ability to change subplotparams post hoc. added figsize getter/setter convenience function in order to match the constructor signature of figure. added tests. --- lib/matplotlib/figure.py | 197 ++++++++++++++++++++++++---- lib/matplotlib/tests/test_figure.py | 188 ++++++++++++++++++++++++-- 2 files changed, 349 insertions(+), 36 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 04f0e73d2671..ae364df47b2d 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1204,6 +1204,32 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, ax._set_position(ax.get_subplotspec().get_position(self)) self.stale = True + def set_subplotpars(self, subplotparams = {}): + subplotparams_args = ["left", "bottom", "right", + "top", "wspace", "hspace"] + kwargs = {} + if isinstance(subplotparams,SubplotParams): + for key in subplotparams_args: + kwargs[key] = getattr(subplotparams,key) + elif isinstance(subplotparams,dict): + for key in subplotparams.keys(): + if key in subplotparams_args: + kwargs[key] = subplotparams[key] + else: + _api.warn_external( + f"'{key}' is not a valid key for set_subplotpars;" + " this key was ignored.") + else: + raise TypeError( + "subplotpars must be a dictionary of keyword-argument pairs or " + "an instance of SubplotParams()") + if kwargs == {}: + self.set_subplotpars(self.get_subplotpars()) + self.subplots_adjust(**kwargs) + + def get_subplotpars(self): + return self.subplotpars + def align_xlabels(self, axs=None): """ Align the xlabels of subplots in the same subplot column if label @@ -2231,24 +2257,6 @@ def __init__(self, """ super().__init__(**kwargs) - if layout is not None: - if tight_layout is not None: - _api.warn_external( - "The Figure parameters 'layout' and 'tight_layout' " - "cannot be used together. Please use 'layout' only.") - if constrained_layout is not None: - _api.warn_external( - "The Figure parameters 'layout' and 'constrained_layout' " - "cannot be used together. Please use 'layout' only.") - if layout == 'constrained': - tight_layout = False - constrained_layout = True - elif layout == 'tight': - tight_layout = True - constrained_layout = False - else: - _api.check_in_list(['constrained', 'tight'], layout=layout) - self.callbacks = cbook.CallbackRegistry() # Callbacks traditionally associated with the canvas (and exposed with # a proxy property), but that actually need to be on the figure for @@ -2299,15 +2307,12 @@ def __init__(self, self.subplotpars = subplotpars # constrained_layout: - self._constrained = False - - self.set_tight_layout(tight_layout) + self._axstack = _AxesStack() # track all figure axes and current axes self.clf() self._cachedRenderer = None - - self.set_constrained_layout(constrained_layout) + self.set_layout(layout,tight_layout,constrained_layout) # list of child gridspecs for this figure self._gridspecs = [] @@ -2399,11 +2404,96 @@ def _set_dpi(self, dpi, forward=True): dpi = property(_get_dpi, _set_dpi, doc="The resolution in dots per inch.") + @property + def layout(self): + if hasattr(self,'_constrained'): + if self.get_constrained_layout(): + layout = 'constrained' + elif self.get_tight_layout(): + layout = 'tight' + else: + layout = None + else: + layout = None + return layout + + def get_layout(self): + return self.layout + + def set_layout(self,layout=None, tight_layout=None,constrained_layout=None): + if ( + layout is None and + tight_layout is None and + constrained_layout is None + ): + layout = self.get_layout() + + if layout is not None: + layout_clash = False + bool_conflict = False + type_conflict = False + + if layout == 'constrained': + layoutstr = 'constrained_layout' + falselayoutstr = 'tight_layout' + layout_clash = tight_layout not in [False,None] + tight_layout=False + bool_conflict = ( + isinstance(constrained_layout,bool) and + not constrained_layout + ) + type_conflict = not isinstance(constrained_layout, + (dict, bool, type(None))) + if bool_conflict or type_conflict or constrained_layout is None: + constrained_layout=True + + + elif layout == 'tight': + layoutstr = 'tight_layout' + falselayoutstr = 'constrained_layout' + layout_clash = constrained_layout not in [False,None] + constrained_layout = False + bool_conflict = ( + isinstance(tight_layout,bool) and + not tight_layout + ) + type_conflict = not isinstance(tight_layout, + (dict, bool, type(None))) + if bool_conflict or type_conflict or tight_layout is None: + tight_layout=True + else: + _api.check_in_list(['constrained', 'tight'], layout=layout) + + if layout_clash: + _api.warn_external(f"Figure parameters " + f"'layout'=='{layout}' and " + f"'{falselayoutstr}'==True cannot " + f"be used together. " + f"Please use 'layout' only.") + if bool_conflict: + _api.warn_external(f"Figure parameters " + f"'layout'=='{layout}' and " + f"'{layoutstr}'==False cannot be " + f"used together. " + f"Please use 'layout' only.") + if type_conflict: + _api.warn_external(f"Figure parameters " + f"'layout'=='{layout}' and " + f"'{layoutstr}' cannot be " + f"used together if '{layoutstr}' is " + f"not True or a dictionary of " + f"{layoutstr} arguments. " + f"Please use 'layout' only.") + + self._constrained = False + self.set_tight_layout(tight_layout) + self.set_constrained_layout(constrained_layout) + def get_tight_layout(self): """Return whether `.tight_layout` is called when drawing.""" return self._tight - def set_tight_layout(self, tight): + def set_tight_layout(self, tight = None): """ Set whether and how `.tight_layout` is called when drawing. @@ -2429,7 +2519,7 @@ def get_constrained_layout(self): """ return self._constrained - def set_constrained_layout(self, constrained): + def set_constrained_layout(self, constrained = None): """ Set whether ``constrained_layout`` is used upon drawing. If None, :rc:`figure.constrained_layout.use` value will be used. @@ -2684,6 +2774,63 @@ def get_size_inches(self): """ return np.array(self.bbox_inches.p1) + def set_figsize(self, w, h = None): + """ + Set the figure size in inches. + Convenience wrapper for matplotlib.figure.Figure.set_size_inches. + + Call signatures:: + + fig.set_figsize(w, h) # OR + fig.set_figsize((w, h)) + + Parameters + ---------- + w : (float, float) or float + Width and height in inches (if height not specified as a separate + argument) or width. + h : float + Height in inches. + forward : bool, default: True + If ``True``, the canvas size is automatically updated, e.g., + you can resize the figure window from the shell. + + See Also + -------- + matplotlib.figure.Figure.get_figsize + matplotlib.figure.Figure.set_size_inches + matplotlib.figure.Figure.set_figwidth + matplotlib.figure.Figure.set_figheight + + Notes + ----- + To transform from pixels to inches divide by `Figure.dpi`. + """ + self.set_size_inches(w,h) + + def get_figsize(self): + """ + Return the current size of the figure in inches. + Convenience wrapper for matplotlib.figure.Figure.get_size_inches. + + Returns + ------- + ndarray + The size (width, height) of the figure in inches. + + See Also + -------- + matplotlib.figure.Figure.set_figsize + matplotlib.figure.Figure.get_size_inches + matplotlib.figure.Figure.get_figwidth + matplotlib.figure.Figure.get_figheight + + Notes + ----- + The size in pixels can be obtained by multiplying with `Figure.dpi`. + """ + return self.get_size_inches() + def get_figwidth(self): """Return the figure width in inches.""" return self.bbox_inches.width diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index cb8f63893aea..ec728cb71e93 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -10,12 +10,13 @@ import pytest from PIL import Image + import matplotlib as mpl from matplotlib import cbook, rcParams from matplotlib._api.deprecation import MatplotlibDeprecationWarning from matplotlib.testing.decorators import image_comparison, check_figures_equal from matplotlib.axes import Axes -from matplotlib.figure import Figure +from matplotlib.figure import Figure, SubplotParams from matplotlib.ticker import AutoMinorLocator, FixedFormatter, ScalarFormatter import matplotlib.pyplot as plt import matplotlib.dates as mdates @@ -350,6 +351,10 @@ def test_set_fig_size(): assert fig.get_figwidth() == 1 assert fig.get_figheight() == 3 + fig.set_figsize(2,4) + assert fig.get_figsize()[0] == 2 + assert fig.get_figsize()[1] == 4 + def test_axes_remove(): fig, axs = plt.subplots(2, 2) @@ -541,29 +546,179 @@ def test_valid_layouts(): def test_invalid_layouts(): + + def assert_is_tight(fig): + assert fig.get_tight_layout() + assert not fig.get_constrained_layout() + assert fig.layout == 'tight' + def assert_is_constrained(fig): + assert not fig.get_tight_layout() + assert fig.get_constrained_layout() + assert fig.layout == 'constrained' + def assert_neither(fig): + assert not fig.get_tight_layout() + assert not fig.get_constrained_layout() + assert fig.layout is None fig, ax = plt.subplots(constrained_layout=True) with pytest.warns(UserWarning): # this should warn, fig.subplots_adjust(top=0.8) - assert not(fig.get_constrained_layout()) - + assert_neither(fig) # Using layout + (tight|constrained)_layout warns, but the former takes # precedence. - with pytest.warns(UserWarning, match="Figure parameters 'layout' and " - "'tight_layout' cannot"): + + # check the set_layout function on figure construction: + with pytest.warns(UserWarning, match="Figure parameters 'layout'=='tight' " + "and 'tight_layout'==False cannot"): fig = Figure(layout='tight', tight_layout=False) - assert fig.get_tight_layout() - assert not fig.get_constrained_layout() - with pytest.warns(UserWarning, match="Figure parameters 'layout' and " - "'constrained_layout' cannot"): + assert_is_tight(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'constrained_layout'==False cannot"): fig = Figure(layout='constrained', constrained_layout=False) - assert not fig.get_tight_layout() - assert fig.get_constrained_layout() + assert_is_constrained(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'==True cannot"): + fig = Figure(layout='tight', constrained_layout=True) + assert_is_tight(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'==True cannot"): + fig = Figure(layout='constrained', tight_layout=True) + assert_is_constrained(fig) + + with pytest.warns(Warning) as warninfo: + fig = Figure(layout='tight', + tight_layout=False, + constrained_layout=True) + warns = {(warn.category, warn.message.args[0]) for warn in warninfo} + expected = { + (UserWarning, "Figure parameters 'layout'=='tight' " + "and 'tight_layout'==False cannot be used together. " + "Please use 'layout' only."), + (UserWarning,"Figure parameters 'layout'=='tight' " + "and 'constrained_layout'==True cannot be used together. " + "Please use 'layout' only.")} + assert_is_tight(fig) + assert warns==expected + with pytest.warns(Warning) as warninfo: + fig = Figure(layout='constrained', + tight_layout=True, + constrained_layout=False) + warns = {(warn.category, warn.message.args[0]) for warn in warninfo} + expected = { + (UserWarning, "Figure parameters 'layout'=='constrained' " + "and 'tight_layout'==True cannot be used together. " + "Please use 'layout' only."), + (UserWarning,"Figure parameters 'layout'=='constrained' " + "and 'constrained_layout'==False cannot be used together. " + "Please use 'layout' only.")} + assert_is_constrained(fig) + assert warns==expected + with pytest.raises(ValueError, match="'foobar' is not a valid value for layout"): Figure(layout='foobar') + # now check the set_layout function after figure_construction + fig = Figure(layout='tight') + with pytest.warns(UserWarning, match="Figure parameters 'layout'=='tight' " + "and 'tight_layout'==False cannot"): + fig.set_layout(layout='tight', tight_layout=False) + assert_is_tight(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'constrained_layout'==False cannot"): + fig.set_layout(layout='constrained', constrained_layout=False) + assert_is_constrained(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'==True cannot"): + fig.set_layout(layout='tight', constrained_layout=True) + assert_is_tight(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'==True cannot"): + fig.set_layout(layout='constrained', tight_layout=True) + assert_is_constrained(fig) + + with pytest.warns(Warning) as warninfo: + fig.set_layout(layout='tight', + tight_layout=False, + constrained_layout=True) + warns = {(warn.category, warn.message.args[0]) for warn in warninfo} + expected = { + (UserWarning, "Figure parameters 'layout'=='tight' " + "and 'tight_layout'==False cannot be used together. " + "Please use 'layout' only."), + (UserWarning,"Figure parameters 'layout'=='tight' " + "and 'constrained_layout'==True cannot be used together. " + "Please use 'layout' only.")} + assert_is_tight(fig) + assert warns==expected + with pytest.warns(Warning) as warninfo: + fig.set_layout(layout='constrained', + tight_layout=True, + constrained_layout=False) + warns = {(warn.category, warn.message.args[0]) for warn in warninfo} + expected = { + (UserWarning, "Figure parameters 'layout'=='constrained' " + "and 'tight_layout'==True cannot be used together. " + "Please use 'layout' only."), + (UserWarning,"Figure parameters 'layout'=='constrained' " + "and 'constrained_layout'==False cannot be used together. " + "Please use 'layout' only.")} + assert_is_constrained(fig) + assert warns==expected +def test_set_subplotpars(): + subplotparams_keys = ["left", "bottom", "right", "top", "wspace", "hspace"] + fig = plt.figure() + subplotparams = fig.get_subplotpars() + test_dict = {} + default_dict = {} + for key in subplotparams_keys: + attr = getattr(subplotparams,key) + assert attr == mpl.rcParams[f"figure.subplot.{key}"] + default_dict[key] = attr + test_dict[key] = attr * 2 + + subplotparams.update(left=test_dict['left']) + assert fig.get_subplotpars().left == test_dict['left'] + + fig.subplots_adjust(**default_dict) + assert fig.get_subplotpars().left == default_dict['left'] + + fig.set_subplotpars(test_dict) + for key, value in test_dict.items(): + assert getattr(fig.get_subplotpars(),key) == value + + test_subplotparams = SubplotParams() + fig.set_subplotpars(test_subplotparams) + for key,value in default_dict.items(): + assert getattr(fig.get_subplotpars(),key) == value + + fig.set_subplotpars(test_dict) + for key,value in test_dict.items(): + assert getattr(fig.get_subplotpars(),key) == value + + test_dict['foo'] = 'bar' + with pytest.warns(UserWarning, + match ="'foo' is not a valid key for set_subplotpars;" + " this key was ignored"): + fig.set_subplotpars(test_dict) + + with pytest.raises(TypeError, + match="subplotpars must be a dictionary of keyword-argument pairs or " + "an instance of SubplotParams()"): + fig.set_subplotpars(['foo']) + + fig.set_subplotpars({}) + with pytest.raises(AttributeError): # test_dict['foo'] = 'bar' + # but fig.get_subplotpars().foo should be invalid + for key,value in test_dict.items(): + assert getattr(fig.get_subplotpars(),key) == value @check_figures_equal(extensions=["png", "pdf"]) def test_add_artist(fig_test, fig_ref): @@ -1226,3 +1381,14 @@ def test_kwargs_pass(): assert fig.get_label() == 'whole Figure' assert sub_fig.get_label() == 'sub figure' + +def test_fig_get_set(): + varnames = filter(lambda var: var not in ['self','kwargs','args'], + Figure.__init__.__code__.co_varnames) + fig = plt.figure() + for var in varnames: + # if getattr fails then the getter and setter does not exist + getfunc = getattr(fig,f"get_{var}") + setfunc = getattr(fig,f"set_{var}") + + From 2775180af8c2aa9125253c8c5b9e1ef1a623d6ae Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Fri, 5 Nov 2021 16:03:29 -0500 Subject: [PATCH 2/7] docs --- lib/matplotlib/figure.py | 48 ++++++++++++++++++++++++++++- lib/matplotlib/tests/test_figure.py | 5 ++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index ae364df47b2d..75c87b1ef09a 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1191,6 +1191,11 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, hspace : float, optional The height of the padding between subplots, as a fraction of the average Axes height. + + See Also + -------- + matplotlib.figure.Figure.set_subplotpars + matplotlib.figure.Figure.get_subplotpars """ if self.get_constrained_layout(): self.set_constrained_layout(False) @@ -1205,6 +1210,29 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, self.stale = True def set_subplotpars(self, subplotparams = {}): + """ + Set the subplot layout parameters. + Accepts either a SubplotParams object, from which the relevant + parameters are copied, or a dictionary of subplot layout parameters. + If a dictionary is provided, this function is a convenience wrapper for + matplotlib.figure.Figure.subplots_adjust + + Parameters + ---------- + subplotparams : `~matplotlib.figure.SubplotParams` or dict, optional + SubplotParams object to copy new subplot parameters from, or a dict + of SubplotParams constructor arguments, i.e., a dictionary with + any of ["left", "bottom", "right", 'top", "wspace", "hspace"] as its + keys. + By default, an empty dictionary is passed, which maintains the + current state of the figure's SubplotParams + + See Also + -------- + matplotlib.figure.Figure.subplots_adjust + matplotlib.figure.Figure.get_subplotpars + """ + subplotparams_args = ["left", "bottom", "right", "top", "wspace", "hspace"] kwargs = {} @@ -1228,6 +1256,18 @@ def set_subplotpars(self, subplotparams = {}): self.subplots_adjust(**kwargs) def get_subplotpars(self): + """ + Return the SubplotParams object associated with the Figure. + + Returns + ------- + `.SubplotParams` + + See Also + -------- + matplotlib.figure.Figure.subplots_adjust + matplotlib.figure.Figure.get_subplotpars + """ return self.subplotpars def align_xlabels(self, axs=None): @@ -2420,7 +2460,13 @@ def layout(self): def get_layout(self): return self.layout - def set_layout(self,layout=None, tight_layout=None,constrained_layout=None): + def set_layout(self,layout=None, tight_layout=None, + constrained_layout=None): + """ + Set the figure layout specification, optionally setting how the layout + is called. + When providing a dict to tight_layout + """ if ( layout is None and tight_layout is None and diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index ec728cb71e93..f23bbf77b8fe 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -544,6 +544,10 @@ def test_valid_layouts(): assert not fig.get_tight_layout() assert fig.get_constrained_layout() + fig = Figure(constrained_layout = {'pad':1}) + assert not fig.get_tight_layout() + assert fig.get_constrained_layout() + def test_invalid_layouts(): @@ -1391,4 +1395,3 @@ def test_fig_get_set(): getfunc = getattr(fig,f"get_{var}") setfunc = getattr(fig,f"set_{var}") - From cc4f860251f710c7ba6e1051c6063a55246b0df6 Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Fri, 5 Nov 2021 16:35:42 -0500 Subject: [PATCH 3/7] added more test conditions for layout function --- lib/matplotlib/figure.py | 68 ++++++++++++++++-- lib/matplotlib/tests/test_figure.py | 106 +++++++++++++++++++++++++--- 2 files changed, 160 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 75c87b1ef09a..f6a44b37b0d8 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -2446,6 +2446,9 @@ def _set_dpi(self, dpi, forward=True): @property def layout(self): + """ + Return the current figure layout solver. + """ if hasattr(self,'_constrained'): if self.get_constrained_layout(): layout = 'constrained' @@ -2458,14 +2461,64 @@ def layout(self): return layout def get_layout(self): + """ + Return the current figure layout solver. + """ return self.layout def set_layout(self,layout=None, tight_layout=None, constrained_layout=None): """ - Set the figure layout specification, optionally setting how the layout - is called. - When providing a dict to tight_layout + Set the figure layout specification. (Optionally) sets how + `.tight_layout` or `.constrained_layout` is called when a dict is + provided to tight_layout or constrained_layout. + + + If `layout` is not None, the layout solver is determined exclusively by + `layout`, regardless of `tight_layout` or `constrained_layout`, + but optional padding parameters stored in `tight_layout` or + `constrained_layout` are used with the respective layout. For instance, + if `layout`=='tight', 'tight_layout==False', and `constrained_layout`== + True, `tight_layout` with default paddings is used to format the figure. + If `layout`=='constrained', `tight_layout`=={'pad':1}, and + `constrained_layout`=={'w_pad':1}, then + `.constrained_layout` is called with padding parameters {'w_pad':1}. + If `layout` is None, `tight_layout` and `constrained_layout` are + mutually exclusive. That is, only one can be True or a dict. + + Parameters + ---------- + layout : {'constrained', 'tight', None}, optional + The layout mechanism for positioning of plot elements. + Supported values: + + - 'constrained': The constrained layout solver usually gives the + best layout results and is thus recommended. However, it is + computationally expensive and can be slow for complex figures + with many elements. + + See :doc:`/tutorials/intermediate/constrainedlayout_guide` + for examples. + + - 'tight': Use the tight layout mechanism. This is a relatively + simple algorithm, that adjusts the subplot parameters so that + decorations like tick labels, axis labels and titles have enough + space. See `.Figure.set_tight_layout` for further details. + + If not given, fall back to using the parameters *tight_layout* and + *constrained_layout*, including their config defaults + :rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`. + tight_layout : bool or dict with keys "pad", "w_pad", "h_pad", "rect" or None + If a bool, sets whether to call `.tight_layout` upon drawing. + If ``None``, use :rc:`figure.autolayout` instead. + If a dict, pass it as kwargs to `.tight_layout`, overriding the + default paddings. + constrained_layout : bool or dict with keys "w_pad", "h_pad", "wspace", + "hspace" or None + If a bool, sets whether to call `.constrained_layout` upon drawing. + If ``None``, use :rc:`figure.autolayout` instead. + If a dict, pass it as kwargs to `.constrained_layout`, overriding the + default paddings. """ if ( layout is None and @@ -2475,6 +2528,7 @@ def set_layout(self,layout=None, tight_layout=None, layout = self.get_layout() if layout is not None: + # these will store the state of any warnings we need to pop layout_clash = False bool_conflict = False type_conflict = False @@ -2513,7 +2567,7 @@ def set_layout(self,layout=None, tight_layout=None, if layout_clash: _api.warn_external(f"Figure parameters " f"'layout'=='{layout}' and " - f"'{falselayoutstr}'==True cannot " + f"'{falselayoutstr}'!=False cannot " f"be used together. " f"Please use 'layout' only.") if bool_conflict: @@ -2530,7 +2584,11 @@ def set_layout(self,layout=None, tight_layout=None, f"not True or a dictionary of " f"{layoutstr} arguments. " f"Please use 'layout' only.") - + else: + #layout is None + if all([tight_layout, constrained_layout]): + raise ValueError("Cannot set 'tight_layout' and " + "'constrained_layout' simultaneously.") self._constrained = False self.set_tight_layout(tight_layout) self.set_constrained_layout(constrained_layout) diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index f23bbf77b8fe..ea5639901607 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -544,10 +544,32 @@ def test_valid_layouts(): assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(constrained_layout = {'pad':1}) + fig = Figure(tight_layout = {'pad':1}) + assert fig.get_tight_layout() + assert not fig.get_constrained_layout() + + fig = Figure(constrained_layout = {'w_pad':1}) assert not fig.get_tight_layout() assert fig.get_constrained_layout() + + + fig = Figure(layout='tight', tight_layout = {'pad':1}) + assert fig.get_tight_layout() + assert not fig.get_constrained_layout() + + fig = Figure(layout = 'constrained', constrained_layout = {'w_pad':1}) + assert not fig.get_tight_layout() + assert fig.get_constrained_layout() + + fig = Figure(layout='tight', tight_layout = {'pad':1}, + constrained_layout=False) + assert fig.get_tight_layout() + assert not fig.get_constrained_layout() + fig = Figure(layout = 'constrained', constrained_layout = {'w_pad':1}, + tight_layout=False) + assert not fig.get_tight_layout() + assert fig.get_constrained_layout() def test_invalid_layouts(): @@ -583,15 +605,66 @@ def assert_neither(fig): assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'==True cannot"): + "'layout'=='tight' and 'constrained_layout'!=False cannot"): fig = Figure(layout='tight', constrained_layout=True) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'==True cannot"): + "'layout'=='constrained' and 'tight_layout'!=False cannot"): fig = Figure(layout='constrained', tight_layout=True) assert_is_constrained(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout = True, + constrained_layout=True) + assert_is_tight(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout ={'pad':1}, + constrained_layout=True) + assert_is_tight(fig) + + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout ={'pad':1}, + constrained_layout={'w_pad':1}) + assert_is_tight(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout = True, + constrained_layout={'w_pad':1}) + assert_is_tight(fig) + + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'!=False cannot"): + fig = Figure(layout='constrained', constrained_layout=True, + tight_layout=True) + assert_is_constrained(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'!=False cannot"): + fig = Figure(layout='constrained', constrained_layout={'w_pad':1}, + tight_layout=True) + assert_is_constrained(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'!=False cannot"): + fig = Figure(layout='constrained', constrained_layout={'w_pad':1}, + tight_layout={'pad':1}) + assert_is_constrained(fig) + + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'!=False cannot"): + fig = Figure(layout='constrained', constrained_layout=True, + tight_layout={'pad':1}) + assert_is_constrained(fig) + with pytest.warns(Warning) as warninfo: fig = Figure(layout='tight', tight_layout=False, @@ -602,7 +675,7 @@ def assert_neither(fig): "and 'tight_layout'==False cannot be used together. " "Please use 'layout' only."), (UserWarning,"Figure parameters 'layout'=='tight' " - "and 'constrained_layout'==True cannot be used together. " + "and 'constrained_layout'!=False cannot be used together. " "Please use 'layout' only.")} assert_is_tight(fig) assert warns==expected @@ -613,7 +686,7 @@ def assert_neither(fig): warns = {(warn.category, warn.message.args[0]) for warn in warninfo} expected = { (UserWarning, "Figure parameters 'layout'=='constrained' " - "and 'tight_layout'==True cannot be used together. " + "and 'tight_layout'!=False cannot be used together. " "Please use 'layout' only."), (UserWarning,"Figure parameters 'layout'=='constrained' " "and 'constrained_layout'==False cannot be used together. " @@ -639,15 +712,24 @@ def assert_neither(fig): assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'==True cannot"): + "'layout'=='tight' and 'constrained_layout'!=False cannot"): fig.set_layout(layout='tight', constrained_layout=True) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'==True cannot"): + "'layout'=='constrained' and 'tight_layout'!=False cannot"): fig.set_layout(layout='constrained', tight_layout=True) assert_is_constrained(fig) + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='tight' and 'constrained_layout'!=False cannot"): + fig.set_layout(layout='tight', constrained_layout={'pad':1}) + assert_is_tight(fig) + with pytest.warns(UserWarning, match="Figure parameters " + "'layout'=='constrained' and 'tight_layout'!=False cannot"): + fig.set_layout(layout='constrained', tight_layout={'pad':1}) + assert_is_constrained(fig) + with pytest.warns(Warning) as warninfo: fig.set_layout(layout='tight', tight_layout=False, @@ -658,7 +740,7 @@ def assert_neither(fig): "and 'tight_layout'==False cannot be used together. " "Please use 'layout' only."), (UserWarning,"Figure parameters 'layout'=='tight' " - "and 'constrained_layout'==True cannot be used together. " + "and 'constrained_layout'!=False cannot be used together. " "Please use 'layout' only.")} assert_is_tight(fig) assert warns==expected @@ -669,13 +751,19 @@ def assert_neither(fig): warns = {(warn.category, warn.message.args[0]) for warn in warninfo} expected = { (UserWarning, "Figure parameters 'layout'=='constrained' " - "and 'tight_layout'==True cannot be used together. " + "and 'tight_layout'!=False cannot be used together. " "Please use 'layout' only."), (UserWarning,"Figure parameters 'layout'=='constrained' " "and 'constrained_layout'==False cannot be used together. " "Please use 'layout' only.")} assert_is_constrained(fig) assert warns==expected + + with pytest.raises(ValueError, + match="Cannot set 'tight_layout' and " + "'constrained_layout' simultaneously."): + fig = Figure(tight_layout = {'w':1},constrained_layout = {'w_pad':1}) + def test_set_subplotpars(): subplotparams_keys = ["left", "bottom", "right", "top", "wspace", "hspace"] fig = plt.figure() From 55d715c072d4ef66f619986d55efc9c8b83e780c Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Fri, 5 Nov 2021 17:27:29 -0500 Subject: [PATCH 4/7] doc refinements, more tests --- lib/matplotlib/figure.py | 61 ++++++++++++++--------------- lib/matplotlib/tests/test_figure.py | 31 +++++++++++++-- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index f6a44b37b0d8..b4b11fa499c8 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1212,20 +1212,19 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, def set_subplotpars(self, subplotparams = {}): """ Set the subplot layout parameters. - Accepts either a SubplotParams object, from which the relevant + Accepts either a `.SubplotParams` object, from which the relevant parameters are copied, or a dictionary of subplot layout parameters. If a dictionary is provided, this function is a convenience wrapper for - matplotlib.figure.Figure.subplots_adjust + `matplotlib.figure.Figure.subplots_adjust` Parameters ---------- - subplotparams : `~matplotlib.figure.SubplotParams` or dict, optional + subplotparams : `~matplotlib.figure.SubplotParams` or dict with keys \ +"left", "bottom", "right", 'top", "wspace", "hspace"] , optional SubplotParams object to copy new subplot parameters from, or a dict - of SubplotParams constructor arguments, i.e., a dictionary with - any of ["left", "bottom", "right", 'top", "wspace", "hspace"] as its - keys. + of SubplotParams constructor arguments. By default, an empty dictionary is passed, which maintains the - current state of the figure's SubplotParams + current state of the figure's `.SubplotParams` See Also -------- @@ -1257,7 +1256,7 @@ def set_subplotpars(self, subplotparams = {}): def get_subplotpars(self): """ - Return the SubplotParams object associated with the Figure. + Return the `.SubplotParams` object associated with the Figure. Returns ------- @@ -2470,21 +2469,23 @@ def set_layout(self,layout=None, tight_layout=None, constrained_layout=None): """ Set the figure layout specification. (Optionally) sets how - `.tight_layout` or `.constrained_layout` is called when a dict is - provided to tight_layout or constrained_layout. + `.tight_layout` or `.set_constrained_layout` is used when a dict is + provided to *tight_layout* or *constrained_layout*. - If `layout` is not None, the layout solver is determined exclusively by - `layout`, regardless of `tight_layout` or `constrained_layout`, - but optional padding parameters stored in `tight_layout` or - `constrained_layout` are used with the respective layout. For instance, - if `layout`=='tight', 'tight_layout==False', and `constrained_layout`== - True, `tight_layout` with default paddings is used to format the figure. - If `layout`=='constrained', `tight_layout`=={'pad':1}, and - `constrained_layout`=={'w_pad':1}, then - `.constrained_layout` is called with padding parameters {'w_pad':1}. - If `layout` is None, `tight_layout` and `constrained_layout` are - mutually exclusive. That is, only one can be True or a dict. + If *layout* is not *None*, the layout solver is determined exclusively by + *layout*, regardless of *tight_layout* or *constrained_layout*, + but optional padding parameters stored in *tight_layout* or + *constrained_layout* are used with the respective layout. For instance, + if *layout* is *'tight'*, *tight_layout* is *False*, and + *constrained_layout* is *True*, `.tight_layout` with default paddings + is used to format the figure. + If *layout* is *'constrained'*, *tight_layout* is *{'pad':1}*, and + *constrained_layout* is *{'w_pad':1}*, then + `.set_constrained_layout` is called with padding parameters {'w_pad':1}. + If *layout* is None, *tight_layout* and *constrained_layout* are + mutually exclusive. That is, only one can be True or a dict, as + resolving the case where both are True is ambiguous. Parameters ---------- @@ -2508,16 +2509,17 @@ def set_layout(self,layout=None, tight_layout=None, If not given, fall back to using the parameters *tight_layout* and *constrained_layout*, including their config defaults :rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`. - tight_layout : bool or dict with keys "pad", "w_pad", "h_pad", "rect" or None + tight_layout : bool or dict with keys "pad", "w_pad", "h_pad", "rect", \ +or None If a bool, sets whether to call `.tight_layout` upon drawing. If ``None``, use :rc:`figure.autolayout` instead. If a dict, pass it as kwargs to `.tight_layout`, overriding the default paddings. - constrained_layout : bool or dict with keys "w_pad", "h_pad", "wspace", - "hspace" or None - If a bool, sets whether to call `.constrained_layout` upon drawing. + constrained_layout : bool or dict with keys "w_pad", "h_pad", "wspace", \ +"hspace" or None + If a bool, sets whether to use ``constrained_layout`` upon drawing. If ``None``, use :rc:`figure.autolayout` instead. - If a dict, pass it as kwargs to `.constrained_layout`, overriding the + If a dict, pass it as kwargs to `.set_constrained_layout`, overriding the default paddings. """ if ( @@ -2881,7 +2883,7 @@ def get_size_inches(self): def set_figsize(self, w, h = None): """ Set the figure size in inches. - Convenience wrapper for matplotlib.figure.Figure.set_size_inches. + Convenience wrapper for `~matplotlib.figure.Figure.set_size_inches`. Call signatures:: @@ -2895,9 +2897,6 @@ def set_figsize(self, w, h = None): argument) or width. h : float Height in inches. - forward : bool, default: True - If ``True``, the canvas size is automatically updated, e.g., - you can resize the figure window from the shell. See Also -------- @@ -2915,7 +2914,7 @@ def set_figsize(self, w, h = None): def get_figsize(self): """ Return the current size of the figure in inches. - Convenience wrapper for matplotlib.figure.Figure.get_size_inches. + Convenience wrapper for `~matplotlib.figure.Figure.get_size_inches`. Returns ------- diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index ea5639901607..abf90ca366b8 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -548,10 +548,25 @@ def test_valid_layouts(): assert fig.get_tight_layout() assert not fig.get_constrained_layout() + fig = Figure(tight_layout = True) + assert fig.get_tight_layout() + assert not fig.get_constrained_layout() + + fig = Figure(tight_layout = True, constrained_layout=False) + assert fig.get_tight_layout() + assert not fig.get_constrained_layout() + fig = Figure(constrained_layout = {'w_pad':1}) assert not fig.get_tight_layout() assert fig.get_constrained_layout() + fig = Figure(constrained_layout = True) + assert not fig.get_tight_layout() + assert fig.get_constrained_layout() + + fig = Figure(constrained_layout = True,tight_layout=False) + assert not fig.get_tight_layout() + assert fig.get_constrained_layout() fig = Figure(layout='tight', tight_layout = {'pad':1}) assert fig.get_tight_layout() @@ -565,12 +580,15 @@ def test_valid_layouts(): constrained_layout=False) assert fig.get_tight_layout() assert not fig.get_constrained_layout() - + fig = Figure(layout = 'constrained', constrained_layout = {'w_pad':1}, tight_layout=False) assert not fig.get_tight_layout() assert fig.get_constrained_layout() - + fig = Figure(layout = None, constrained_layout = False, + tight_layout=False) + assert not fig.get_tight_layout() + assert not fig.get_constrained_layout() def test_invalid_layouts(): def assert_is_tight(fig): @@ -763,7 +781,14 @@ def assert_neither(fig): match="Cannot set 'tight_layout' and " "'constrained_layout' simultaneously."): fig = Figure(tight_layout = {'w':1},constrained_layout = {'w_pad':1}) - + with pytest.raises(ValueError, + match="Cannot set 'tight_layout' and " + "'constrained_layout' simultaneously."): + fig = Figure(tight_layout = True,constrained_layout = {'w_pad':1}) + with pytest.raises(ValueError, + match="Cannot set 'tight_layout' and " + "'constrained_layout' simultaneously."): + fig = Figure(tight_layout = True,constrained_layout = True) def test_set_subplotpars(): subplotparams_keys = ["left", "bottom", "right", "top", "wspace", "hspace"] fig = plt.figure() From 781d0e82cc7c7b24dce7b9b6032a1caa55617155 Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Fri, 5 Nov 2021 17:48:11 -0500 Subject: [PATCH 5/7] pep8/flake8 --- lib/matplotlib/figure.py | 148 ++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 73 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index b4b11fa499c8..f87528d61db8 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -183,6 +183,7 @@ class FigureBase(Artist): Base class for `.figure.Figure` and `.figure.SubFigure` containing the methods that add artists to the figure or subfigure, create Axes, etc. """ + def __init__(self, **kwargs): super().__init__() # remove the non-figure artist _axes property @@ -1051,9 +1052,9 @@ def legend(self, *args, **kwargs): """ handles, labels, extra_args, kwargs = mlegend._parse_legend_args( - self.axes, - *args, - **kwargs) + self.axes, + *args, + **kwargs) # check for third arg if len(extra_args): # _api.warn_deprecated( @@ -1209,7 +1210,7 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, ax._set_position(ax.get_subplotspec().get_position(self)) self.stale = True - def set_subplotpars(self, subplotparams = {}): + def set_subplotpars(self, subplotparams={}): """ Set the subplot layout parameters. Accepts either a `.SubplotParams` object, from which the relevant @@ -1221,24 +1222,23 @@ def set_subplotpars(self, subplotparams = {}): ---------- subplotparams : `~matplotlib.figure.SubplotParams` or dict with keys \ "left", "bottom", "right", 'top", "wspace", "hspace"] , optional - SubplotParams object to copy new subplot parameters from, or a dict - of SubplotParams constructor arguments. - By default, an empty dictionary is passed, which maintains the - current state of the figure's `.SubplotParams` + SubplotParams object to copy new subplot parameters from, or a dict + of SubplotParams constructor arguments. + By default, an empty dictionary is passed, which maintains the + current state of the figure's `.SubplotParams` See Also -------- matplotlib.figure.Figure.subplots_adjust matplotlib.figure.Figure.get_subplotpars """ - subplotparams_args = ["left", "bottom", "right", - "top", "wspace", "hspace"] + "top", "wspace", "hspace"] kwargs = {} - if isinstance(subplotparams,SubplotParams): + if isinstance(subplotparams, SubplotParams): for key in subplotparams_args: - kwargs[key] = getattr(subplotparams,key) - elif isinstance(subplotparams,dict): + kwargs[key] = getattr(subplotparams, key) + elif isinstance(subplotparams, dict): for key in subplotparams.keys(): if key in subplotparams_args: kwargs[key] = subplotparams[key] @@ -1248,8 +1248,8 @@ def set_subplotpars(self, subplotparams = {}): " this key was ignored.") else: raise TypeError( - "subplotpars must be a dictionary of keyword-argument pairs or " - "an instance of SubplotParams()") + "subplotpars must be a dictionary of keyword-argument pairs or" + " an instance of SubplotParams()") if kwargs == {}: self.set_subplotpars(self.get_subplotpars()) self.subplots_adjust(**kwargs) @@ -2346,12 +2346,11 @@ def __init__(self, self.subplotpars = subplotpars # constrained_layout: - self._axstack = _AxesStack() # track all figure axes and current axes self.clf() self._cachedRenderer = None - self.set_layout(layout,tight_layout,constrained_layout) + self.set_layout(layout, tight_layout, constrained_layout) # list of child gridspecs for this figure self._gridspecs = [] @@ -2448,7 +2447,7 @@ def layout(self): """ Return the current figure layout solver. """ - if hasattr(self,'_constrained'): + if hasattr(self, '_constrained'): if self.get_constrained_layout(): layout = 'constrained' elif self.get_tight_layout(): @@ -2465,26 +2464,27 @@ def get_layout(self): """ return self.layout - def set_layout(self,layout=None, tight_layout=None, + def set_layout(self, layout=None, tight_layout=None, constrained_layout=None): """ Set the figure layout specification. (Optionally) sets how `.tight_layout` or `.set_constrained_layout` is used when a dict is provided to *tight_layout* or *constrained_layout*. - - If *layout* is not *None*, the layout solver is determined exclusively by - *layout*, regardless of *tight_layout* or *constrained_layout*, + + If *layout* is not *None*, the layout solver is determined exclusively + by *layout*, regardless of *tight_layout* or *constrained_layout*, but optional padding parameters stored in *tight_layout* or *constrained_layout* are used with the respective layout. For instance, - if *layout* is *'tight'*, *tight_layout* is *False*, and - *constrained_layout* is *True*, `.tight_layout` with default paddings + if *layout* is *'tight'*, *tight_layout* is *False*, and + *constrained_layout* is *True*, `.tight_layout` with default paddings is used to format the figure. - If *layout* is *'constrained'*, *tight_layout* is *{'pad':1}*, and + If *layout* is *'constrained'*, *tight_layout* is *{'pad':1}*, and *constrained_layout* is *{'w_pad':1}*, then - `.set_constrained_layout` is called with padding parameters {'w_pad':1}. - If *layout* is None, *tight_layout* and *constrained_layout* are - mutually exclusive. That is, only one can be True or a dict, as + `.set_constrained_layout` is called with padding parameters + *{'w_pad':1}*. + If *layout* is None, *tight_layout* and *constrained_layout* are + mutually exclusive. That is, only one can be True or a dict, as resolving the case where both are True is ambiguous. Parameters @@ -2509,24 +2509,24 @@ def set_layout(self,layout=None, tight_layout=None, If not given, fall back to using the parameters *tight_layout* and *constrained_layout*, including their config defaults :rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`. - tight_layout : bool or dict with keys "pad", "w_pad", "h_pad", "rect", \ -or None + tight_layout : bool or dict with keys "pad", "w_pad", "h_pad", \ +"rect", or None If a bool, sets whether to call `.tight_layout` upon drawing. If ``None``, use :rc:`figure.autolayout` instead. If a dict, pass it as kwargs to `.tight_layout`, overriding the default paddings. - constrained_layout : bool or dict with keys "w_pad", "h_pad", "wspace", \ -"hspace" or None + constrained_layout : bool or dict with keys "w_pad", "h_pad", \ +"wspace", "hspace" or None If a bool, sets whether to use ``constrained_layout`` upon drawing. If ``None``, use :rc:`figure.autolayout` instead. - If a dict, pass it as kwargs to `.set_constrained_layout`, overriding the - default paddings. + If a dict, pass it as kwargs to `.set_constrained_layout`, + overriding the default paddings. """ if ( - layout is None and - tight_layout is None and + layout is None and + tight_layout is None and constrained_layout is None - ): + ): layout = self.get_layout() if layout is not None: @@ -2538,59 +2538,61 @@ def set_layout(self,layout=None, tight_layout=None, if layout == 'constrained': layoutstr = 'constrained_layout' falselayoutstr = 'tight_layout' - layout_clash = tight_layout not in [False,None] - tight_layout=False + layout_clash = tight_layout not in [False, None] + tight_layout = False bool_conflict = ( - isinstance(constrained_layout,bool) and + isinstance(constrained_layout, bool) and not constrained_layout - ) + ) type_conflict = not isinstance(constrained_layout, - (dict, bool, type(None))) - if bool_conflict or type_conflict or constrained_layout is None: - constrained_layout=True - + (dict, bool, type(None))) + if ( + bool_conflict or + type_conflict or + constrained_layout is None + ): + constrained_layout = True elif layout == 'tight': layoutstr = 'tight_layout' falselayoutstr = 'constrained_layout' - layout_clash = constrained_layout not in [False,None] + layout_clash = constrained_layout not in [False, None] constrained_layout = False bool_conflict = ( - isinstance(tight_layout,bool) and + isinstance(tight_layout, bool) and not tight_layout - ) - type_conflict = not isinstance(tight_layout, - (dict, bool, type(None))) + ) + type_conflict = not isinstance(tight_layout, + (dict, bool, type(None))) if bool_conflict or type_conflict or tight_layout is None: - tight_layout=True + tight_layout = True else: _api.check_in_list(['constrained', 'tight'], layout=layout) if layout_clash: - _api.warn_external(f"Figure parameters " - f"'layout'=='{layout}' and " - f"'{falselayoutstr}'!=False cannot " - f"be used together. " - f"Please use 'layout' only.") + _api.warn_external(f"Figure parameters " + f"'layout'=='{layout}' and " + f"'{falselayoutstr}'!=False cannot " + f"be used together. " + f"Please use 'layout' only.") if bool_conflict: _api.warn_external(f"Figure parameters " - f"'layout'=='{layout}' and " - f"'{layoutstr}'==False cannot be " - f"used together. " - f"Please use 'layout' only.") + f"'layout'=='{layout}' and " + f"'{layoutstr}'==False cannot be " + f"used together. " + f"Please use 'layout' only.") if type_conflict: _api.warn_external(f"Figure parameters " - f"'layout'=='{layout}' and " - f"'{layoutstr}' cannot be " - f"used together if '{layoutstr}' is " - f"not True or a dictionary of " - f"{layoutstr} arguments. " - f"Please use 'layout' only.") + f"'layout'=='{layout}' and " + f"'{layoutstr}' cannot be " + f"used together if '{layoutstr}' is " + f"not True or a dictionary of " + f"{layoutstr} arguments. " + f"Please use 'layout' only.") else: - #layout is None if all([tight_layout, constrained_layout]): raise ValueError("Cannot set 'tight_layout' and " - "'constrained_layout' simultaneously.") + "'constrained_layout' simultaneously.") self._constrained = False self.set_tight_layout(tight_layout) self.set_constrained_layout(constrained_layout) @@ -2599,7 +2601,7 @@ def get_tight_layout(self): """Return whether `.tight_layout` is called when drawing.""" return self._tight - def set_tight_layout(self, tight = None): + def set_tight_layout(self, tight=None): """ Set whether and how `.tight_layout` is called when drawing. @@ -2625,7 +2627,7 @@ def get_constrained_layout(self): """ return self._constrained - def set_constrained_layout(self, constrained = None): + def set_constrained_layout(self, constrained=None): """ Set whether ``constrained_layout`` is used upon drawing. If None, :rc:`figure.constrained_layout.use` value will be used. @@ -2880,7 +2882,7 @@ def get_size_inches(self): """ return np.array(self.bbox_inches.p1) - def set_figsize(self, w, h = None): + def set_figsize(self, w, h=None): """ Set the figure size in inches. Convenience wrapper for `~matplotlib.figure.Figure.set_size_inches`. @@ -2909,11 +2911,11 @@ def set_figsize(self, w, h = None): ----- To transform from pixels to inches divide by `Figure.dpi`. """ - self.set_size_inches(w,h) + self.set_size_inches(w, h) def get_figsize(self): """ - Return the current size of the figure in inches. + Return the current size of the figure in inches. Convenience wrapper for `~matplotlib.figure.Figure.get_size_inches`. Returns From 09b931bc029ca4d5c54aa89ed061309492240f8a Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Fri, 5 Nov 2021 18:12:39 -0500 Subject: [PATCH 6/7] doc formatting --- lib/matplotlib/figure.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index f87528d61db8..ed690d74400f 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -2472,20 +2472,26 @@ def set_layout(self, layout=None, tight_layout=None, provided to *tight_layout* or *constrained_layout*. - If *layout* is not *None*, the layout solver is determined exclusively - by *layout*, regardless of *tight_layout* or *constrained_layout*, - but optional padding parameters stored in *tight_layout* or - *constrained_layout* are used with the respective layout. For instance, - if *layout* is *'tight'*, *tight_layout* is *False*, and - *constrained_layout* is *True*, `.tight_layout` with default paddings - is used to format the figure. - If *layout* is *'constrained'*, *tight_layout* is *{'pad':1}*, and - *constrained_layout* is *{'w_pad':1}*, then - `.set_constrained_layout` is called with padding parameters - *{'w_pad':1}*. - If *layout* is None, *tight_layout* and *constrained_layout* are - mutually exclusive. That is, only one can be True or a dict, as - resolving the case where both are True is ambiguous. + - If *layout* is not *None*, the layout solver is determined + exclusively by *layout*, regardless of *tight_layout* or + *constrained_layout*, but optional padding parameters stored in + *tight_layout* or *constrained_layout* are used with the respective + layout. + For instance: + + - if *layout* is *'tight'*, *tight_layout* is *False*, and + *constrained_layout* is *True*, `.tight_layout` with default paddings + is used to format the figure. + + - If *layout* is *'constrained'*, *tight_layout* is *{'pad':1}*, and + *constrained_layout* is *{'w_pad':1}*, then + `.set_constrained_layout` is called with padding parameters + *{'w_pad':1}*. + + - If *layout* is None, *tight_layout* and *constrained_layout* are + mutually exclusive. That is, only one can be *True* or a dict, as + resolving the case where both are not *False* and *layout* is *None* + is ambiguous. Parameters ---------- From 1d324c487d5a625d2b79d04c6caa54dcd8b2c675 Mon Sep 17 00:00:00 2001 From: Jay Stanley Date: Mon, 8 Nov 2021 10:46:47 -0600 Subject: [PATCH 7/7] pep8/flake8 tests. cbook._define_aliases for figsize --- lib/matplotlib/figure.py | 69 +------- lib/matplotlib/tests/test_figure.py | 260 +++++++++++++++------------- 2 files changed, 149 insertions(+), 180 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index ed690d74400f..b9a789d57c93 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -2180,6 +2180,9 @@ def draw(self, renderer): @docstring.interpd +@cbook._define_aliases({ + "size_inches": ["figsize"] +}) class Figure(FigureBase): """ The top level container for all the plot elements. @@ -2472,11 +2475,11 @@ def set_layout(self, layout=None, tight_layout=None, provided to *tight_layout* or *constrained_layout*. - - If *layout* is not *None*, the layout solver is determined - exclusively by *layout*, regardless of *tight_layout* or - *constrained_layout*, but optional padding parameters stored in - *tight_layout* or *constrained_layout* are used with the respective - layout. + - If *layout* is not *None*, the layout solver is determined + exclusively by *layout*, regardless of *tight_layout* or + *constrained_layout*, but optional padding parameters stored in + *tight_layout* or *constrained_layout* are used with the respective + layout. For instance: - if *layout* is *'tight'*, *tight_layout* is *False*, and @@ -2556,7 +2559,7 @@ def set_layout(self, layout=None, tight_layout=None, bool_conflict or type_conflict or constrained_layout is None - ): + ): constrained_layout = True elif layout == 'tight': @@ -2888,60 +2891,6 @@ def get_size_inches(self): """ return np.array(self.bbox_inches.p1) - def set_figsize(self, w, h=None): - """ - Set the figure size in inches. - Convenience wrapper for `~matplotlib.figure.Figure.set_size_inches`. - - Call signatures:: - - fig.set_figsize(w, h) # OR - fig.set_figsize((w, h)) - - Parameters - ---------- - w : (float, float) or float - Width and height in inches (if height not specified as a separate - argument) or width. - h : float - Height in inches. - - See Also - -------- - matplotlib.figure.Figure.get_figsize - matplotlib.figure.Figure.set_size_inches - matplotlib.figure.Figure.set_figwidth - matplotlib.figure.Figure.set_figheight - - Notes - ----- - To transform from pixels to inches divide by `Figure.dpi`. - """ - self.set_size_inches(w, h) - - def get_figsize(self): - """ - Return the current size of the figure in inches. - Convenience wrapper for `~matplotlib.figure.Figure.get_size_inches`. - - Returns - ------- - ndarray - The size (width, height) of the figure in inches. - - See Also - -------- - matplotlib.figure.Figure.set_figsize - matplotlib.figure.Figure.get_size_inches - matplotlib.figure.Figure.get_figwidth - matplotlib.figure.Figure.get_figheight - - Notes - ----- - The size in pixels can be obtained by multiplying with `Figure.dpi`. - """ - return self.get_size_inches() - def get_figwidth(self): """Return the figure width in inches.""" return self.bbox_inches.width diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index abf90ca366b8..7dbd017cb668 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -351,7 +351,7 @@ def test_set_fig_size(): assert fig.get_figwidth() == 1 assert fig.get_figheight() == 3 - fig.set_figsize(2,4) + fig.set_figsize(2, 4) assert fig.get_figsize()[0] == 2 assert fig.get_figsize()[1] == 4 @@ -544,61 +544,65 @@ def test_valid_layouts(): assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(tight_layout = {'pad':1}) + fig = Figure(tight_layout={'pad': 1}) assert fig.get_tight_layout() assert not fig.get_constrained_layout() - fig = Figure(tight_layout = True) + fig = Figure(tight_layout=True) assert fig.get_tight_layout() assert not fig.get_constrained_layout() - fig = Figure(tight_layout = True, constrained_layout=False) + fig = Figure(tight_layout=True, constrained_layout=False) assert fig.get_tight_layout() assert not fig.get_constrained_layout() - fig = Figure(constrained_layout = {'w_pad':1}) + fig = Figure(constrained_layout={'w_pad': 1}) assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(constrained_layout = True) + fig = Figure(constrained_layout=True) assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(constrained_layout = True,tight_layout=False) + fig = Figure(constrained_layout=True, tight_layout=False) assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(layout='tight', tight_layout = {'pad':1}) + fig = Figure(layout='tight', tight_layout={'pad': 1}) assert fig.get_tight_layout() assert not fig.get_constrained_layout() - fig = Figure(layout = 'constrained', constrained_layout = {'w_pad':1}) + fig = Figure(layout='constrained', constrained_layout={'w_pad': 1}) assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(layout='tight', tight_layout = {'pad':1}, - constrained_layout=False) + fig = Figure(layout='tight', tight_layout={'pad': 1}, + constrained_layout=False) assert fig.get_tight_layout() - assert not fig.get_constrained_layout() + assert not fig.get_constrained_layout() - fig = Figure(layout = 'constrained', constrained_layout = {'w_pad':1}, - tight_layout=False) + fig = Figure(layout='constrained', constrained_layout={'w_pad': 1}, + tight_layout=False) assert not fig.get_tight_layout() assert fig.get_constrained_layout() - fig = Figure(layout = None, constrained_layout = False, - tight_layout=False) + fig = Figure(layout=None, constrained_layout=False, + tight_layout=False) assert not fig.get_tight_layout() assert not fig.get_constrained_layout() + + def test_invalid_layouts(): def assert_is_tight(fig): assert fig.get_tight_layout() assert not fig.get_constrained_layout() assert fig.layout == 'tight' + def assert_is_constrained(fig): assert not fig.get_tight_layout() assert fig.get_constrained_layout() assert fig.layout == 'constrained' + def assert_neither(fig): assert not fig.get_tight_layout() assert not fig.get_constrained_layout() @@ -612,106 +616,113 @@ def assert_neither(fig): # precedence. # check the set_layout function on figure construction: - with pytest.warns(UserWarning, match="Figure parameters 'layout'=='tight' " - "and 'tight_layout'==False cannot"): + with pytest.warns(UserWarning, match="Figure parameters 'layout'=='tight'" + " and 'tight_layout'==False cannot"): fig = Figure(layout='tight', tight_layout=False) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'constrained_layout'==False cannot"): + "'layout'=='constrained' and " + "'constrained_layout'==False cannot"): fig = Figure(layout='constrained', constrained_layout=False) assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig = Figure(layout='tight', constrained_layout=True) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', constrained_layout=True) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): fig = Figure(layout='constrained', tight_layout=True) assert_is_constrained(fig) - with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig = Figure(layout='tight', tight_layout = True, - constrained_layout=True) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout=True, + constrained_layout=True) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig = Figure(layout='tight', tight_layout ={'pad':1}, - constrained_layout=True) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout={'pad': 1}, + constrained_layout=True) assert_is_tight(fig) - with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig = Figure(layout='tight', tight_layout ={'pad':1}, - constrained_layout={'w_pad':1}) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout={'pad': 1}, + constrained_layout={'w_pad': 1}) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig = Figure(layout='tight', tight_layout = True, - constrained_layout={'w_pad':1}) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig = Figure(layout='tight', tight_layout=True, + constrained_layout={'w_pad': 1}) assert_is_tight(fig) - with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): fig = Figure(layout='constrained', constrained_layout=True, - tight_layout=True) + tight_layout=True) assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): - fig = Figure(layout='constrained', constrained_layout={'w_pad':1}, - tight_layout=True) + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): + fig = Figure(layout='constrained', constrained_layout={'w_pad': 1}, + tight_layout=True) assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): - fig = Figure(layout='constrained', constrained_layout={'w_pad':1}, - tight_layout={'pad':1}) + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): + fig = Figure(layout='constrained', constrained_layout={'w_pad': 1}, + tight_layout={'pad': 1}) assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): fig = Figure(layout='constrained', constrained_layout=True, - tight_layout={'pad':1}) + tight_layout={'pad': 1}) assert_is_constrained(fig) with pytest.warns(Warning) as warninfo: - fig = Figure(layout='tight', - tight_layout=False, - constrained_layout=True) + fig = Figure(layout='tight', + tight_layout=False, + constrained_layout=True) warns = {(warn.category, warn.message.args[0]) for warn in warninfo} expected = { (UserWarning, "Figure parameters 'layout'=='tight' " - "and 'tight_layout'==False cannot be used together. " - "Please use 'layout' only."), - (UserWarning,"Figure parameters 'layout'=='tight' " - "and 'constrained_layout'!=False cannot be used together. " - "Please use 'layout' only.")} + "and 'tight_layout'==False cannot be used together. " + "Please use 'layout' only."), + (UserWarning, "Figure parameters 'layout'=='tight' " + "and 'constrained_layout'!=False cannot be used together. " + "Please use 'layout' only.")} assert_is_tight(fig) - assert warns==expected + assert warns == expected with pytest.warns(Warning) as warninfo: - fig = Figure(layout='constrained', - tight_layout=True, - constrained_layout=False) + fig = Figure(layout='constrained', + tight_layout=True, + constrained_layout=False) warns = {(warn.category, warn.message.args[0]) for warn in warninfo} expected = { (UserWarning, "Figure parameters 'layout'=='constrained' " - "and 'tight_layout'!=False cannot be used together. " - "Please use 'layout' only."), - (UserWarning,"Figure parameters 'layout'=='constrained' " - "and 'constrained_layout'==False cannot be used together. " - "Please use 'layout' only.")} + "and 'tight_layout'!=False cannot be used together. " + "Please use 'layout' only."), + (UserWarning, "Figure parameters 'layout'=='constrained' " + "and 'constrained_layout'==False cannot be used together. " + "Please use 'layout' only.")} assert_is_constrained(fig) - assert warns==expected - + assert warns == expected with pytest.raises(ValueError, match="'foobar' is not a valid value for layout"): @@ -720,75 +731,82 @@ def assert_neither(fig): fig = Figure(layout='tight') with pytest.warns(UserWarning, match="Figure parameters 'layout'=='tight' " - "and 'tight_layout'==False cannot"): + "and 'tight_layout'==False cannot"): fig.set_layout(layout='tight', tight_layout=False) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'constrained_layout'==False cannot"): + "'layout'=='constrained' and " + "'constrained_layout'==False cannot"): fig.set_layout(layout='constrained', constrained_layout=False) assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig.set_layout(layout='tight', constrained_layout=True) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig.set_layout(layout='tight', constrained_layout=True) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): fig.set_layout(layout='constrained', tight_layout=True) assert_is_constrained(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='tight' and 'constrained_layout'!=False cannot"): - fig.set_layout(layout='tight', constrained_layout={'pad':1}) + "'layout'=='tight' and " + "'constrained_layout'!=False cannot"): + fig.set_layout(layout='tight', constrained_layout={'pad': 1}) assert_is_tight(fig) with pytest.warns(UserWarning, match="Figure parameters " - "'layout'=='constrained' and 'tight_layout'!=False cannot"): - fig.set_layout(layout='constrained', tight_layout={'pad':1}) + "'layout'=='constrained' and " + "'tight_layout'!=False cannot"): + fig.set_layout(layout='constrained', tight_layout={'pad': 1}) assert_is_constrained(fig) with pytest.warns(Warning) as warninfo: - fig.set_layout(layout='tight', - tight_layout=False, - constrained_layout=True) + fig.set_layout(layout='tight', + tight_layout=False, + constrained_layout=True) warns = {(warn.category, warn.message.args[0]) for warn in warninfo} expected = { (UserWarning, "Figure parameters 'layout'=='tight' " - "and 'tight_layout'==False cannot be used together. " - "Please use 'layout' only."), - (UserWarning,"Figure parameters 'layout'=='tight' " - "and 'constrained_layout'!=False cannot be used together. " - "Please use 'layout' only.")} + "and 'tight_layout'==False cannot be used together. " + "Please use 'layout' only."), + (UserWarning, "Figure parameters 'layout'=='tight' " + "and 'constrained_layout'!=False cannot be used together. " + "Please use 'layout' only.")} assert_is_tight(fig) - assert warns==expected + assert warns == expected with pytest.warns(Warning) as warninfo: - fig.set_layout(layout='constrained', - tight_layout=True, - constrained_layout=False) + fig.set_layout(layout='constrained', + tight_layout=True, + constrained_layout=False) warns = {(warn.category, warn.message.args[0]) for warn in warninfo} expected = { (UserWarning, "Figure parameters 'layout'=='constrained' " - "and 'tight_layout'!=False cannot be used together. " - "Please use 'layout' only."), - (UserWarning,"Figure parameters 'layout'=='constrained' " - "and 'constrained_layout'==False cannot be used together. " - "Please use 'layout' only.")} + "and 'tight_layout'!=False cannot be used together. " + "Please use 'layout' only."), + (UserWarning, "Figure parameters 'layout'=='constrained' " + "and 'constrained_layout'==False cannot be used together. " + "Please use 'layout' only.")} assert_is_constrained(fig) - assert warns==expected + assert warns == expected with pytest.raises(ValueError, match="Cannot set 'tight_layout' and " "'constrained_layout' simultaneously."): - fig = Figure(tight_layout = {'w':1},constrained_layout = {'w_pad':1}) + fig = Figure(tight_layout={'w': 1}, constrained_layout={'w_pad': 1}) with pytest.raises(ValueError, match="Cannot set 'tight_layout' and " "'constrained_layout' simultaneously."): - fig = Figure(tight_layout = True,constrained_layout = {'w_pad':1}) + fig = Figure(tight_layout=True, constrained_layout={'w_pad': 1}) with pytest.raises(ValueError, match="Cannot set 'tight_layout' and " "'constrained_layout' simultaneously."): - fig = Figure(tight_layout = True,constrained_layout = True) + fig = Figure(tight_layout=True, constrained_layout=True) + + def test_set_subplotpars(): subplotparams_keys = ["left", "bottom", "right", "top", "wspace", "hspace"] fig = plt.figure() @@ -796,7 +814,7 @@ def test_set_subplotpars(): test_dict = {} default_dict = {} for key in subplotparams_keys: - attr = getattr(subplotparams,key) + attr = getattr(subplotparams, key) assert attr == mpl.rcParams[f"figure.subplot.{key}"] default_dict[key] = attr test_dict[key] = attr * 2 @@ -809,33 +827,35 @@ def test_set_subplotpars(): fig.set_subplotpars(test_dict) for key, value in test_dict.items(): - assert getattr(fig.get_subplotpars(),key) == value + assert getattr(fig.get_subplotpars(), key) == value test_subplotparams = SubplotParams() fig.set_subplotpars(test_subplotparams) - for key,value in default_dict.items(): - assert getattr(fig.get_subplotpars(),key) == value + for key, value in default_dict.items(): + assert getattr(fig.get_subplotpars(), key) == value fig.set_subplotpars(test_dict) - for key,value in test_dict.items(): - assert getattr(fig.get_subplotpars(),key) == value + for key, value in test_dict.items(): + assert getattr(fig.get_subplotpars(), key) == value test_dict['foo'] = 'bar' - with pytest.warns(UserWarning, - match ="'foo' is not a valid key for set_subplotpars;" - " this key was ignored"): + with pytest.warns(UserWarning, + match="'foo' is not a valid key for set_subplotpars;" + " this key was ignored"): fig.set_subplotpars(test_dict) with pytest.raises(TypeError, - match="subplotpars must be a dictionary of keyword-argument pairs or " - "an instance of SubplotParams()"): + match="subplotpars must be a dictionary of " + "keyword-argument pairs or " + "an instance of SubplotParams()"): fig.set_subplotpars(['foo']) fig.set_subplotpars({}) - with pytest.raises(AttributeError): # test_dict['foo'] = 'bar' - # but fig.get_subplotpars().foo should be invalid - for key,value in test_dict.items(): - assert getattr(fig.get_subplotpars(),key) == value + with pytest.raises(AttributeError): # test_dict['foo'] = 'bar' + # but fig.get_subplotpars().foo should be invalid + for key, value in test_dict.items(): + assert getattr(fig.get_subplotpars(), key) == value + @check_figures_equal(extensions=["png", "pdf"]) def test_add_artist(fig_test, fig_ref): @@ -1267,7 +1287,7 @@ def test_subfigure_tightbbox(): sub = fig.subfigures(1, 2) np.testing.assert_allclose( - fig.get_tightbbox(fig.canvas.get_renderer()).width, 0.1) + fig.get_tightbbox(fig.canvas.get_renderer()).width, 0.1) @image_comparison(['test_subfigure_ss.png'], style='mpl20', @@ -1350,11 +1370,11 @@ def test_subfigure_spanning(): w = 640 h = 480 - np.testing.assert_allclose(sub_figs[0].bbox.min, [0., h * 2/3]) + np.testing.assert_allclose(sub_figs[0].bbox.min, [0., h * 2 / 3]) np.testing.assert_allclose(sub_figs[0].bbox.max, [w / 3, h]) np.testing.assert_allclose(sub_figs[1].bbox.min, [w / 3, h / 3]) - np.testing.assert_allclose(sub_figs[1].bbox.max, [w * 2/3, h]) + np.testing.assert_allclose(sub_figs[1].bbox.max, [w * 2 / 3, h]) np.testing.assert_allclose(sub_figs[2].bbox.min, [w / 3, 0]) np.testing.assert_allclose(sub_figs[2].bbox.max, [w, h / 3]) @@ -1395,7 +1415,7 @@ def test_subfigure_ticks(): @image_comparison(['test_subfigure_scatter_size.png'], style='mpl20', - remove_text=True) + remove_text=True) def test_subfigure_scatter_size(): # markers in the left- and right-most subplots should be the same fig = plt.figure() @@ -1499,12 +1519,12 @@ def test_kwargs_pass(): assert fig.get_label() == 'whole Figure' assert sub_fig.get_label() == 'sub figure' + def test_fig_get_set(): - varnames = filter(lambda var: var not in ['self','kwargs','args'], - Figure.__init__.__code__.co_varnames) + varnames = filter(lambda var: var not in ['self', 'kwargs', 'args'], + Figure.__init__.__code__.co_varnames) fig = plt.figure() for var in varnames: # if getattr fails then the getter and setter does not exist - getfunc = getattr(fig,f"get_{var}") - setfunc = getattr(fig,f"set_{var}") - + getfunc = getattr(fig, f"get_{var}") + setfunc = getattr(fig, f"set_{var}")