Need help with Darren Dale qt example of extending Toolbar

HI modified one of the examples and it brings up the chart window with the custom toolbar. However, nothing happens with the “pickevent”

“”"

This demo demonstrates how to embed a matplotlib (mpl) plot

into a PyQt4 GUI application, including:

  • Using the navigation toolbar

  • Adding data to the plot

  • Dynamically modifying the plot’s properties

  • Processing mpl events

  • Saving the plot to a file from a menu

The main goal is to serve as a basis for developing rich PyQt GUI

applications featuring mpl plots (using the mpl OO API).

Eli Bendersky (eliben@…287…)

License: this code is in the public domain

Last modified: 19.01.2009

“”"

from future import division

import sys, os, random

from PyQt4.QtCore import *

from PyQt4.QtGui import *

import matplotlib

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar

from matplotlib.figure import Figure

import math

import os

import sys

import matplotlib

from matplotlib import verbose

from matplotlib.backend_bases import cursors

from matplotlib.figure import Figure

try:

from PyQt4 import QtCore, QtGui, Qt

except ImportError:

raise ImportError(“Qt4 backend requires that PyQt4 is installed.”)

cursord = {

cursors.MOVE : QtCore.Qt.SizeAllCursor,

cursors.HAND : QtCore.Qt.PointingHandCursor,

cursors.POINTER : QtCore.Qt.ArrowCursor,

cursors.SELECT_REGION : QtCore.Qt.CrossCursor,

}

class NavigationToolbarCustom(NavigationToolbar):

def init(self, *args, **kwargs):

pixmap = QtGui.QPixmap()

pixmap.load(’:/cross.png’)

cursors.SELECT_POINT = pixmap

super(NavigationToolbar, self).init(*args, **kwargs)

def _init_toolbar(self):

self.basedir = os.path.join(matplotlib.rcParams[ ‘datapath’ ],‘images’)

a = self.addAction(self._icon(‘home.svg’), ‘Home’, self.home)

a.setToolTip(‘Reset original view’)

a = self.addAction(self._icon(‘back.svg’), ‘Back’, self.back)

a.setToolTip(‘Back to previous view’)

a = self.addAction(self._icon(‘forward.svg’), ‘Forward’, self.forward)

a.setToolTip(‘Forward to next view’)

self.addSeparator()

a = self.addAction(self._icon(‘move.svg’), ‘Pan’, self.pan)

a.setToolTip(‘Pan axes with left mouse, zoom with right’)

a = self.addAction(self._icon(‘zoom_to_rect.svg’), ‘Zoom’, self.zoom)

a.setToolTip(‘Zoom to rectangle’)

a = self.addAction(self._icon(‘hand.svg’), ‘Select’,

self.selectPointMode)

a.setToolTip(‘Select the nearest data point’)

self.addSeparator()

a = self.addAction(self._icon(‘subplots.png’), ‘Subplots’,

self.configure_subplots)

a.setToolTip(‘Configure subplots’)

a = self.addAction(self._icon(‘filesave.svg’), ‘Save’,

self.save_figure)

a.setToolTip(‘Save the figure’)

self.buttons = {}

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.

if self.coordinates:

self.locLabel = QtGui.QLabel( “”, self )

self.locLabel.setAlignment(

QtCore.Qt.AlignRight | QtCore.Qt.AlignTop )

self.locLabel.setSizePolicy(

QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,

QtGui.QSizePolicy.Ignored))

labelAction = self.addWidget(self.locLabel)

labelAction.setVisible(True)

reference holder for subplots_adjust window

self.adj_window = None

def mouse_move(self, event):

print ‘mouse_move’, event.button

if not event.inaxes or not self._active:

if self._lastCursor != cursors.POINTER:

self.set_cursor(cursors.POINTER)

self._lastCursor = cursors.POINTER

else:

if self._active==‘ZOOM’:

if self._lastCursor != cursors.SELECT_REGION:

self.set_cursor(cursors.SELECT_REGION)

self._lastCursor = cursors.SELECT_REGION

if self._xypress:

x, y = event.x, event.y

lastx, lasty, a, ind, lim, trans = self._xypress[0]

self.draw_rubberband(event, x, y, lastx, lasty)

elif (self._active==‘PAN’ and

self._lastCursor != cursors.MOVE):

self.set_cursor(cursors.MOVE)

self._lastCursor = cursors.MOVE

elif self._active==‘SELECT’:

if self._lastCursor != cursors.SELECT_POINT:

QtGui.QApplication.restoreOverrideCursor()

QtGui.QApplication.setOverrideCursor(QtGui.QCursor(cursors.SELECT_POINT))

