python matplotlib blit to axes or sides of the figure?
Asked Answered
A

1

8

I'm trying to refresh some plots that I have within a gui everytime I go once through a fitting procedure. Also, these plots are within a framw which can be resized, so the axes and labels etc need to be redrawn after the resizing. So was wondering if anyone knew how to update the sides of a figure using something like plot.figure.canvas.copy_from_bbox and blit. This appears to only copy and blit the background of the graphing area (where the lines are being drawn) and not to the sides of the graph or figure (where the labels and ticks are). I have been trying to get my graphs to update by trial and error and reading mpl documentation, but so far my code has jst become horrendously complex with things like self.this_plot.canvas_of_plot..etc.etc.. .plot.figure.canvas.copy_from_bbox... which is probably far too convoluted. I know that my language might be a little off but I've been trying to read through the matplotlb documentation and the differences between Figure, canvas, graph, plot, figure.Figure, etc. are starting to evade me. So my first and foremost question would be:

1 - How do you update the ticks and labels around a matplotlib plot.

and secondly, since I would like to have a better grasp on what the answer to this question,

2 - What is the difference between a plot, figure, canvas, etc. in regards to the area which they cover in the GUI.

Thank you very much for the help.

Ahlers answered 13/2, 2013 at 0:6 Comment(0)
C
24

All this can certainly be rather confusing at first!

To begin with, if you're chaining the ticks, etc, there isn't much point in using blitting. Blitting is just a way to avoid re-drawing everything if only some things are changing. If everything is changing, there's no point in using blitting. Just re-draw the plot.

Basically, you just want fig.canvas.draw() or plt.draw()

At any rate, to answer your first question, in most cases you won't need to update them manually. If you change the axis limits, they'll update themselves. You're running into problems because you're blitting just the inside of the axes instead of redrawing the plot.

As for your second question, a good, detailed overview is the Artist Tutorial of the Matplotlib User's Guide.

In a nutshell, there are two separate layers. One deals with grouping things into the parts that you'll worry about when plotting (e.g. the figure, axes, axis, lines, etc) and another that deals with rendering and drawing in general (the canvas and renderer).

Anything you can see in a matplotlib plot is an Artist. (E.g. text, a line, the axes, and even the figure itself.) An artist a) knows how to draw itself, and b) can contain other artists.

For an artist to draw itself, it uses the renderer (a backend-specific module that you'll almost never touch directly) to draw on a FigureCanvas a.k.a. "canvas" (an abstraction around either a vector-based page or a pixel buffer). To draw everything in a figure, you call canvas.draw().

Because artists can be groups of other artists, there's a hierarchy to things. Basically, something like this (obviously, this varies):

Figure
    Axes (0-many) (An axes is basically a plot)
        Axis (usually two) (x-axis and y-axis)
            ticks
            ticklabels
            axis label
         background patch
         title, if present
         anything you've plotted, e.g. Line2D's

Hopefully that makes things a touch clearer, anyway.

If you really do want to use blitting to update the tick labels, etc, you'll need to grab and restore the full region including them. This region is a bit tricky to get, because it isn't exactly known until after draw-time (rendering text in matplotlib is more complicated than rendering other things due to latex support, etc). You can do it, and I'll be glad to give an example if it's really what you want, but it's typically not going to yield a speed advantage over just drawing everything. (The exception is if you're only updating one subplot in a figure with lots of subplots.)

Certainty answered 13/2, 2013 at 3:54 Comment(7)
Thank you very much for this wonderful summary of matplotlib elements. I know that this will be useful for me and many other on the web as a reference to understand the overall structure of the module.Ahlers
This is excellent. I have been searching for 2 years for a good summary of how the Fig/Axes/Axis classes are supposed to relate!Smoothbore
I would like to see your example where a single subplot is updated. Could you extend your answer with that?Shaniceshanie
@JoeKington I disagree with the idea that blitting is useless when changing ticks, etc. Imagine you have a shifting graph with random data in it. Most artists will have to be redrawn except the xlabel, ylabel, title, and legend, so if we can squeeze some extra performance and smoothness for free that's good to take.Ambidextrous
I am working on a MRE for myself but will eventually post it on SO as a self-answered question. Embedded in PyQt5, the speed advantage is there (200 fps instead of 50) when the new data does not nudge the x/y limits. Interestingly in plain old matplotlib I get 200 fps even when the limits and labels are changed live.Ambidextrous
@Ambidextrous sounds pretty interesting, did you manage to upload the example to SO or are you willing to share the code through other channels?Wilkes
@Ambidextrous thank you! I kind of solved my issue by moving live plotting to a way more powerful machine :-D but I'm still very interested nonetheless. Don't feel pressured to finish it for me though ;-)Wilkes

© 2022 - 2024 — McMap. All rights reserved.