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

figure changes size at end of loop if drawn dynamically #17

Open
lucainnocenti opened this issue Aug 21, 2017 · 15 comments
Open

figure changes size at end of loop if drawn dynamically #17

lucainnocenti opened this issue Aug 21, 2017 · 15 comments
Milestone

Comments

@lucainnocenti
Copy link

As per the title, consider the following snippet:

import time
import ipympl
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 1, figsize=(5, 5))
data = []
plt.show()
for idx in range(4):
    data.append(idx ** 2)
    ax.clear()
    ax.plot(data)
    fig.canvas.draw()
    time.sleep(0.2)

and this is what I get running it:

gyrodown

I used plt.show() at the beginning of the loop because nothing gets drawn otherwise.
Is there a way to avoid this?

@tacaswell
Copy link
Member

Do you have high-dpi display?

@lucainnocenti
Copy link
Author

I do, is that the problem?

@tacaswell
Copy link
Member

It shouldn't be a problem, but it is :)

The way that the high-dpi displays are handled is by adding a layer of 'virtual pixels' that unless you opt-out just 'zooms' your bitmaps by 2x. What looks like is happening here is that the js side is correctly opting out, but it is not being threaded through to matplotlib to render the image and double the 'virtual' dpi until after the cell is finished executing.

Until we sort this out splitting everything after plt.show() into a second cell may help.

@tacaswell tacaswell modified the milestone: 0.1 Aug 26, 2017
@lucainnocenti
Copy link
Author

thanks for the comment @tacaswell. What do you mean exactly by "splitting evething (...) into a second cell"?

@tacaswell
Copy link
Member

I mean put it in a second cell so the first cell creates and show the figure, the second updates it.

@wjakob
Copy link

wjakob commented Aug 19, 2018

I am also running into this issue -- exactly the same plotting mechanism and symptoms (on the latest Anaconda). It would be nice if it wasn't necessary to split the plots in this way when using Retina displays (which is basically all macs nowadays).

@tacaswell
Copy link
Member

@wjakob The parameter that controls this is https://github.com/matplotlib/jupyter-matplotlib/blob/master/ipympl/backend_nbagg.py#L141 .

I suspect what is happening is:

  • you call show which creates the figure
  • the js side sends a message back to adjust the DPI
  • but the event loop is blocked running your code which loops through and and updates the plot
  • after you loop is done the tornado event loop processes the message to update the DPI ratio which triggers a re-draw which shows you the full size figure.

One (very hackish) solution is to do fig.canvas._dpi_ratio = 2 and just hard-code you are in a hi-dpi enviroment. The more proper solution is to find a way to let the underlying event loop spin, but I do not know how to do that...

@tiehfood
Copy link

any solution to this problem? fig.canvas._dpi_ratio = 2 doesn't change anything to me

@tacaswell
Copy link
Member

@tiehfood I think someone needs to look into the communications between the js front end and the python side to sort out when the dpi is negotiated, would you be interested in trying?

The revelant code is likely in https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/backend_webagg_core.py and https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/backend_nbagg.py

@tiehfood
Copy link

I am no code expert and I have just access to the jupyter front end in this case...

@martinRenou
Copy link
Member

martinRenou commented Jul 2, 2019

I tried to find the reason for this issue. I added print statements to the messages handling Python side, and it appears that all the messages (i.e. initialized message, set_dpi_ratio message, resize message) are received/handled only at the end of the animation... I don't know what is the reason for that. Maybe you have an idea @tacaswell ?

@martinRenou
Copy link
Member

As we are not using the tornado application with ipympl, I suspect the way to fix it would be to get rid of it on the backend

@malbergo
Copy link

malbergo commented Dec 3, 2020

Any updates on this front?

@KIC
Copy link

KIC commented Jan 4, 2021

This bug is now 3 years old and I still have this issue. Are there any plans how this can be fixed?

@Wittline
Copy link

Hi Guys,

I was facing the same issue, I was creating different plots into the same cell using a loop, the way I fixed it was putting the fig = plt.figure(figsize=(20, 10)) inside the loop. Now all the plots has the same size into the execution of the same cell. I had it out of the loop before.

Check the example below:

image

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

No branches or pull requests

9 participants