Skip to content

ENH: Allow to register standalone figures with pyplot #29855

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
23 changes: 19 additions & 4 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,10 @@
window title is set to this value. If num is a ``SubFigure``, its
parent ``Figure`` is activated.

If *num* is a Figure instance that is already tracked in pyplot, it is
activated. If *num* is a Figure instance that is not tracked in pyplot,
it is added to the the tracked figures and activated.

figsize : (float, float), default: :rc:`figure.figsize`
Width, height in inches.

Expand Down Expand Up @@ -990,21 +994,32 @@
in the matplotlibrc file.
"""
allnums = get_fignums()
next_num = max(allnums) + 1 if allnums else 1

if isinstance(num, FigureBase):
# type narrowed to `Figure | SubFigure` by combination of input and isinstance
has_figure_property_parameters = (
any(param is not None for param in [figsize, dpi, facecolor, edgecolor])
or not frameon or kwargs
)

root_fig = num.get_figure(root=True)
if root_fig.canvas.manager is None:
raise ValueError("The passed figure is not managed by pyplot")
elif (any(param is not None for param in [figsize, dpi, facecolor, edgecolor])
or not frameon or kwargs) and root_fig.canvas.manager.num in allnums:
if has_figure_property_parameters:
raise ValueError(

Check warning on line 1009 in lib/matplotlib/pyplot.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/pyplot.py#L1009

Added line #L1009 was not covered by tests
"You cannot pass figure properties when calling figure() with "
"an existing Figure instance")
backend = _get_backend_mod()
manager_ = backend.new_figure_manager_given_figure(next_num, root_fig)
_pylab_helpers.Gcf._set_new_active_manager(manager_)
return manager_.canvas.figure
elif has_figure_property_parameters and root_fig.canvas.manager.num in allnums:
_api.warn_external(
"Ignoring specified arguments in this call because figure "
f"with num: {root_fig.canvas.manager.num} already exists")
_pylab_helpers.Gcf.set_active(root_fig.canvas.manager)
return root_fig

next_num = max(allnums) + 1 if allnums else 1
fig_label = ''
if num is None:
num = next_num
Expand Down
2 changes: 0 additions & 2 deletions lib/matplotlib/tests/test_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ def test_figure_label():
assert plt.get_figlabels() == ['', 'today']
plt.figure(fig_today)
assert plt.gcf() == fig_today
with pytest.raises(ValueError):
plt.figure(Figure())


def test_figure_label_replaced():
Expand Down
24 changes: 24 additions & 0 deletions lib/matplotlib/tests/test_pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,30 @@ def test_multiple_same_figure_calls():
assert fig is fig3


def test_register_existing_figure_with_pyplot():
from matplotlib.figure import Figure
# start with a standalone figure
fig = Figure()
assert fig.canvas.manager is None
with pytest.raises(AttributeError):
# Heads-up: This will change to returning None in the future
# See docstring for the Figure.number property
fig.number
# register the Figure with pyplot
plt.figure(fig)
assert fig.number == 1
# the figure can now be used in pyplot
plt.suptitle("my title")
assert fig.get_suptitle() == "my title"
# it also has a manager that is properly wired up in the pyplot state
assert plt._pylab_helpers.Gcf.get_fig_manager(fig.number) is fig.canvas.manager
# and we can regularly switch the pyplot state
fig2 = plt.figure()
assert fig2.number == 2
assert plt.figure(1) is fig
assert plt.gcf() is fig


def test_close_all_warning():
fig1 = plt.figure()

Expand Down
Loading