Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Unifying the Figure getter/setter interface to match its constructor #21549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 286 additions & 28 deletions 314 lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -1191,6 +1192,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)
Expand All @@ -1204,6 +1210,65 @@ 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={}):
"""
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 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`

See Also
--------
matplotlib.figure.Figure.subplots_adjust
matplotlib.figure.Figure.get_subplotpars
"""
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 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):
"""
Align the xlabels of subplots in the same subplot column if label
Expand Down Expand Up @@ -2231,24 +2296,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
Expand Down Expand Up @@ -2299,15 +2346,11 @@ 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 = []
Expand Down Expand Up @@ -2399,11 +2442,172 @@ def _set_dpi(self, dpi, forward=True):

dpi = property(_get_dpi, _set_dpi, doc="The resolution in dots per inch.")

@property
def layout(self):
"""
Return the current figure layout solver.
"""
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 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) 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*, 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
----------
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 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 (
layout is None and
tight_layout is None and
constrained_layout is 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

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}'!=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.")
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.")
else:
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)

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.

Expand All @@ -2429,7 +2633,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.
Expand Down Expand Up @@ -2684,6 +2888,60 @@ def get_size_inches(self):
"""
return np.array(self.bbox_inches.p1)

def set_figsize(self, w, h=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably just use cbook._define_aliases (see other uses in the library).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @anntzer. I made the requested change in the newest commit. Also updated the tests to match pep8.

"""
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
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.