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

Create a sibling to pyplot.plot that garuntees the creation of a new figure #18248

Closed
ianhi opened this issue Aug 14, 2020 · 5 comments
Closed

Comments

@ianhi
Copy link
Contributor

ianhi commented Aug 14, 2020

Problem

pyplot.plot will only create a new figure if there are no active figures. Thus when I am in a jupyter notebook with the ipympl backend I often write the following snippet:

plt.figure()
plt.plot(...)

There are two issues, one of convenience and one of user confusion:

  1. I'd prefer to not have to write plt.figure every time I want a new figure to show up.
  2. The current situation can be confusing to new users see %matplotlib ipympl does not allow cell "re-plot" ? ipympl#248
    • In particular this breaks the expectation established by usage of the inline backend that plt.plot in a cell will always create a new figure

My examples are both jupyter centric as that is my primary environment, but it feels as though the proposed solutions would belong in matplotlib proper rather than a backend.

Proposed Solution

Create two new functions in pyplot: plot_figure and plot_subplots that are guaranteed to create a new figure and otherwise act like pyplot.plot. Below are two incomplete implementations that I have been using.

def plot_figure(*args, **kwargs):
    """
    Calls plt.figure() for you, and then acts like plt.plot
    """
    if 'figsize' in kwargs:
        fig = figure(kwargs['figsize'])
        del kwargs['figsize']
    else:
        fig = figure()
    lines = plt.plot(*args, **kwargs)
    return fig, lines

def plot_subplots(*args, **kwargs):
    """
    Calls plt.subplots() for you, and then acts like plt.plot
    """
    if 'figsize' in kwargs:
        fig, ax = plt.subplots(figsize=kwargs['figsize'])
        del kwargs['figsize']
    else:
        fig, ax = plt.subplots()
    lines = plt.plot(*args, **kwargs)
    return fig, ax, lines

Additional context and prior art

Something that would be nice but probably is not technically feasible is a matplotlib figure that is associated with a specific juptyer cell. The proposed solution approximates such a figure per cell behavior. I think this desire is residual from my having "grown up" as it were using the inline backend. There are now features that I want from the interactive backend, but old habits like expecting plt.plot to just create a figure die hard.

@QuLogic
Copy link
Member

QuLogic commented Aug 14, 2020

This special cases plot; what about hist or imshow or anything else? And if you have to learn a second copy of every function, why not use plt.figure? In short, I don't think this is all that much more convenient, unless you only plot single lines.

@timhoffm
Copy link
Member

timhoffm commented Aug 15, 2020

"Create a new figure when using a plotting command" is what the hold(False) machinery was for. That state would be preferable to having separate versions of every function. But hold overall was removed in #3070.

pyplot.plot will only create a new figure if there are no active figures.

That's exactly how pyplot is meant to work: Do everything on the active figure. For convenience, a new figure is created if there is no active figure.

In particular this breaks the expectation established by usage of the inline backend that plt.plot in a cell will always create a new figure

That's a misconception. Every cell creates a new figure. Personally, I find that more intuitive because a cell is a "unit of thought", but I cannot speak for expectations of others.

I'd prefer to not have to write plt.figure every time I want a new figure to show up. In practice, that shouldn't be needed too often if you use cells to structure your code. It's only need if you need multiple figures from a single cell. For certain applications using multple subplots may also be better than using multple figures.

@ianhi
Copy link
Contributor Author

ianhi commented Aug 16, 2020

Every cell creates a new figure. Personally, I find that more intuitive because a cell is a "unit of thought

That is a much better way of putting it. In fact I think that is really what I want, but I assumed it wouldn't be possible. Though given that the inline backend manages to do as much I imagine the the ipympl backend may also be able to. I will close this and potentially open an issue there to discuss how that might be possible to implement.

Thanks!

@ianhi ianhi closed this as completed Aug 16, 2020
@QuLogic
Copy link
Member

QuLogic commented Aug 18, 2020

In particular this breaks the expectation established by usage of the inline backend that plt.plot in a cell will always create a new figure

That's a misconception. Every cell creates a new figure. Personally, I find that more intuitive because a cell is a "unit of thought", but I cannot speak for expectations of others.

This is not quite right either. Every cell closes all open figures. This might seem like a meaningless distinction, but if you were to call plt.subplots(); plt.subplots(); plt.subplots(); in a cell, you would get back 3 inline figures. What opens the figure is any plotting call (plot, scatter, etc.), implicitly, and it does so for every cell because the previous cells closed their figures.

@tacaswell
Copy link
Member

@ianhi See matplotlib/ipympl#171 for a long discussion of what is going on and why it is a bit subtle to get right.

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

No branches or pull requests

4 participants