Oops. The earlier patch was reversed by accident. Here is the fixed patch.
On Wednesday 05 July 2006 22:30, you wrote:
> Hi all
> I ported the QtAgg backend over to Qt4 and created a patch for adding
> this backend to matplotlib with the name, Qt4Agg. I include it here, for
> anyone interested. I also noticed an earlier message like this, seemingly
> without resolution. Is there other- maybe, better- code for Qt4 available
> somewhere?
>
> Kevin Mueller
> Dept. Atmospheric Science, Univ. Illinois Urbana-Qt4Champaign
diff -Naur matplotlib-0.87.3.old/lib/matplotlib/__init__.py matplotlib-0.87.3/lib/matplotlib/__init__.py
--- matplotlib-0.87.3.old/lib/matplotlib/__init__.py 2006-07-05 22:02:14.000000000 -0500
+++ matplotlib-0.87.3/lib/matplotlib/__init__.py 2006-07-05 22:04:59.000000000 -0500
@@ -467,8 +467,8 @@
def validate_backend(s, fail_on_err = True):
s=s.lower()
backends = ['Agg2', 'Agg', 'Aqt', 'Cairo', 'CocoaAgg', 'EMF', 'GD', 'GDK', 'GTK',
- 'GTKAgg', 'GTKCairo', 'FltkAgg', 'Paint', 'Pdf', 'PS', 'QtAgg', 'SVG',
- 'Template', 'TkAgg', 'WX', 'WXAgg', ]
+ 'GTKAgg', 'GTKCairo', 'FltkAgg', 'Paint', 'Pdf', 'PS', 'QtAgg',
+ 'Qt4Agg', 'SVG', 'Template', 'TkAgg', 'WX', 'WXAgg', ]
for i in backends:
if s == i.lower(): return i
if fail_on_err: raise ValueError('Backend must be %s, or %s'% \
diff -Naur matplotlib-0.87.3.old/lib/matplotlib/backends/__init__.py matplotlib-0.87.3/lib/matplotlib/backends/__init__.py
--- matplotlib-0.87.3.old/lib/matplotlib/backends/__init__.py 2006-07-05 22:02:14.000000000 -0500
+++ matplotlib-0.87.3/lib/matplotlib/backends/__init__.py 2006-07-05 22:07:13.000000000 -0500
@@ -4,8 +4,8 @@
__all__ = ['backend','show','draw_if_interactive',
'new_figure_manager', 'backend_version']
-interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'FltkAgg', 'QtAgg', 'TkAgg',
- 'WX', 'WXAgg', 'CocoaAgg', 'Aqt']
+interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'FltkAgg', 'QtAgg', 'Qt4Agg',
+ 'TkAgg', 'WX', 'WXAgg', 'CocoaAgg', 'Aqt']
non_interactive_bk = ['Agg2', 'Agg', 'Cairo', 'EMF', 'GD', 'GDK', 'Paint',
'Pdf', 'PS', 'SVG', 'Template']
all_backends = interactive_bk + non_interactive_bk
diff -Naur matplotlib-0.87.3.old/lib/matplotlib/backends/backend_qt4.py matplotlib-0.87.3/lib/matplotlib/backends/backend_qt4.py
--- matplotlib-0.87.3.old/lib/matplotlib/backends/backend_qt4.py 1969-12-31 18:00:00.000000000 -0600
+++ matplotlib-0.87.3/lib/matplotlib/backends/backend_qt4.py 2006-07-05 22:07:55.000000000 -0500
@@ -0,0 +1,340 @@
+from __future__ import division
+import math
+import os
+import sys
+
+import matplotlib
+from matplotlib import verbose
+from matplotlib.numerix import asarray, fromstring, UInt8, zeros, \
+ where, transpose, nonzero, indices, ones, nx
+import matplotlib.numerix as numerix
+from matplotlib.cbook import is_string_like, enumerate, onetrue
+from matplotlib.font_manager import fontManager
+from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \
+ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors
+from matplotlib._pylab_helpers import Gcf
+from matplotlib.figure import Figure
+from matplotlib.mathtext import math_parse_s_ft2font
+
+from PyQt4 import QtCore, QtGui
+
+backend_version = "0.9.1"
+def fn_name(): return sys._getframe(1).f_code.co_name
+
+DEBUG = False
+
+cursord = {
+ cursors.MOVE : QtCore.Qt.PointingHandCursor,
+ cursors.HAND : QtCore.Qt.WaitCursor,
+ cursors.POINTER : QtCore.Qt.ArrowCursor,
+ cursors.SELECT_REGION : QtCore.Qt.CrossCursor,
+ }
+
+def draw_if_interactive():
+ """
+ Is called after every pylab drawing command
+ """
+ if matplotlib.is_interactive():
+ figManager = Gcf.get_active()
+ if figManager != None:
+ figManager.canvas.draw()
+
+def show( mainloop=True ):
+ """
+ Show all the figures and enter the qt main loop
+ This should be the last line of your script
+ """
+ for manager in Gcf.get_all_fig_managers():
+ manager.window.show()
+
+ if DEBUG: print 'Inside show'
+ figManager = Gcf.get_active()
+ if figManager != None:
+ figManager.canvas.draw()
+ #if ( createQApp ):
+ # qtapplication.setMainWidget( figManager.canvas )
+
+ if mainloop and createQApp:
+ QtCore.QObject.connect( qtapplication, QtCore.SIGNAL( "lastWindowClosed()" ),
+ qtapplication, QtCore.SLOT( "quit()" ) )
+ qtapplication.exec_()
+
+
+def new_figure_manager( num, *args, **kwargs ):
+ """
+ Create a new figure manager instance
+ """
+ thisFig = Figure( *args, **kwargs )
+ canvas = FigureCanvasQT( thisFig )
+ manager = FigureManagerQT( canvas, num )
+ return manager
+
+
+class FigureCanvasQT( QtGui.QWidget, FigureCanvasBase ):
+ keyvald = { QtCore.Qt.Key_Control : 'control',
+ QtCore.Qt.Key_Shift : 'shift',
+ QtCore.Qt.Key_Alt : 'alt',
+ }
+ # left 1, middle 2, right 3
+ buttond = {1:1, 2:3, 4:2}
+ def __init__( self, figure ):
+ if DEBUG: print 'FigureCanvasQt: ', figure
+ FigureCanvasBase.__init__( self, figure )
+ QtGui.QWidget.__init__( self, None )
+ self.figure = figure
+ self.setMouseTracking( True )
+
+ w,h = self.get_width_height()
+ self.resize( w, h )
+
+ def mousePressEvent( self, event ):
+ x = event.pos().x()
+ # flipy so y=0 is bottom of canvas
+ y = self.figure.bbox.height() - event.pos().y()
+ button = self.buttond[event.button()]
+ FigureCanvasBase.button_press_event( self, x, y, button )
+ if DEBUG: print 'button pressed:', event.button()
+
+ def mouseMoveEvent( self, event ):
+ x = event.x()
+ # flipy so y=0 is bottom of canvas
+ y = self.figure.bbox.height() - event.y()
+ FigureCanvasBase.motion_notify_event( self, x, y )
+ if DEBUG: print 'mouse move'
+
+ def mouseReleaseEvent( self, event ):
+ x = event.x()
+ # flipy so y=0 is bottom of canvas
+ y = self.figure.bbox.height() - event.y()
+ button = self.buttond[event.button()]
+ FigureCanvasBase.button_release_event( self, x, y, button )
+ if DEBUG: print 'button released'
+ self.draw()
+
+ def keyPressEvent( self, event ):
+ key = self._get_key( event )
+ FigureCanvasBase.key_press_event( self, key )
+ if DEBUG: print 'key press', key
+
+ def keyReleaseEvent( self, event ):
+ key = self._get_key(event)
+ FigureCanvasBase.key_release_event( self, key )
+ if DEBUG: print 'key release', key
+
+ def resizeEvent( self, event ):
+ if DEBUG: print 'resize (%d x %d)' % (event.size().width(), event.size().height())
+ QtGui.QWidget.resizeEvent( self, event )
+
+ def resize( self, w, h ):
+ QtGui.QWidget.resize( self, w, h )
+
+ def _get_key( self, event ):
+ if event.key() < 256:
+ key = event.text().latin1()
+ elif self.keyvald.has_key( event.key() ):
+ key = self.keyvald[ event.key() ]
+ else:
+ key = None
+
+ return key
+
+class FigureManagerQT( FigureManagerBase ):
+ """
+ Public attributes
+
+ canvas : The FigureCanvas instance
+ num : The Figure number
+ toolbar : The QtGui.QToolBar
+ window : The QtGui.QMainWindow
+ """
+
+ def __init__( self, canvas, num ):
+ if DEBUG: print 'FigureManagerQT.%s' % fn_name()
+ FigureManagerBase.__init__( self, canvas, num )
+ self.canvas = canvas
+ self.window = QtGui.QMainWindow()
+ self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
+
+ centralWidget = QtGui.QWidget( self.window )
+ self.canvas.setParent( centralWidget )
+
+ # Give the keyboard focus to the figure instead of the manager
+ self.canvas.setFocusPolicy( QtCore.Qt.ClickFocus )
+ self.canvas.setFocus()
+ self.window.setWindowTitle( "Figure %d" % num )
+
+ QtCore.QObject.connect( self.window, QtCore.SIGNAL( 'destroyed()' ),
+ self._widgetclosed )
+ self.window._destroying = False
+
+ if matplotlib.rcParams['toolbar'] == 'classic':
+ print "Classic toolbar is not yet supported"
+ #self.toolbar = NavigationToolbarQT( centralWidget, canvas )
+ self.toolbar = None
+ elif matplotlib.rcParams['toolbar'] == 'toolbar2':
+ self.toolbar = NavigationToolbar2QT( centralWidget, canvas )
+ else:
+ self.toolbar = None
+
+ # Use a vertical layout for the plot and the toolbar. Set the
+ # stretch to all be in the plot so the toolbar doesn't resize.
+ layout = QtGui.QVBoxLayout( centralWidget )
+ layout.addWidget( self.canvas, 1 )
+ if self.toolbar:
+ layout.addWidget( self.toolbar, 0 )
+
+ self.window.setCentralWidget( centralWidget )
+
+ # Reset the window height so the canvas will be the right
+ # size. This ALMOST works right. The first issue is that the
+ # height w/ a toolbar seems to be off by just a little bit (so
+ # we add 4 pixels). The second is that the total width/height
+ # is slightly smaller that we actually want. It seems like
+ # the border of the window is being included in the size but
+ # AFAIK there is no way to get that size.
+ w = self.canvas.width()
+ h = self.canvas.height()
+ if self.toolbar:
+ h += self.toolbar.height() + 4
+ self.window.resize( w, h )
+
+ if matplotlib.is_interactive():
+ self.window.show()
+
+ def notify_axes_change( fig ):
+ # This will be called whenever the current axes is changed
+ if self.toolbar != None: self.toolbar.update()
+ self.canvas.figure.add_axobserver( notify_axes_change )
+
+ def _widgetclosed( self ):
+ if self.window._destroying: return
+ self.window._destroying = True
+ Gcf.destroy(self.num)
+
+ def destroy( self, *args ):
+ if self.window._destroying: return
+ self.window._destroying = True
+ if DEBUG: print "destroy figure manager"
+ self.window.close(True)
+
+class NavigationToolbar2QT( NavigationToolbar2, QtGui.QWidget ):
+ # list of toolitems to add to the toolbar, format is:
+ # text, tooltip_text, image_file, callback(str)
+ toolitems = (
+ ('Home', 'Reset original view', 'home.ppm', 'home'),
+ ('Back', 'Back to previous view','back.ppm', 'back'),
+ ('Forward', 'Forward to next view','forward.ppm', 'forward'),
+ (None, None, None, None),
+ ('Pan', 'Pan axes with left mouse, zoom with right', 'move.ppm', 'pan'),
+ ('Zoom', 'Zoom to rectangle','zoom_to_rect.ppm', 'zoom'),
+ (None, None, None, None),
+ ('Save', 'Save the figure','filesave.ppm', 'save_figure'),
+ )
+
+ def __init__( self, parent, canvas ):
+ self.canvas = canvas
+ QtGui.QWidget.__init__( self, parent )
+
+ # Layout toolbar buttons horizontally.
+ self.layout = QtGui.QHBoxLayout( self )
+ self.layout.setMargin( 2 )
+
+ NavigationToolbar2.__init__( self, canvas )
+
+ def _init_toolbar( self ):
+ basedir = matplotlib.rcParams[ 'datapath' ]
+
+ for text, tooltip_text, image_file, callback in self.toolitems:
+ if text == None:
+ self.layout.addSpacing( 8 )
+ continue
+
+ fname = os.path.join( basedir, image_file )
+ image = QtGui.QPixmap()
+ image.load( fname )
+
+ button = QtGui.QToolButton()
+ button.setIcon(QtGui.QIcon( image ))
+ button.setToolTip( tooltip_text )
+
+ # The automatic layout doesn't look that good - it's too close
+ # to the images so add a margin around it.
+ margin = 4
+ button.setFixedSize( image.width()+margin, image.height()+margin )
+
+ QtCore.QObject.connect( button, QtCore.SIGNAL( 'clicked()' ),
+ getattr( self, callback ) )
+ self.layout.addWidget( button )
+
+ # Add the x,y location widget at the right side of the toolbar
+ # The stretch factor is 1 which means any resizing of the toolbar
+ # will resize this label instead of the buttons.
+ self.locLabel = QtGui.QLabel( "", self )
+ self.locLabel.setAlignment( QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter )
+ self.layout.addWidget( self.locLabel, 1 )
+
+ def dynamic_update( self ):
+ self.canvas.draw()
+
+ def set_message( self, s ):
+ self.locLabel.setText( s )
+
+ def set_cursor( self, cursor ):
+ if DEBUG: print 'Set cursor' , cursor
+ QtGui.QApplication.restoreOverrideCursor()
+ QtGui.QApplication.setOverrideCursor( QtGui.QCursor( cursord[cursor] ) )
+
+ def draw_rubberband( self, event, x0, y0, x1, y1 ):
+ height = self.canvas.figure.bbox.height()
+ y1 = height - y1
+ y0 = height - y0
+
+ w = abs(x1 - x0)
+ h = abs(y1 - y0)
+
+ rect = [ int(val)for val in min(x0,x1), min(y0, y1), w, h ]
+ self.canvas.drawRectangle( rect )
+
+ def save_figure( self ):
+ fname = QtGui.QFileDialog.getSaveFileName()
+ if fname:
+ self.canvas.print_figure( str(fname) )
+
+# set icon used when windows are minimized
+try:
+ QtGui.window_set_default_icon_from_file (
+ os.path.join( matplotlib.rcParams['datapath'], 'matplotlib.svg' ) )
+except:
+ verbose.report( 'Could not load matplotlib icon: %s' % sys.exc_info()[1] )
+
+
+def error_msg_qt( msg, parent=None ):
+ if not is_string_like( msg ):
+ msg = ','.join( map( str,msg ) )
+
+ QtGui.QMessageBox.warning( None, "Matplotlib", msg, QtGui.QMessageBox.Ok )
+
+def exception_handler( type, value, tb ):
+ """Handle uncaught exceptions
+ It does not catch SystemExit
+ """
+ msg = ''
+ # get the filename attribute if available (for IOError)
+ if hasattr(value, 'filename') and value.filename != None:
+ msg = value.filename + ': '
+ if hasattr(value, 'strerror') and value.strerror != None:
+ msg += value.strerror
+ else:
+ msg += str(value)
+
+ if len( msg ) : error_msg_qt( msg )
+
+
+FigureManager = FigureManagerQT
+
+# We need one and only one QApplication before we can build any Qt widgets
+# Detect if a QApplication exists.
+createQApp = QtGui.QApplication.startingUp()
+if createQApp:
+ if DEBUG: print "Starting up QApplication"
+ qtapplication = QtGui.QApplication( [" "] )
diff -Naur matplotlib-0.87.3.old/lib/matplotlib/backends/backend_qt4agg.py matplotlib-0.87.3/lib/matplotlib/backends/backend_qt4agg.py
--- matplotlib-0.87.3.old/lib/matplotlib/backends/backend_qt4agg.py 1969-12-31 18:00:00.000000000 -0600
+++ matplotlib-0.87.3/lib/matplotlib/backends/backend_qt4agg.py 2006-07-05 22:08:01.000000000 -0500
@@ -0,0 +1,127 @@
+"""
+Render to qt4 from agg
+"""
+from __future__ import division
+
+import os, sys
+from matplotlib import verbose
+from matplotlib.cbook import enumerate
+from matplotlib.figure import Figure
+
+from backend_agg import FigureCanvasAgg
+from backend_qt4 import FigureManagerQT, FigureCanvasQT,\
+ show, draw_if_interactive, backend_version
+import struct
+
+from PyQt4 import QtCore, QtGui
+
+DEBUG = False
+isLittleEndian = struct.pack('@i',7)=='\x07\x00\x00\x00'
+
+def new_figure_manager( num, *args, **kwargs ):
+ """
+ Create a new figure manager instance
+ """
+ if DEBUG: print 'backend_qt4agg.new_figure_manager'
+ thisFig = Figure( *args, **kwargs )
+ canvas = FigureCanvasQTAgg( thisFig )
+ return FigureManagerQT( canvas, num )
+
+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.pixmap = QtGui.QPixmap()
+
+ def resizeEvent( self, e ):
+ FigureCanvasQT.resizeEvent( self, e )
+ w = e.size().width()
+ h = e.size().height()
+ if DEBUG: print "FigureCanvasQtAgg.resizeEvent(", w, ",", h, ")"
+ dpival = self.figure.dpi.get()
+ winch = w/dpival
+ hinch = h/dpival
+ self.figure.set_figsize_inches( winch, hinch )
+ self.draw()
+
+ def drawRectangle( self, rect ):
+ self.rect = rect
+ self.drawRect = True
+ # False in repaint does not clear the image before repainting
+ self.repaint()
+
+ def paintEvent( self, e ):
+ """
+ Draw to the Agg backend and then copy the image to the QtGui.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.get_width_height()
+
+ p = QtGui.QPainter( self )
+ FigureCanvasAgg.draw( self )
+
+ # only replot data when needed
+ if ( self.replot ):
+ stringBuffer = str( self.buffer_rgba(0,0) )
+
+
+ # 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).
+ # TODO: fix this to choose correct endian
+ if isLittleEndian:
+ 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)
+
+ self.pixmap = QtGui.QPixmap.fromImage( qImage )
+
+ p.drawPixmap( 0, 0, self.pixmap )
+
+ # 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()
+ 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.replot = True
+ self.repaint()
+ self.update()
+
+ def print_figure( self, filename, dpi=150, facecolor='w', edgecolor='w',
+ orientation='portrait' ):
+ if DEBUG: print 'FigureCanvasQTAgg.print_figure'
+ agg = self.switch_backends( FigureCanvasAgg )
+ agg.print_figure( filename, dpi, facecolor, edgecolor, orientation )
+
+
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel