Skip to content

[Bug]: strange behaviour when redefining figure size #27978

Closed

Description

@jdkloe

Bug summary

setting figure size using the figsize parameter to matplotlib.pyplot.figure works just fine, but setting it to a different value in the same script fails in case the first argument to the figure call is an identifier.

Code for reproduction

import matplotlib.pyplot
# first call
fig = matplotlib.pyplot.figure(1,figsize=(1,2))
fig.get_figheight()
fig.get_figwidth()
# second call
fig = matplotlib.pyplot.figure(1,figsize=(3,4))
fig.get_figheight()
fig.get_figwidth()

Actual outcome

>>> import matplotlib.pyplot
>>> # first call
>>> fig = matplotlib.pyplot.figure(1,figsize=(1,2))
Qt: Session management error: Could not open network socket
>>> fig.get_figheight()
2.0
>>> fig.get_figwidth()
1.0
>>> # second call
>>> fig = matplotlib.pyplot.figure(1,figsize=(3,4))
>>> fig.get_figheight()
2.0
>>> fig.get_figwidth()
1.0
>>> 

Expected outcome

The second call should change the figure size and the get_figheight/get_figwidth methods should report the changed size.

Additional information

Note that the problem does not occur if no identifier is provided to the figure call, so this works just fine:

fig = matplotlib.pyplot.figure(figsize=(3,4))
fig.get_figheight()
fig.get_figwidth()

Operating system

Fedora 39 linux

Matplotlib Version

3.8.2

Matplotlib Backend

QtAgg

Python version

Python 3.12.2

Jupyter version

n.a.

Installation

Linux package manager

Activity

  1. timhoffm commented on Mar 26, 2024

    @timhoffm
    Member

    figure(1, ...) returns a figure with the given id if that exists, or creates one if not.

    The second call just returns the same figure again. Kim against modifying an existing figure through the interface. We may discuss whether we want to warn on that. I think a recall should not have any parameters. Currently, they are ignored. The only downside would be that you can now do the exact same call twice. But I argue that creation and recall are fundamentally different and the user should know which one they want. (This does not improve the situation for. the no kwargs case, but at least does not yield a figure other than expected.

  2. jdkloe commented on Mar 26, 2024

    @jdkloe
    Author

    Well, this behaviour clearly surprised me, and it took me some time to find the issue when working on some code that I did not write myself.
    Yes, I think it would be good to issue a warning if a user tries to add additional parameters on a second call.
    The syntax of the call suggests that this is an instantiation of a class and therefore would create a new figure with new settings, but clearly this is not the case for the second call.
    I think it would be much more clear if there was a second function, called something like get_figure(identifier) to retrieve an already existing figure. Without identifier it could just be the same as gcf()

  3. WeatherGod commented on Mar 26, 2024

    @WeatherGod
    Member
  4. tacaswell commented on Mar 26, 2024

    @tacaswell
    Member

    I agree we should we warning if user input is ignored. I have a vague memory that we have talked about this before but got stuck on what should we do in the case of

    import matplotlib.pyplot
    # first call
    fig = matplotlib.pyplot.figure(1,figsize=(1,2))
    fig.get_figheight()
    fig.get_figwidth()
    # second call
    fig = matplotlib.pyplot.figure(1,figsize=(1,2))
    fig.get_figheight()
    fig.get_figwidth()

    On one hand, we should warn because we are reusing the figure and ignoring all of the users input, on the other hand the values match the values that are already on the existing figure so we should not warn because they actually got what the wanted.

    It is possible I may be remembering a similar discussion about reusing existing axes?

  5. timhoffm commented on Mar 26, 2024

    @timhoffm
    Member

    I can see an argument to warn also for a second identical call with kwargs: while you get the same type of figure, in any non-trivial use case, you‘ll get an empty figure for the first call and a non-empty figure for the second call. These are so fundamentally different that it‘s unlikely you can work with them correctly if you don‘t know from context which one you’ll get. And if you know the figure exists, figure(N) just means „make figure N active“ no need to repeat its arguments. Also since this is likely used interactively, the short version without arguments is more convenient.

    --

    Edit: To give context: What options do we have?

    Do nothing at all

    Disadvantage: The above example: You call with an explicit parameter but get back something different

    >>> fig = plt.figure(1,figsize=(1,2))
    >>> fig = plt.figure(1,figsize=(3,4))
    >>> fig.get_figheight()
    2.0
    >>> fig.get_figwidth()
    1.0
    

    Only warn if the given parameters do not match

    Technical note: Detecting this correctly is somewhat cumbersome. You have to store the called parameters; and maybe normalize (e.g. positional vs. kwarg usage).

    Usability note: Would we require to replicate all args for the recall, or should we accept the bare figure(1) as well even if the first call had the arguments? - IMHO clearly the second. This is primarily for interactive use and forcing to type out all kwargs again would be annoying.

    Always warn if parameters are given for a recall.

    While one could argue that plt.figure(1) returning a figure with non-standard parameters is surprising, you really don't know what you are getting from the code because lots of configuration is determined by rcParams.

    Second, as stated above, recall is mainly for interactive usage, so the short version is desireable, and nobody should need to type out the parameters again. So warning on two identical kwarg calls is ok - it may even be helpful, because you may think you get a new figure, but you don't.


    Overall for simplicity and safety, I propose to always warn if parameters are given for a recall.

  6. tacaswell commented on Mar 27, 2024

    @tacaswell
    Member

    Overall for simplicity and safety, I propose to always warn if parameters are given for a recall.

    I agree with this proposal.

  7. added this to the v3.10.0 milestone on May 21, 2024
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