Skip to content

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

Closed

Description

@juhuebner

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

Activity

  1. tacaswell commented on Jul 29, 2022

    @tacaswell
    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.

  2. juhuebner commented on Jul 29, 2022

    @juhuebner
    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.

  3. tacaswell commented on Jul 29, 2022

    @tacaswell
    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.

  4. juhuebner commented on Aug 3, 2022

    @juhuebner
    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
    
  5. tacaswell commented on Aug 3, 2022

    @tacaswell
    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

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