Skip to content

Commit bc31177

Browse files
committed
ENH: Allow to register standalone figures with pyplot
It may be fundamentally nice not to have to create the figure though pyplot to be able to use it in pyplot afterwards. You can now do ``` from matplotlib.figure import Figure import matplotlib.pyplot as plt fig = Figure() fig.subplots().plot([1, 3, 2]) plt.figure(fig) # fig is now tracked in pyplot plt.show() ``` This also opens up the possibility to more dynamically track and untrack figures in pyplot, which opens up the road to optimized figure tracking in pyplot (#29849)
1 parent 011d12f commit bc31177

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

lib/matplotlib/pyplot.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,10 @@ def figure(
933933
window title is set to this value. If num is a ``SubFigure``, its
934934
parent ``Figure`` is activated.
935935
936+
If *num* is a Figure instance that is already tracked in pyplot, it is
937+
activated. If *num* is a Figure instance that is not tracked in pyplot,
938+
it is added to the tracked figures and activated.
939+
936940
figsize : (float, float) or (float, float, str), default: :rc:`figure.figsize`
937941
The figure dimensions. This can be
938942
@@ -1019,21 +1023,32 @@ def figure(
10191023
in the matplotlibrc file.
10201024
"""
10211025
allnums = get_fignums()
1026+
next_num = max(allnums) + 1 if allnums else 1
10221027

10231028
if isinstance(num, FigureBase):
10241029
# type narrowed to `Figure | SubFigure` by combination of input and isinstance
1030+
has_figure_property_parameters = (
1031+
any(param is not None for param in [figsize, dpi, facecolor, edgecolor])
1032+
or not frameon or kwargs
1033+
)
1034+
10251035
root_fig = num.get_figure(root=True)
10261036
if root_fig.canvas.manager is None:
1027-
raise ValueError("The passed figure is not managed by pyplot")
1028-
elif (any(param is not None for param in [figsize, dpi, facecolor, edgecolor])
1029-
or not frameon or kwargs) and root_fig.canvas.manager.num in allnums:
1037+
if has_figure_property_parameters:
1038+
raise ValueError(
1039+
"You cannot pass figure properties when calling figure() with "
1040+
"an existing Figure instance")
1041+
backend = _get_backend_mod()
1042+
manager_ = backend.new_figure_manager_given_figure(next_num, root_fig)
1043+
_pylab_helpers.Gcf._set_new_active_manager(manager_)
1044+
return manager_.canvas.figure
1045+
elif has_figure_property_parameters and root_fig.canvas.manager.num in allnums:
10301046
_api.warn_external(
10311047
"Ignoring specified arguments in this call because figure "
10321048
f"with num: {root_fig.canvas.manager.num} already exists")
10331049
_pylab_helpers.Gcf.set_active(root_fig.canvas.manager)
10341050
return root_fig
10351051

1036-
next_num = max(allnums) + 1 if allnums else 1
10371052
fig_label = ''
10381053
if num is None:
10391054
num = next_num

lib/matplotlib/tests/test_figure.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,6 @@ def test_figure_label():
147147
assert plt.get_figlabels() == ['', 'today']
148148
plt.figure(fig_today)
149149
assert plt.gcf() == fig_today
150-
with pytest.raises(ValueError):
151-
plt.figure(Figure())
152150

153151

154152
def test_figure_label_replaced():

lib/matplotlib/tests/test_pyplot.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,30 @@ def test_multiple_same_figure_calls():
471471
assert fig is fig3
472472

473473

474+
def test_register_existing_figure_with_pyplot():
475+
from matplotlib.figure import Figure
476+
# start with a standalone figure
477+
fig = Figure()
478+
assert fig.canvas.manager is None
479+
with pytest.raises(AttributeError):
480+
# Heads-up: This will change to returning None in the future
481+
# See docstring for the Figure.number property
482+
fig.number
483+
# register the Figure with pyplot
484+
plt.figure(fig)
485+
assert fig.number == 1
486+
# the figure can now be used in pyplot
487+
plt.suptitle("my title")
488+
assert fig.get_suptitle() == "my title"
489+
# it also has a manager that is properly wired up in the pyplot state
490+
assert plt._pylab_helpers.Gcf.get_fig_manager(fig.number) is fig.canvas.manager
491+
# and we can regularly switch the pyplot state
492+
fig2 = plt.figure()
493+
assert fig2.number == 2
494+
assert plt.figure(1) is fig
495+
assert plt.gcf() is fig
496+
497+
474498
def test_close_all_warning():
475499
fig1 = plt.figure()
476500

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy