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

Missing axes and background when using Gtk3Agg backend and animations in a GtkNotebook #3758

Closed
timovwb opened this issue Nov 5, 2014 · 6 comments

Comments

@timovwb
Copy link
Contributor

timovwb commented Nov 5, 2014

I have multiple notebook tabs in my application where one holds a matplotlib graph made with the Gtk3Agg backend. It has multiple subplots which are animated with the builtin functions. Switching to the tab with the graph for the first time is not a problem, but there are missing axes when going back.

Here's a modified example from the website which illustrates the problem.

import numpy as np
import matplotlib as mpl
import matplotlib.animation as animation
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas

from gi.repository import Gtk

class TestWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.resize(600, 400)

        notebook = Gtk.Notebook()
        notebook.append_page(self.build_text_page(), None)
        notebook.append_page(self.build_graph_page(), None)
        self.add(notebook)
        self.show_all()

    def build_text_page(self):
        text = """
            Switch the notebook tabs to see the graph background and some axes disappear. 
        """
        label = Gtk.Label(label=text)
        return label

    def build_graph_page(self):
        figure = mpl.figure.Figure()
        canvas = FigureCanvas(figure)

        x = np.arange(0, 2*np.pi, 0.01)

        ax1 = figure.add_subplot(121)
        line1, = ax1.plot(x, np.sin(x))

        ax2 = figure.add_subplot(122)
        line2, = ax2.plot(x, np.sin(x))

        def animate(i):
            line1.set_ydata(np.sin(x+i/10.0))
            line2.set_ydata(np.sin(x+i/10.0))
            return line1, line2

        def init():
            line1.set_ydata(np.ma.array(x, mask=True))
            line2.set_ydata(np.ma.array(x, mask=True))
            return line1, line2

        self.ani = animation.FuncAnimation(figure, animate, np.arange(1, 200), init_func=init,
                                           interval=25, blit=True)
        return canvas

if __name__ == "__main__":
    win = TestWindow()
    win.connect("delete-event", Gtk.main_quit)
    Gtk.main()
@WeatherGod
Copy link
Member

Try setting blit=False. If that works, then I suspect something is wonky
with the tabbing that is causing the blit code to lose the background
information. Personally, I think the whole blitting feature might need to
get ripped out sometime soon. It causes way more headaches than it solves
IMHO.

Cheers!
Ben Root

On Wed, Nov 5, 2014 at 11:48 AM, Timo notifications@github.com wrote:

I have multiple notebook tabs in my application where one holds a
matplotlib graph made with the Gtk3Agg backend. It has multiple subplots
which are animated with the builtin functions. Switching to the tab with
the graph for the first time is not a problem, but there are missing axes
when going back.

Here's a modified example from the website which illustrates the problem.

import numpy as npimport matplotlib as mplimport matplotlib.animation as animationfrom matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
from gi.repository import Gtk
class TestWindow(Gtk.Window):
def init(self):
Gtk.Window.init(self)
self.resize(600, 400)

    notebook = Gtk.Notebook()
    notebook.append_page(self.build_text_page(), None)
    notebook.append_page(self.build_graph_page(), None)
    self.add(notebook)
    self.show_all()

def build_text_page(self):
    text = """            Switch the notebook tabs to see the graph background and some axes disappear.         """
    label = Gtk.Label(label=text)
    return label

def build_graph_page(self):
    figure = mpl.figure.Figure()
    canvas = FigureCanvas(figure)

    x = np.arange(0, 2*np.pi, 0.01)

    ax1 = figure.add_subplot(121)
    line1, = ax1.plot(x, np.sin(x))

    ax2 = figure.add_subplot(122)
    line2, = ax2.plot(x, np.sin(x))

    def animate(i):
        line1.set_ydata(np.sin(x+i/10.0))
        line2.set_ydata(np.sin(x+i/10.0))
        return line1, line2

    def init():
        line1.set_ydata(np.ma.array(x, mask=True))
        line2.set_ydata(np.ma.array(x, mask=True))
        return line1, line2

    self.ani = animation.FuncAnimation(figure, animate, np.arange(1, 200), init_func=init,
                                       interval=25, blit=True)
    return canvas

if name == "main":
win = TestWindow()
win.connect("delete-event", Gtk.main_quit)
Gtk.main()


Reply to this email directly or view it on GitHub
#3758.

@timovwb
Copy link
Contributor Author

timovwb commented Nov 5, 2014

Thanks, blit=False works indeed. Problem is I have 12 subplots in my application and the CPU usage is a lot higher this way.

I can connect to the GTK map event which is fired each time the graph is shown on screen and do a complete draw() in that handler. This has a small delay before everything appears again and doesn't work each time though.

Do other backends have the same issue or is something missing in the GTK backend?

@tacaswell
Copy link
Member

Blitting is a bit of black-magic as it involves reaching in and touching the pixel buffer being used to draw the GUI to the screen and can be a tad brittle. I suspect what is going on here is that the blit caches are not getting invalidated/recreated correctly, but being should would involve tracing through your gui + the animation code.

Have a look at the code in 'Animation._handle_resize`, my guess is you need to do something like that.

@tacaswell tacaswell added this to the unassigned milestone Nov 25, 2014
@tacaswell
Copy link
Member

Can you register a call back with gtk to fire on tab-switch to force a full-redraw of the canvas? A quick test if this will work is if you re-size the window after you switch tabs if the plots fix them selves.

@timovwb
Copy link
Contributor Author

timovwb commented Nov 25, 2014

Yes, GTK has a map signal which is emitted when a widget is visible. Adding the following lines fixes the problem, but not very reliably.

        def on_map(widget):
            widget.draw_idle()
        canvas.connect("map", on_map)

This particular example only works with draw_idle, not draw. Switching quickly between tabs doesn't force a redraw. It works a bit more reliable in my application, but there's a small visible delay before the redraw. This might be because it's a graph with 12 subplots though, I'll need to check this further if needed.

@tacaswell
Copy link
Member

I am a bit confused why you need to use draw_idle.

You might also want to push any computation you are doing off to a second thread to make sure the event loop is idle often enough.

@timovwb I am going to close this issue as it isn't clear to me if there is a bug in mpl. The user mailing list might be a better place to continue this discussion as it has a wider audience. If you disagree, ping me.

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

3 participants