Skip to content

backend partially ignores "figure.figsize" in plt.rc_context in jupyter #23513

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
juhuebner opened this issue Jul 29, 2022 · 5 comments
Closed

Comments

@juhuebner
Copy link

juhuebner commented Jul 29, 2022

Bug summary

This possibly related to #20738

When I run the code below on a new jupyter kernel, only the tick styling is working. The figure.size and figure.dpi is ignored first.

One has to run something interacting with the backend first (like matplotlib.pyplot.show() ) in order to get plt.rc_context() working correctly.

Is this normal behavior, since the correct backend already seems to be activated or did I oversee something?

Code for reproduction

import matplotlib.pyplot as plt

rc = {"figure.figsize": [6, 1], "figure.dpi": 150, "xtick.direction": "in", "ytick.direction": "in"}

# Uncommenting this helps, but is this the intended behavoiur in jupyter?
# plt.show()

with plt.rc_context(rc):
    # Sanity check.
    print(f"{plt.rcParams['figure.figsize']=}")
    print(f"{plt.rcParams['figure.dpi']=}")
    print(f"{plt.rcParams['backend']=}")
    fig, ax = plt.subplots()

    # ax.plot(x, x)
    plt.show()

Actual outcome

plt.rcParams['figure.figsize']=[6.0, 1.0]
plt.rcParams['figure.dpi']=150.0
plt.rcParams['backend']='module://matplotlib_inline.backend_inline'

image

Expected outcome

Runnig the code twice, which has then plt.show() already called once delivers the correct output:
download

Additional information

No response

Operating system

No response

Matplotlib Version

3.5.2

Matplotlib Backend

module://matplotlib_inline.backend_inline

Python version

Python 3.9.7

Jupyter version

6.4.12

Installation

No response

@tacaswell
Copy link
Member

I suspect that this is fixed by ipython/matplotlib-inline#14

The interaction here is:

  • in mpl 3.5.2 we deferred importing the backend until we absolutely had to (this fixed some bugs with the Qt backend and has been a long-term goal) rather than at pyplot first import time
  • matplotlib-inline sets rcparams at it's import time

Due to the delayed import matplotlib-inline is now imported inside of the context manager which overrides your values (and which the context sets back to what it was before on exit which hides the state change!). The call to plt.show() fixes the problem because it forces the import to be earlier. Simlarly, running the cell a second time works because the module is already imported and hence does not change the rcparams.

Adding plt.get_backend() will also force the import and is the work-around I would go with for now (it should work on all versions of mpl / matplotlib-inline and is mostly harmless).

I am going to close this issue because we understand it and a fix has been merged downstream. Sorry we broke this on you.

@juhuebner
Copy link
Author

@tacaswell

Thank you very much for the really quick and insightful answer. However, when I put plt.get_backend() in-between the import and the context section, it has no effect like plt.show(). I noticed plt.clf() works as well. However, in both cases I don't know if I generate some potential pitfalls.

@tacaswell
Copy link
Member

One day I will learn to always test my suggestions before suggesting....

I (incorrectly) thought that you would be going through the backend fallback logic so checking the would do import the backend module, but there is actually a string already set so get_backend is fast and has no side effects 🤦🏻 .

Instead doing:

import matplotlib_inline  # side effect of changing the rcParams

will definitely import the module and trigger the rcparam changing logic.

@juhuebner
Copy link
Author

There is still something fishy with this import.

will definitely import the module and trigger the rcparam changing logic.

You are probably referring to https://github.com/ipython/matplotlib-inline/blob/f764b4354b2358aa001471215494d7dfdc505593/matplotlib_inline/backend_inline.py#L227

However, somewhere in the machinery the module already got imported, which then hinders the re-execution of _enable_matplotlib_integration()
You can see it via, e.g.,

import sys
sys.modules["matplotlib_inline"]

However, explicitly importing it into a new namespace works:

from matplotlib_inline import backend_inline

@tacaswell
Copy link
Member

I did not learn my lesson about testing in the post where I noted needing to learn my lesson about testing 🤦🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants