Reputation: 4548
As part of a big GUI effort that is meant to plotting complex scientific figures I am trying to speed up interactions and figure updates. So far I've been using canvas.draw() method to update any changes to any drawn object in the figure. I won't be able to reproduce an example code as it's a thousands lines of code but this is a snapshot of what I am dealing with
the above figure is a fairly congested example image with 3 Axes, contour plot, path, arrow, png image, different transparency objects, shadows, lines, fills, colorbar, etc
normally a user will be playing with a GUI like the one above to add, delete update or modify any plotted object. For such a figure any modification is slow because it calls canvas.draw() at the backend.
#self.__canvas.Refresh()
#self.__canvas.Update()
###self.__canvas.update() # 'FigureCanvasWxAgg' object has no attribute 'update'
#self.__canvas.Refresh()
#self.__canvas.flush_events()
#self.__canvas.blit(self.__selectedAxes.bbox)
self.__canvas.draw()
I have tried using all the above but only canvas.draw results in updating the figure all the others won't. So far I am not sure how to speed up re-drawing the image after updating only one object.
Also, according to this post blit results in memory leaks. Did anyone tried to verify this hypothesis ?
Any suggestion is appreciated
Upvotes: 1
Views: 807
Reputation: 55
Instead of using self.__canvas.draw()
and redrawing all data on the plots, you can use blitting. By useage of blitting you can add specific new elements to a plot instead of redrawing the whole thing. This saves a massive amount of time.
In order to start blitting, the canvas has to be drawn at least once somewhere in your code. Otherwise there will be nothing 'to blit to'. So unfortunately you can't get fully rid of self.__canvas.draw()
.
To blit a certain element, for example a rectangle, you will first have to add the rectangle element to the axes. A rectangle is a matplotlib.patch and to add a patch to the axes you will have to use: self.axes.add_patch(rectangle)
. Once added you will need to draw it on the axes by using: self.axes.draw_artist(rectangle)
. After it has been drawn, you can blit it to the canvas using: self.canvas.blit(self.axes.bbox)
.
Save the plot with the blitted element as a background image using: self.background = self.canvas.copy_from_bbox(self.axes.bbox)
and restore it to your canvas using: self.canvas.restore_region(self.background)
.
Some example code that blits a Rectangle to the canvas:
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend.wxagg import FigureCanvasWxAgg as FigureCanvas
import wx
class Panel(wx.Frame):
wx.Frame.__init__(self, parent, id, 'Title')
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, proportion=1, flag= wx.ALL | wx.GROW)
"""Plot data and stuff to canvas...."""
self.canvas.draw()
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
square = matplotlib.patches.Rectangle((xPos,yPos), width, height)
self.canvas.restore_region(self.background)
self.axes.add_patch(square)
self.axes.draw_artist(square)
self.canvas.blit(self.axes.bbox)
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
Can be I made some typos. But you will get the idea of it.
Upvotes: 1