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

Windows are not shown with Tk + interactive mode, from matplotlib 3.4 #19935

Open
kngwyu opened this issue Apr 11, 2021 · 5 comments
Open

Windows are not shown with Tk + interactive mode, from matplotlib 3.4 #19935

kngwyu opened this issue Apr 11, 2021 · 5 comments
Labels
Milestone

Comments

@kngwyu
Copy link

kngwyu commented Apr 11, 2021

Bug report

Bug summary

The behavior of Tk backend in interactive mode has changed. My code depends on the old behavior and does not work with matplotlib 3.4.

Code for reproduction

import time

import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt


def test_heatmap_draw():
    mpl.use("TkAgg")
    plt.ion()

    DATA_SHAPE = 10, 10
    fig = plt.figure()
    ax = fig.add_subplot()
    img = ax.imshow(np.zeros(DATA_SHAPE), vmin=-1, vmax=1)

    for _ in range(10):
        img.set_data(np.random.uniform(-1, 1, DATA_SHAPE))
        fig.canvas.draw()
        time.sleep(0.1)


if __name__ == "__main__":
    test_heatmap_draw()

Actual outcome
No windows are shown with matplotlib >= 3.4.
I guess that #17789 is the trigger. Inserting self._master.update_idletasks worked, like:

class FigureCanvasTkAgg(FigureCanvasAgg, FigureCanvasTk):
    def draw(self):
        super().draw()
        self.blit()
        self._master.update_idletasks()

Expected outcome
The heatmap is interactively updated with matplotlib 3.3.4.

  • Is this change intended? Then I want to know a proper way to write this kind of app. I know that plt.pause(0.1) works, but actually don't want to pause in my actual use case.
  • If this is not intended, how could I fix backends in a reasonable way?

BTW, thank you for encouraging me on twitter.

@richardsheridan
Copy link
Contributor

richardsheridan commented Apr 11, 2021

My opinion is that this is the intended behavior. It is harmful to call update_idletasks or update in TCL library code for the reasons mentioned in that issue. However, client code should be free to use it. In this case the appropriate api, since you are driving your own event loop, is figure.canvas.flush_events which just calls update but in a backend-agnostic way.

Updating the docs would be very nice, I'll help where I can!

@kngwyu
Copy link
Author

kngwyu commented Apr 12, 2021

@richardjgowers
Thank you for your help! That makes sense.

For documents, I think the Explicitly spinning the Event Loop is enough good, but I feel the more entry-level description of interactive mode is somewhat confusing.
It says that:

If in interactive mode:
- newly created figures will be displayed immediately
- figures will automatically redraw when elements are changed
- pyplot.show() displays the figures and immediately returns

However, I guess that we need flush_events or some blocking functions to render images. Are these descriptions are simply outdated? Or, do I miss something?
Any help is greatly appricated.

@richardsheridan
Copy link
Contributor

richardsheridan commented Apr 12, 2021

A little farther down in that page there are some exceptions to those bullet points:

The GUI event loop being integrated with your command prompt and the figures being in interactive mode are independent of each other. If you use pyplot.ion but have not arranged for the event loop integration, your figures will appear but will not be interactive while the prompt is waiting for input.

and

Using figure.Figure.show it is possible to display a figure on the screen without starting the event loop and without being in interactive mode. This may work (depending on the GUI toolkit) but will likely result in a non-responsive figure.

I think it is a subtle and possibly confusing point that interactive mode is not interactive unless you are working in a command prompt with event loop integration. That is, if you run a script with matplotlib code such as what you posted above, you will have a different result of interactivity compared with typing each command at the REPL.In my mind, the thing you need to do to get interactivity is pump GUI events, and plt.ion just configures some of the pyplot API to "work better" at the REPL.

Perhaps bringing these facts forward in doc/users/interactive.rst before the bullet points would help?

@QuLogic
Copy link
Member

QuLogic commented Apr 13, 2021

        time.sleep(0.1)

You should replace this with plt.pause(0.1) to run the main loop.

@tacaswell tacaswell added this to the v3.5.0 milestone Apr 13, 2021
@kngwyu
Copy link
Author

kngwyu commented Apr 13, 2021

I think it is a subtle and possibly confusing point that interactive mode is not interactive unless you are working in a command prompt with event loop integration.

Right, I didn't actually understand that point.

Perhaps bringing these facts forward in doc/users/interactive.rst before the bullet points would help?

Thank you for the pointer. I would like also to mention that some backends behaved inconsistently on this point, but they are fixed.

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

No branches or pull requests

5 participants