Skip to content

[Bug]: get_backend() clears figures from Gcf.figs if they were created under rc_context #23298

Closed

Description

@drammock

Bug summary

calling matplotlib.get_backend() removes all figures from Gcf if the first figure in Gcf.figs was created in an rc_context.

Code for reproduction

import matplotlib.pyplot as plt
from matplotlib import get_backend, rc_context

# fig1 = plt.figure()  # <- UNCOMMENT THIS LINE AND IT WILL WORK
# plt.ion()            # <- ALTERNATIVELY, UNCOMMENT THIS LINE AND IT WILL ALSO WORK
with rc_context():
    fig2 = plt.figure()
before = f'{id(plt._pylab_helpers.Gcf)} {plt._pylab_helpers.Gcf.figs!r}'
get_backend()
after = f'{id(plt._pylab_helpers.Gcf)} {plt._pylab_helpers.Gcf.figs!r}'

assert before == after, '\n' + before + '\n' + after

Actual outcome

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-1-fa4d099aa289> in <cell line: 11>()
      9 after = f'{id(plt._pylab_helpers.Gcf)} {plt._pylab_helpers.Gcf.figs!r}'
     10 
---> 11 assert before == after, '\n' + before + '\n' + after
     12 

AssertionError: 
94453354309744 OrderedDict([(1, <matplotlib.backends.backend_qt.FigureManagerQT object at 0x7fb33e26c220>)])
94453354309744 OrderedDict()

Expected outcome

The figure should not be missing from Gcf. Consequences of this are, e.g, plt.close(fig2) doesn't work because Gcf.destroy_fig() can't find it.

Additional information

No response

Operating system

Xubuntu

Matplotlib Version

3.5.2

Matplotlib Backend

QtAgg

Python version

Python 3.10.4

Jupyter version

n/a

Installation

conda

Activity

  1. tacaswell commented on Jun 18, 2022

    @tacaswell
    Member

    My knee-jerk guess is that :

    • the rcParams['backend'] in the auto-sentinel
    • that is stashed by rc_context
    • if you do the first thing to force the backend to be resolved in the context manager it get changes
    • the context manager sets it back to the sentinel an the way out
    • get_backend() re-resolves the backend which because it changes the backend it closes all of the figures

    This is probably been a long standing latent bug, but was brought to the front when we made the backend resolution lazier.

  2. added this to the v3.6.0 milestone on Jun 18, 2022
  3. tacaswell commented on Jun 18, 2022

    @tacaswell
    Member

    That is indeed the problem. I do not see an easy way to fix this that we can backport to 3.5.x, PR coming with a way to fix this for 3.6....

  4. added 2 commits that reference this issue on Jun 18, 2022
    97fcbd6
    7fce03e
  5. kailizcatman commented on Jul 23, 2022

    @kailizcatman

    I encountered this bug when using matplotlib (3.5.2) indirectly via seaborn. Before my environment is updated with matplotlib 3.6, what would you recommend as a workaround for this bug? The workaround should preferably have as little side effect as possible.

  6. tacaswell commented on Jul 24, 2022

    @tacaswell
    Member

    Adding

    import matplotlib
    matplotlib.get_backend()
    del matplotilb 

    should force the backend resolution to work around this issue and have no other side effects. This only needs to be done once per process.

  7. kailizcatman commented on Jul 24, 2022

    @kailizcatman

    Thank you.

  8. jklymak commented on Jul 24, 2022

    @jklymak
    Member

    But also seaborn need not use a context manager here?

  9. mwaskom commented on Jul 30, 2022

    @mwaskom

    But also seaborn need not use a context manager here?

    ?

  10. jklymak commented on Jul 30, 2022

    @jklymak
    Member

    I think seaborn can turn the layout off (fig.set_tight_layout(False)). I guess if you want it to turn back on, you could save the old state and toggle it back on.

    I guess philosophically I don't think of rcParams as something downstream libraries should be changing, but rather defaults that the user sets. However I appreciate that there is a counter current in the project of thinking of rcParams as a global state for the library that gets manipulated at will, and I can see how the context manager helps encourage that. However, I'm just not convinced it is a good idea given the number of weird side effects it can produce.

  11. mwaskom commented on Jul 30, 2022

    @mwaskom

    The rcParams very much are "a global state that can be manipulated at will" so if doing so can produce "weird side effects", it seems important for matplotlib to clearly document them.

  12. added 2 commits that reference this issue on Apr 19, 2026
    2f87ad1
    fa82856
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions