Hi there,
Finally with lot of try I've finally managed to make blitting of a cmap
working.
I've also patched QT4agg backend, to make a redraw immediately.
(replaced self.draw by self.repaint)
In my current project I was able to stream a 655KB network stream, do
demodulation of an IQ stream and display the spectrogram in real time (4096
pixel per 1024) with matplotlib and QT4 backend, thx to the patch + blitting
example attached.
Without patch, the refrech was veeery long. (waiting for QT loop to execute
code wen it wanted.)
And do NOT always work. If you've got a powerfull pc you've got chance to
see only white background...
(or simply the loop timer to 0, you will see that without patch blit does
not work).
Only tested under windows currently, 'cause my project is on windows
currently...
There is one bug in the example, that I didn't manage to correct yet.
Depending on screen resolution, the color of the cmap blitted area can be
kind of alpha'ed. (that is look like a little bit transparent...) , Any idea
on the root of this issue?
By the way to make the example work I needed to do this:
self.ax2.draw_artist(self.line2)
self.blit(self.ax2.bbox)
self.restore_region(self.background2)
that is blit before restore... don't understand why yet.
Any comment welcomed.
Is there any chance, after review, to find a way to include this in main
trunk?
What do think about this?
Cheers,
Laurent
"""
Render to qt from agg
"""
from __future__ import division
import os, sys
import matplotlib
from matplotlib.figure import Figure
from backend_agg import FigureCanvasAgg
from backend_qt4 import QtCore, QtGui, FigureManagerQT, FigureCanvasQT,\
show, draw_if_interactive, backend_version, \
NavigationToolbar2QT
DEBUG = False
def new_figure_manager( num, *args, **kwargs ):
"""
Create a new figure manager instance
"""
if DEBUG: print 'backend_qtagg.new_figure_manager'
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass( *args, **kwargs )
canvas = FigureCanvasQTAgg( thisFig )
return FigureManagerQT( canvas, num )
class NavigationToolbar2QTAgg(NavigationToolbar2QT):
def _get_canvas(self, fig):
return FigureCanvasQTAgg(fig)
class FigureManagerQTAgg(FigureManagerQT):
def _get_toolbar(self, canvas, parent):
# must be inited after the window, drawingArea and figure
# attrs are set
if matplotlib.rcParams['toolbar']=='classic':
print "Classic toolbar is not supported"
elif matplotlib.rcParams['toolbar']=='toolbar2':
toolbar = NavigationToolbar2QTAgg(canvas, parent)
else:
toolbar = None
return toolbar
class FigureCanvasQTAgg( FigureCanvasQT, FigureCanvasAgg ):
"""
The canvas the figure renders into. Calls the draw and print fig
methods, creates the renderers, etc...
Public attribute
figure - A Figure instance
"""
def __init__( self, figure ):
if DEBUG: print 'FigureCanvasQtAgg: ', figure
FigureCanvasQT.__init__( self, figure )
FigureCanvasAgg.__init__( self, figure )
self.drawRect = False
self.rect = []
self.replot = True
self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
def drawRectangle( self, rect ):
self.rect = rect
self.drawRect = True
self.repaint( )
def paintEvent( self, e ):
"""
Draw to the Agg backend and then copy the image to the qt.drawable.
In Qt, all drawing should be done inside of here when a widget is
shown onscreen.
"""
#FigureCanvasQT.paintEvent( self, e )
if DEBUG: print 'FigureCanvasQtAgg.paintEvent: ', self, \
self.get_width_height()
# only replot data when needed
if type(self.replot) is bool: # might be a bbox for blitting
if self.replot:
FigureCanvasAgg.draw(self)
# matplotlib is in rgba byte order. QImage wants to put the bytes
# into argb format and is in a 4 byte unsigned int. Little endian
# system is LSB first and expects the bytes in reverse order
# (bgra).
if QtCore.QSysInfo.ByteOrder == QtCore.QSysInfo.LittleEndian:
stringBuffer = self.renderer._renderer.tostring_bgra()
else:
stringBuffer = self.renderer._renderer.tostring_argb()
qImage = QtGui.QImage(stringBuffer, self.renderer.width,
self.renderer.height,
QtGui.QImage.Format_ARGB32)
p = QtGui.QPainter(self)
p.drawPixmap(QtCore.QPoint(0, 0), QtGui.QPixmap.fromImage(qImage))
# draw the zoom rectangle to the QPainter
if self.drawRect:
p.setPen( QtGui.QPen( QtCore.Qt.black, 1, QtCore.Qt.DotLine ) )
p.drawRect( self.rect[0], self.rect[1], self.rect[2],
self.rect[3] )
p.end()
# we are blitting here
else:
bbox = self.replot
l, b, r, t = bbox.extents
w = int(r) - int(l)
h = int(t) - int(b)
t = int(b) + h
reg = self.copy_from_bbox(bbox)
stringBuffer = reg.to_string_argb()
qImage = QtGui.QImage(stringBuffer, w, h,
QtGui.QImage.Format_ARGB32)
pixmap = QtGui.QPixmap.fromImage(qImage)
p = QtGui.QPainter( self )
p.drawPixmap(QtCore.QPoint(l, self.renderer.height-t), pixmap)
p.end()
self.replot = False
self.drawRect = False
def draw( self ):
"""
Draw the figure when xwindows is ready for the update
"""
if DEBUG: print "FigureCanvasQtAgg.draw", self
self.replot = True
FigureCanvasAgg.draw(self)
self.update()
def blit(self, bbox=None):
"""
Blit the region in bbox
"""
self.replot = bbox
l, b, w, h = bbox.bounds
t = b + h
self.repaint(l, self.renderer.height-t, w, h)
def print_figure(self, *args, **kwargs):
FigureCanvasAgg.print_figure(self, *args, **kwargs)
self.draw()
import os
import sys
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.transforms as mtransforms
import matplotlib.cm as cm
from PyQt4 import QtCore, QtGui
ITERS = 100
import numpy as np
import time
class BlitQT(FigureCanvas):
def __init__(self):
FigureCanvas.__init__(self, Figure())
fig = self.figure
NUMBER_OF_DATA = 1024
self.x = np.arange(NUMBER_OF_DATA)
self.ax1 = fig.add_axes([0.1,0.7,0.8,0.2])
self.ax1.grid()
self.ax2 = fig.add_axes([0.1,0.4,0.8,0.2])
self.ax2.grid()
self.ax3 = fig.add_axes([0.1,0.1,0.8,0.2])
self.ax3.set_axis_bgcolor('k')
for l in self.ax3.get_xticklines() + self.ax3.get_yticklines():
l.set_markersize(0)
self._width = 1024
self._height = 256
self._draw_width = 1
self._draw_height = 4096
self.z = self.getZ()
self.old_size = self.ax1.bbox.width, self.ax1.bbox.height
self.cnt = 0
# create the initial lines
self.line1, = self.ax1.plot(self.x, self.getY(), 'r', animated=True,
lw=.5)
self.line2, = self.ax2.plot(self.x, self.getY(), animated=True, lw=.5)
self.line3 = self.ax3.imshow(self.z, interpolation='nearest',
cmap=cm.jet, animated = True, aspect=None, origin='lower')
self.line3.set_extent((self._width-1,0,0,self._height-1))
dx=8
self.ax3.set_xlim(-(self._width-1)+dx,dx)
self.draw()
self.background1 = self.copy_from_bbox(self.ax1.bbox)
self.background2 = self.copy_from_bbox(self.ax2.bbox)
self.background3 = self.copy_from_bbox(self.ax3.bbox)
self.tstart = time.time()
self.startTimer(0)
def getZ(self):
return np.random.random((self._draw_height,self._draw_width))
def get_bg_bbox(self, axe):
return axe.bbox#.padded(-3)
def getY(self):
return np.random.random_sample(1024)
def timerEvent(self, evt):
#if (self.cnt % 3) == 0:
current_size = self.ax1.bbox.width, self.ax1.bbox.height
if self.old_size != current_size:
self.old_size = current_size
self.ax1.clear()
self.ax1.grid()
self.ax2.clear()
self.ax2.grid()
self.ax3.clear()
for l in self.ax3.get_xticklines() + self.ax3.get_yticklines():
l.set_markersize(0)
self.draw()
self.background1 = self.copy_from_bbox(self.ax1.bbox)
self.background2 = self.copy_from_bbox(self.ax2.bbox)
self.background3 = self.copy_from_bbox(self.ax3.bbox)
# update the data
self.line1.set_ydata(self.getY())
self.line2.set_ydata(self.getY())
self.line3.set_array(self.getZ())
# restore the clean slate background
self.ax1.draw_artist(self.line1)
self.blit(self.ax1.bbox)
self.restore_region(self.background1)
# just draw the animated artist
self.ax2.draw_artist(self.line2)
self.blit(self.ax2.bbox)
self.restore_region(self.background2)
self.ax3.draw_artist(self.line3)
self.blit(self.ax3.bbox)
self.background3 = self.copy_from_bbox(self.get_bg_bbox(self.ax3))
dx_pixel = 1
x1, y1, x2, y2 = self.background3.get_extents()
self.restore_region(self.background3,
bbox=(x1+3, y1, x2, y2),
xy=(x1-dx_pixel, y1))
if self.cnt == 0:
self.draw()
if not (self.cnt%ITERS):
# print the timing info and quit
print 'FPS:' , ITERS/(time.time()-self.tstart)
self.tstart = time.time()
self.cnt += 1
app = QtGui.QApplication(sys.argv)
widget = BlitQT()
widget.show()
app.exec_()
------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing.
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users