self._lastCursor = cursors.SELECT_POINT

if event.inaxes and event.inaxes.get_navigate():

try: s = event.inaxes.format_coord(event.xdata, event.ydata)

except ValueError: pass

except OverflowError: pass

else:

if len(self.mode):

self.set_message(’%s : %s’ % (self.mode, s))

else:

self.set_message(s)

else: self.set_message(self.mode)

def selectPointMode(self, *args):

if self._active == ‘SELECT’:

self._active = None

else:

self._active = ‘SELECT’

if self._idPress is not None:

self._idPress = self.canvas.mpl_disconnect(self._idPress)

self.mode = ‘’

if self._idRelease is not None:

self._idRelease = self.canvas.mpl_disconnect(self._idRelease)

self.mode = ‘’

if self._active:

self._idRelease = self.canvas.mpl_connect(

‘button_press_event’, self.selectPoint)

self.mode = ‘pixel select mode’

self.canvas.widgetlock(self)

else:

self.canvas.widgetlock.release(self)

self.set_message(self.mode)

def selectPoint(self, event):

if event.inaxes and event.inaxes.get_navigate():

print 'selectPoint: ', 1

self.xdatastart=event.xdata

print 'selectPoint: ', 2

self.ydatastart=event.ydata

self.xstart=event.x

self.ystart=event.y

print 'selectPoint: ', 3

self._banddraw = self.canvas.mpl_connect(

‘motion_notify_event’,self.drawband)

print 'selectPoint: ', 4

self._idRelease = self.canvas.mpl_disconnect(self._idRelease)

self._idRelease = self.canvas.mpl_connect(

‘button_release_event’, self.selectSecondPoint)

print 'selectPoint: ', 5

def selectSecondPoint(self, event):

if event.inaxes and event.inaxes.get_navigate():

print 'selectSecondPoint: ', 1

self._banddraw=self.canvas.mpl_disconnect(self._banddraw)

print 'selectSecondPoint: ', 2

self._idRelease = self.canvas.mpl_disconnect(self._idRelease)

print 'selectSecondPoint: ', 3

self._idRelease = self.canvas.mpl_connect(

‘button_press_event’, self.selectPoint)

self.draw_rubberband(event, 0, 0, 0, 0)

print 'selectSecondPoint: ', 4

self.emit(

QtCore.SIGNAL(‘pickEvent’),

self.xdatastart,

self.ydatastart,

event.xdata,

event.ydata

)

print 'selectSecondPoint: ', 5

def drawband(self, event):

self.draw_rubberband(event,self.xstart, self.ystart, event.x, event.y)

def onPick(self, xstart, ystart, xend, yend):

xstart_i, ystart_i = self.getIndices(xstart, ystart)

xend_i, yend_i = self.getIndices(xend, yend)

if xstart_i > xend_i: xstart_i, xend_i = xend_i, xstart_i

if ystart_i > yend_i: ystart_i, yend_i = yend_i, ystart_i

try:

indices = self.indices[ystart_i:yend_i+1, xstart_i:xend_i+1]

print indices

self.emit(QtCore.SIGNAL(‘pickEvent’), indices.flatten())

except TypeError:

pass

def getIndices(self, xdata, ydata):

xIndex = locateClosest(xdata, self.xPixelLocs)

yIndex = locateClosest(ydata, self.yPixelLocs)

return xIndex, yIndex

def locateClosest(point, points):

compare = numpy.abs(points-point)

return numpy.nonzero(numpy.ravel(compare==compare.min()))[0]

class AppForm(QMainWindow):

def init(self, parent=None):

QMainWindow.init(self, parent)

self.setWindowTitle(‘Demo: PyQt with matplotlib’)

self.create_menu()

self.create_main_frame()

self.create_status_bar()

self.textbox.setText(‘1 2 3 4’)

self.on_draw()

def save_plot(self):

file_choices = “PNG (.png)|.png”

path = unicode(QFileDialog.getSaveFileName(self,

‘Save file’, ‘’,

file_choices))

if path:

self.canvas.print_figure(path, dpi=self.dpi)

self.statusBar().showMessage(‘Saved to %s’ % path, 2000)

def on_about(self):

msg = “”" A demo of using PyQt with matplotlib:

  • Use the matplotlib navigation bar

  • Add values to the text box and press Enter (or click “Draw”)

  • Show or hide the grid

  • Drag the slider to modify the width of the bars

  • Save the plot to a file using the File menu

  • Click on a bar to receive an informative message

“”"

QMessageBox.about(self, “About the demo”, msg.strip())

def on_pick(self, event):

The event received here is of the type

matplotlib.backend_bases.PickEvent

···

It carries lots of information, of which we’re using

only a small amount here.

box_points = event.artist.get_bbox().get_points()

msg = “You’ve clicked on a bar with coords:\n %s” % box_points

QMessageBox.information(self, “Click!”, msg)

def on_draw(self):

“”" Redraws the figure

“”"

str = unicode(self.textbox.text())

self.data = map(int, str.split())

x = range(len(self.data))

clear the axes and redraw the plot anew

self.axes.clear()

self.axes.grid(self.grid_cb.isChecked())

self.axes.bar(

left=x,

height=self.data,

width=self.slider.value() / 100.0,

align=‘center’,

alpha=0.44,

picker=5)

self.canvas.draw()

def create_main_frame(self):

self.main_frame = QWidget()

Create the mpl Figure and FigCanvas objects.

5x4 inches, 100 dots-per-inch

self.dpi = 100

self.fig = Figure((5.0, 4.0), dpi=self.dpi)

self.canvas = FigureCanvas(self.fig)

self.canvas.setParent(self.main_frame)

Since we have only one plot, we can use add_axes

instead of add_subplot, but then the subplot

configuration tool in the navigation toolbar wouldn’t

work.

self.axes = self.fig.add_subplot(111)

Bind the ‘pick’ event for clicking on one of the bars

self.canvas.mpl_connect(‘pick_event’, self.on_pick)

self.canvas.mpl_connect(‘pickevent’, self.onPick)

Create the navigation toolbar, tied to the canvas

self.mpl_toolbar = NavigationToolbarCustom(self.canvas, self.main_frame)

Other GUI controls

self.textbox = QLineEdit()

self.textbox.setMinimumWidth(200)

self.connect(self.textbox, SIGNAL(‘editingFinished ()’), self.on_draw)

self.draw_button = QPushButton("&Draw")

self.connect(self.draw_button, SIGNAL(‘clicked()’), self.on_draw)

self.grid_cb = QCheckBox(“Show &Grid”)

self.grid_cb.setChecked(False)

self.connect(self.grid_cb, SIGNAL(‘stateChanged(int)’), self.on_draw)

slider_label = QLabel(‘Bar width (%):’)

self.slider = QSlider(QtCore.Qt.Horizontal)

self.slider.setRange(1, 100)

self.slider.setValue(20)

self.slider.setTracking(True)

self.slider.setTickPosition(QSlider.TicksBothSides)

self.connect(self.slider, SIGNAL(‘valueChanged(int)’), self.on_draw)

Layout with box sizers

hbox = QHBoxLayout()

for w in [ self.textbox, self.draw_button, self.grid_cb,

slider_label, self.slider]:

hbox.addWidget(w)

hbox.setAlignment(w, QtCore.Qt.AlignVCenter)

vbox = QVBoxLayout()

vbox.addWidget(self.canvas)

vbox.addWidget(self.mpl_toolbar)

vbox.addLayout(hbox)

self.main_frame.setLayout(vbox)

self.setCentralWidget(self.main_frame)

def create_status_bar(self):

self.status_text = QLabel(“This is a demo”)

self.statusBar().addWidget(self.status_text, 1)

def create_menu(self):

self.file_menu = self.menuBar().addMenu("&File")

load_file_action = self.create_action("&Save plot",

shortcut=“Ctrl+S”, slot=self.save_plot,

tip=“Save the plot”)

quit_action = self.create_action("&Quit", slot=self.close,

shortcut=“Ctrl+Q”, tip=“Close the application”)

self.add_actions(self.file_menu,

(load_file_action, None, quit_action))

self.help_menu = self.menuBar().addMenu("&Help")

about_action = self.create_action("&About",

shortcut=‘F1’, slot=self.on_about,

tip=‘About the demo’)

self.add_actions(self.help_menu, (about_action,))

def add_actions(self, target, actions):

for action in actions:

if action is None:

target.addSeparator()

else:

target.addAction(action)

def create_action( self, text, slot=None, shortcut=None,

icon=None, tip=None, checkable=False,

signal=“triggered()”):

action = QAction(text, self)

if icon is not None:

action.setIcon(QIcon(":/%s.png" % icon))

if shortcut is not None:

action.setShortcut(shortcut)

if tip is not None:

action.setToolTip(tip)

action.setStatusTip(tip)

if slot is not None:

self.connect(action, SIGNAL(signal), slot)

if checkable:

action.setCheckable(True)

return action

def main():

app = QApplication(sys.argv)

form = AppForm()

form.show()

app.exec_()

if name == “main”:

main()