Skip to content
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

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

Open
jdkloe opened this issue Mar 26, 2024 · 6 comments · May be fixed by #27992
Open

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

jdkloe opened this issue Mar 26, 2024 · 6 comments · May be fixed by #27992

Comments

@jdkloe
Copy link

jdkloe commented Mar 26, 2024

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

@timhoffm
Copy link
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.

@jdkloe
Copy link
Author

jdkloe commented Mar 26, 2024

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()

@WeatherGod
Copy link
Member

WeatherGod commented Mar 26, 2024 via email

@tacaswell
Copy link
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?

@timhoffm
Copy link
Member

timhoffm commented Mar 26, 2024

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.

@tacaswell
Copy link
Member

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

I agree with this proposal.

@Impaler343 Impaler343 linked a pull request Mar 29, 2024 that will close this issue
3 tasks
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

Successfully merging a pull request may close this issue.

4 participants