Skip to content

Multiple calls to matplotlib.pyplot.switch_backend #14329

@ianthomas23

Description

@ianthomas23

Whilst looking at #14311 I discovered that in many circumstances we are unnecessarily calling matplotlib.pyplot.switch_backend twice when we only need to do so once.

Reproducer (using current main branches of ipython, matplotlib and matplotlib-inline):

$ ipython
<snip>

In [1]: import matplotlib.pyplot as plt; plt.set_loglevel("debug")

In [2]: %matplotlib tk
DEBUG:matplotlib.pyplot:Loaded backend qtagg version 5.15.9.
DEBUG:matplotlib.pyplot:Loaded backend TkAgg version 8.6.

and in JupyterLab:

Screenshot from 2024-02-12 12-13-35

The cause is importing matplotlib_inline.backend_inline.configure_inline_support

from matplotlib_inline.backend_inline import configure_inline_support

before calling activate_matplotlib
pt.activate_matplotlib(backend)

There is a side-effect of importing backend_inline which is to call _enable_matplotlib_integration:
https://github.com/ipython/matplotlib-inline/blob/0f419e31f2c3ab70d6bf0f1cd5950f993e01e360/matplotlib_inline/backend_inline.py#L228
which can call matplotlib.pyplot.switch_backend with the wrong backend before we call it with the correct one.

The solution is to move the import of backend_inline to after the correct activate_matplotlib(backend) call and before configure_inline_support is called. This works locally for me manually testing in Jupyter and IPython. I'll submit a PR with this to run the full CI suite on it.

An alternative would be to remove the import side-effect in matplotlib-inline and lazily call _enable_matplotlib_integration, but this will change more code and is potentially more dangerous as other libraries may be relying on the existing call.

I think this is a duplicate of (or overlaps with) #14006 and ipython/matplotlib-inline#25. There is a PR for latter that has a different solution but it has stalled, awaiting input from a Matplotlib maintainer. I am a (occasional) Matplotlib maintainer, and I prefer this solution as it doesn't poke around in the internals of either matplotlib or matplotlib-inline so is less risky.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions