|
| 1 | +from __future__ import division |
| 2 | +import os, math |
| 3 | +import sys |
| 4 | +import matplotlib |
| 5 | +from matplotlib import verbose, MPLError |
| 6 | +from matplotlib.numerix import asarray, fromstring, UInt8, zeros, \ |
| 7 | + where, transpose, nonzero, indices, ones, nx |
| 8 | +import matplotlib.numerix as numerix |
| 9 | +from matplotlib.cbook import is_string_like, enumerate, onetrue |
| 10 | +from matplotlib.font_manager import fontManager |
| 11 | +from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ |
| 12 | + FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors |
| 13 | +from matplotlib._pylab_helpers import Gcf |
| 14 | +from matplotlib.figure import Figure |
| 15 | +from matplotlib.mathtext import math_parse_s_ft2font |
| 16 | +import qt |
| 17 | + |
| 18 | +backend_version = "0.9" |
| 19 | +def fn_name(): return sys._getframe(1).f_code.co_name |
| 20 | + |
| 21 | +DEBUG = False |
| 22 | + |
| 23 | +cursord = { |
| 24 | + cursors.MOVE : qt.Qt.PointingHandCursor, |
| 25 | + cursors.HAND : qt.Qt.WaitCursor, |
| 26 | + cursors.POINTER : qt.Qt.ArrowCursor, |
| 27 | + cursors.SELECT_REGION : qt.Qt.CrossCursor, |
| 28 | + } |
| 29 | + |
| 30 | +def draw_if_interactive(): |
| 31 | + """ |
| 32 | + Is called after every pylab drawing command |
| 33 | + """ |
| 34 | + if matplotlib.is_interactive(): |
| 35 | + figManager = Gcf.get_active() |
| 36 | + if figManager != None: |
| 37 | + figManager.canvas.draw() |
| 38 | + |
| 39 | +def show( mainloop=True ): |
| 40 | + """ |
| 41 | + Show all the figures and enter the qt main loop |
| 42 | + This should be the last line of your script |
| 43 | + """ |
| 44 | + for manager in Gcf.get_all_fig_managers(): |
| 45 | + manager.window.show() |
| 46 | + |
| 47 | + if DEBUG: print 'Inside show' |
| 48 | + figManager = Gcf.get_active() |
| 49 | + if figManager != None: |
| 50 | + figManager.canvas.draw() |
| 51 | + #if ( createQApp ): |
| 52 | + # qtapplication.setMainWidget( figManager.canvas ) |
| 53 | + |
| 54 | + if mainloop and createQApp: |
| 55 | + qt.QObject.connect( qtapplication, qt.SIGNAL( "lastWindowClosed()" ), |
| 56 | + qtapplication, qt.SLOT( "quit()" ) ) |
| 57 | + qtapplication.exec_loop() |
| 58 | + |
| 59 | + |
| 60 | +def new_figure_manager( num, *args, **kwargs ): |
| 61 | + """ |
| 62 | + Create a new figure manager instance |
| 63 | + """ |
| 64 | + thisFig = Figure( *args, **kwargs ) |
| 65 | + canvas = FigureCanvasQT( thisFig ) |
| 66 | + manager = FigureManagerQT( canvas, num ) |
| 67 | + return manager |
| 68 | + |
| 69 | + |
| 70 | +class FigureCanvasQT( qt.QWidget, FigureCanvasBase ): |
| 71 | + keyvald = { qt.Qt.Key_Control : 'control', |
| 72 | + qt.Qt.Key_Shift : 'shift', |
| 73 | + qt.Qt.Key_Alt : 'alt', |
| 74 | + } |
| 75 | + |
| 76 | + def __init__( self, figure ): |
| 77 | + if DEBUG: print 'FigureCanvasQt: ', figure |
| 78 | + FigureCanvasBase.__init__( self, figure ) |
| 79 | + qt.QWidget.__init__( self, None, "QWidget figure" ) |
| 80 | + self.figure = figure |
| 81 | + self.setMouseTracking( True ) |
| 82 | + |
| 83 | + w,h = self.figure.get_width_height() |
| 84 | + self.resize( w, h ) |
| 85 | + |
| 86 | + def mousePressEvent( self, event ): |
| 87 | + x = event.pos().x() |
| 88 | + # flipy so y=0 is bottom of canvas |
| 89 | + y = self.figure.bbox.height() - event.pos().y() |
| 90 | + FigureCanvasBase.button_press_event( self, x, y, event.button() ) |
| 91 | + if DEBUG: print 'button pressed' |
| 92 | + |
| 93 | + def mouseMoveEvent( self, event ): |
| 94 | + x = event.x() |
| 95 | + # flipy so y=0 is bottom of canvas |
| 96 | + y = self.figure.bbox.height() - event.y() |
| 97 | + FigureCanvasBase.motion_notify_event( self, x, y ) |
| 98 | + if DEBUG: print 'mouse move' |
| 99 | + |
| 100 | + def mouseReleaseEvent( self, event ): |
| 101 | + x = event.x() |
| 102 | + # flipy so y=0 is bottom of canvas |
| 103 | + y = self.figure.bbox.height() - event.y() |
| 104 | + FigureCanvasBase.button_release_event( self, x, y, event.button() ) |
| 105 | + if DEBUG: print 'button released' |
| 106 | + self.draw() |
| 107 | + |
| 108 | + def keyPressEvent( self, event ): |
| 109 | + key = self._get_key( event ) |
| 110 | + FigureCanvasBase.key_press_event( self, key ) |
| 111 | + if DEBUG: print 'key press', key |
| 112 | + |
| 113 | + def keyReleaseEvent( self, event ): |
| 114 | + key = self._get_key(event) |
| 115 | + FigureCanvasBase.key_release_event( self, key ) |
| 116 | + if DEBUG: print 'key release', key |
| 117 | + |
| 118 | + def _get_key( self, event ): |
| 119 | + if event.key() < 256: |
| 120 | + key = event.text().latin1() |
| 121 | + elif self.keyvald.has_key( event.key() ): |
| 122 | + key = self.keyvald[ event.key() ] |
| 123 | + else: |
| 124 | + key = None |
| 125 | + |
| 126 | + return key |
| 127 | + |
| 128 | +class FigureManagerQT( FigureManagerBase ): |
| 129 | + """ |
| 130 | + Public attributes |
| 131 | +
|
| 132 | + canvas : The FigureCanvas instance |
| 133 | + num : The Figure number |
| 134 | + toolbar : The qt.QToolBar |
| 135 | + window : The qt.QMainWindow |
| 136 | + """ |
| 137 | + |
| 138 | + def __init__( self, canvas, num ): |
| 139 | + if DEBUG: print 'FigureManagerQT.%s' % fn_name() |
| 140 | + FigureManagerBase.__init__( self, canvas, num ) |
| 141 | + self.canvas = canvas |
| 142 | + self.window = qt.QMainWindow() |
| 143 | + |
| 144 | + self.canvas.reparent( self.window, qt.QPoint( 0, 0 ) ) |
| 145 | + # Give the keyboard focus to the figure instead of the manager |
| 146 | + self.canvas.grabKeyboard() |
| 147 | + self.window.setCaption( "Figure %d" % num ) |
| 148 | + self.window.setCentralWidget( self.canvas ) |
| 149 | + |
| 150 | + if matplotlib.rcParams['toolbar'] == 'classic': |
| 151 | + print "Classic toolbar is not yet supported" |
| 152 | + #self.toolbar = NavigationToolbar( canvas, self.window ) |
| 153 | + self.toolbar = None |
| 154 | + elif matplotlib.rcParams['toolbar'] == 'toolbar2': |
| 155 | + self.toolbar = NavigationToolbar2QT( canvas, self.window ) |
| 156 | + else: |
| 157 | + self.toolbar = None |
| 158 | + |
| 159 | + self.window.resize( self.canvas.size() ) |
| 160 | + |
| 161 | + if matplotlib.is_interactive(): |
| 162 | + self.window.show() |
| 163 | + |
| 164 | + def notify_axes_change( fig ): |
| 165 | + # This will be called whenever the current axes is changed |
| 166 | + if self.toolbar != None: self.toolbar.update() |
| 167 | + self.canvas.figure.add_axobserver( notify_axes_change ) |
| 168 | + |
| 169 | + #def destroy( self, *args ): |
| 170 | + # if DEBUG: print "destroy figure manager" |
| 171 | + # self.window.exit() |
| 172 | + |
| 173 | +class NavigationToolbar2QT( NavigationToolbar2, qt.QToolBar ): |
| 174 | + # list of toolitems to add to the toolbar, format is: |
| 175 | + # text, tooltip_text, image_file, callback(str) |
| 176 | + toolitems = ( |
| 177 | + ('Home', 'Reset original view', 'home.png', 'home'), |
| 178 | + ('Back', 'Back to previous view','back.png', 'back'), |
| 179 | + ('Forward', 'Forward to next view','forward.png', 'forward'), |
| 180 | + (None, None, None, None), |
| 181 | + ('Pan', 'Pan axes with left mouse, zoom with right', 'move.png', 'pan'), |
| 182 | + ('Zoom', 'Zoom to rectangle','zoom_to_rect.png', 'zoom'), |
| 183 | + (None, None, None, None), |
| 184 | + ('Save', 'Save the figure','filesave.png', 'save_figure'), |
| 185 | + ) |
| 186 | + |
| 187 | + def __init__( self, canvas, window ): |
| 188 | + self.window = window |
| 189 | + self.canvas = canvas |
| 190 | + qt.QToolBar.__init__( self, "Navigator2", window, qt.Qt.DockBottom ) |
| 191 | + NavigationToolbar2.__init__( self, canvas ) |
| 192 | + |
| 193 | + def _init_toolbar( self ): |
| 194 | + self.window.setUsesTextLabel( False ) |
| 195 | + basedir = matplotlib.rcParams[ 'datapath' ] |
| 196 | + |
| 197 | + for text, tooltip_text, image_file, callback in self.toolitems: |
| 198 | + if text == None: |
| 199 | + self.addSeparator() |
| 200 | + continue |
| 201 | + |
| 202 | + fname = os.path.join( basedir, image_file ) |
| 203 | + image = qt.QPixmap() |
| 204 | + image.load( fname ) |
| 205 | + a = qt.QAction( qt.QIconSet( image ), text, qt.QKeySequence('M'), |
| 206 | + self.window ) |
| 207 | + a.setToolTip( tooltip_text ) |
| 208 | + qt.QObject.connect( a, qt.SIGNAL( 'activated()' ), |
| 209 | + getattr( self, callback ) ) |
| 210 | + a.addTo( self ) |
| 211 | + |
| 212 | + def dynamic_update( self ): |
| 213 | + self.canvas.draw() |
| 214 | + |
| 215 | + def set_message( self, s ): |
| 216 | + self.window.statusBar().message( s ) |
| 217 | + |
| 218 | + def set_cursor( self, cursor ): |
| 219 | + if DEBUG: print 'Set cursor' , cursor |
| 220 | + #qt.QApplication.restoreOverrideCursor() |
| 221 | + #qt.QApplication.setOverrideCursor( qt.QCursor( cursord[cursor] ) ) |
| 222 | + |
| 223 | + def draw_rubberband( self, event, x0, y0, x1, y1 ): |
| 224 | + height = self.canvas.figure.bbox.height() |
| 225 | + y1 = height - y1 |
| 226 | + y0 = height - y0 |
| 227 | + |
| 228 | + w = abs(x1 - x0) |
| 229 | + h = abs(y1 - y0) |
| 230 | + |
| 231 | + rect = [ int(val)for val in min(x0,x1), min(y0, y1), w, h ] |
| 232 | + self.canvas.drawRectangle( rect ) |
| 233 | + |
| 234 | + def save_figure( self ): |
| 235 | + self.canvas.releaseKeyboard() |
| 236 | + fname = qt.QFileDialog.getSaveFileName() |
| 237 | + |
| 238 | + if fname: |
| 239 | + self.canvas.print_figure( fname.latin1() ) |
| 240 | + self.canvas.grabKeyboard() |
| 241 | + |
| 242 | +# set icon used when windows are minimized |
| 243 | +try: |
| 244 | + qt.window_set_default_icon_from_file ( |
| 245 | + os.path.join( matplotlib.rcParams['datapath'], 'matplotlib.svg' ) ) |
| 246 | +except: |
| 247 | + verbose.report( 'Could not load matplotlib icon: %s' % sys.exc_info()[1] ) |
| 248 | + |
| 249 | + |
| 250 | +def error_msg_qt( msg, parent=None ): |
| 251 | + if not is_string_like( msg ): |
| 252 | + msg = ','.join( map( str,msg ) ) |
| 253 | + |
| 254 | + qt.QMessageBox.warning( None, "Matplotlib", msg, qt.QMessageBox.Ok ) |
| 255 | + |
| 256 | +def exception_handler( type, value, tb ): |
| 257 | + """Handle uncaught exceptions |
| 258 | + It does not catch SystemExit |
| 259 | + """ |
| 260 | + msg = '' |
| 261 | + # get the filename attribute if available (for IOError) |
| 262 | + if hasattr(value, 'filename') and value.filename != None: |
| 263 | + msg = value.filename + ': ' |
| 264 | + if hasattr(value, 'strerror') and value.strerror != None: |
| 265 | + msg += value.strerror |
| 266 | + else: |
| 267 | + msg += str(value) |
| 268 | + |
| 269 | + if len( msg ) : error_msg( msg ) |
| 270 | + |
| 271 | + |
| 272 | +FigureManager = FigureManagerQT |
| 273 | +error_msg = error_msg_qt |
| 274 | + |
| 275 | +# We need one and only one QApplication before we can build any Qt widgets |
| 276 | +# Detect if a QApplication exists. |
| 277 | +createQApp = qt.QApplication.startingUp() |
| 278 | +if createQApp: |
| 279 | + if DEBUG: print "Starting up QApplication" |
| 280 | + qtapplication = qt.QApplication( [" "] ) |
0 commit comments