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

matplotlib plot does not fully render if an exception is raised before cell execution completes #2166

Closed
odedbd opened this issue Feb 9, 2017 · 11 comments

Comments

@odedbd
Copy link

odedbd commented Feb 9, 2017

I run the following in a notebook cell:

%matplotlib notebook
import matplotlib.pyplot as plt

def plot_something():
    plt.figure()
    plt.plot([0,2],[0,2],'-')
    plt.show()

plot_something()
raise Exception

Expected output:

  • an interactive figure created with the line x==y on range [0,2]
  • exception output (including a traceback).

Actual output:

  • an interactive figure is created, but the line is not rendered/visible
  • exception output (including traceback).

notebook_matplotlib_exception

Looking at the x,y prompt on the bottom right of the figure widget (attached screenshot) you can see that the axis range was set to [0,2] for both x & y. I have verified that by changing the plot parameters and checking that the top right corner x,y values change accordingly.

This issue is problematic when a cell executes a calculation which creates multiple figures. Any exception raised within the cell will prevent any plot from properly rendering, including the plots created before the exception was raised.

The issue is also exacerbated when the exception is raised in a following cell which gets invoked before the cell creating the plots completes execution. This is described in more detail in the SO question I posted.

I am not sure whether this belongs here or on matplotlib issues. I was unable to find a duplicate for this searching the issues for both.

Thanks!

@takluyver
Copy link
Member

@tacaswell ?

@tacaswell
Copy link

Adding plt.gcf().canvas.draw() in a subsequent cell re-draws it (but at the wrong size?!). My guess at what is going on here is that the notebook backend code is relying on the 'standard' clean-up of a cell to set some state / properly inject it's self into the dom and set up the web-sockets.

This behaves properly with ipympl (https://github.com/matplotlib/jupyter-matplotlib)

import ipympl
import matplotlib.pyplot as plt

def plot_something():
    plt.figure()
    plt.plot([0,2],[0,2],'-')
    plt.show()

plot_something()
raise Exception

Need to check with @SylvainCorlay if that is ready for prime-time yet and start advertising it!

@odedbd
Copy link
Author

odedbd commented Feb 15, 2017

@tacaswell - thank you for your suggestion. I upgraded matplotlib and install ipympl and it works almost as expected.

The behavior I am seeing is different for the first time I run the cell and the next times. It is also different for different level of browser zoom levels (I am using Chrome 56.0.2924.87 on Windows 8.1)-

First time that the cell is run -
The figure appears but is not fully rendered (see image)-
notebook_matplotlib_exception_ipympl
If I then resize the figure using the GUI (bottom right corner), the behavior changes based on browser zoom level-

  1. When using 100% zoom level (default), the figure is rendered too small. When in this state the zoom rectangle is drawn offset from the mouse pointer. The zooming is determined by the mouse pointer, it is just the drawing of the rectangle that is off.
  2. When using 90% zoom level (ctrl^- once), the figure is rendered to size and the zoom rectangle is working fine.

When I rerun the cell the figure is re-rendered properly without need for resizing and independent of zoom level.

Also, do you think there could be a workaround for this using matplotlib < 2.0 and nbAgg?

from playing around quickly with ipympl it seems taht while it looks really great, there are still some important issues in progress. for example closing figures when clearing cell input doesn't seem to work, so it is not drop-in replacement ready just yet. Also, I am unsure how quickly I can get our codebase to upgrade to matplotlib 2.0 so a solution using matplotlib 1.5.3 would be great.

@tacaswell
Copy link

There will be no more 1.5.x releases, so any fix would have to be locally applied.

Can you report those bugs again ipympl?

A vast majority of the the changes in 2.0 were style based. Unless you have some custom Image artists, it should be a smaller change than the normal minor releases (from an API point of view).

@odedbd
Copy link
Author

odedbd commented Apr 18, 2017

I'm not sure what's changed in my setup (still using matplotlib 1.5.3, could be that jupyter-client was upgraded, using 4.3) but calling plt.gcf().canvas.draw() now seems to work as expected. I can even use the following in a subsequent cell to draw several figures that were left unrendered due to an exception-

for fig_num in plt.get_fignums():
    plt.figure(fig_num).canvas.draw()

I am closing the issue as I can no longer reproduce it.

@tacaswell - if you can still reproduce this with some setup and think it's worthwhile to keep alive please reopen.

@odedbd odedbd closed this as completed Apr 18, 2017
@SergiyKolesnikov
Copy link

SergiyKolesnikov commented Aug 3, 2017

@odedbd Thanks for describing the cause of the problem and a workaround! Please reopen this issue, because the problem is still there and using plt.figure(fig_num).canvas.draw() is a non-obvious workaround.

In my notebook I had a lot of plots and the exception was thrown in one of the last cells that I used as scratch. The plots were not rendered when I ran 'restart kernel and run all cells' command and it was absolutely not obvious what caused the problem and how to deal with it. I wanted to report the bug and found your issue.

%matplotlib inline does not have this problem and all plots are rendered even if an exceptions is thrown before the rendering is completed.

matplotlib 2.0.2
jupyter-client 5.0.1
notebook 5.0.0
python 3.5

@odedbd odedbd reopened this Aug 7, 2017
@EricGallimore
Copy link

I'm currently running into this issue. plt.gcf().canvas.draw() is an effective workaround (thanks!), but I agree that it should be addressed.

I'm using:
matplotlib 2.1.1
jupyter-client 5.2.1
notebook 5.2.2
Python 3.5.2 on Ubuntu Server 16.04.3

I'm using %matplotlib ipympl, but I see the same behavior with %matplotlib notebook.

It seems like there is a timing or execution speed component related to when the exception is thrown relative to when figures get drawn.

I would welcome suggestions for further troubleshooting, since I'm not familiar enough with all the moving parts to make any progress. I can also provide access (privately) to a notebook server that shows this behavior if it would help diagnose this problem.

@tacaswell
Copy link

I think this issue should be closed with no action. fig.canvas.draw() is the standard way to force a re-draw of an interactive Matplotlib figure, it does not show up when using ipympl (which is properly integrated with the widgets framework), and this only shows up when something goes wrong enough that an exception is raised.

@takluyver takluyver added this to the Reference milestone Feb 6, 2018
@takluyver
Copy link
Member

OK, thanks.

@EricGallimore
Copy link

I'd like to propose we re-open this. It does occur using ipympl, and it's not clear to the user what's going on (until you Google long enough to find this issue).

@takluyver
Copy link
Member

I don't know the machinery involved very well, but it doesn't sound like there's anything to fix in IPython. Though if the ipympl or matplotlib maintainers identify a change that's needed in IPython, we can look at that.

It looks like @odedbd already opened an issue for ipympl: matplotlib/ipympl#10

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants