In a wxPython panel I want to use matplotlib's Lasso widget. In my implementation Lasso is used in three different functionalities. Nevertheless, in order to accomplish these functionalities I must combine key events with mouse button events.
By default, the initial Lasso function can be used by pressing the left mouse button. So, for my first functionality I press the left mouse button, select a region of interest and do something with the points included. For the second functionality, I would like to select another region of interest and do something else with these points.I am trying to do that by pressing shift+LMB. Finally, in my third functionality I would like to do something else with the selected points by pressing Ctrl+LMB.
Schematically, I would like to do the following:
if left mouse button is pressed:
use Lasso and with the included points do the 1st functionality
if shift is press and left mouse button is pressed:
use Lasso and with the included points do the 2nd functionality
if ctrl is press and lmb is also pressed :
call Lasso and with the included points do the 3rd functionality
Unfortunately, I can not achieve my goal and I get the following error: if self.shift_is_held == True:
AttributeError: object has no attribute 'shift_is_held'. It seems that it can not recognize the button events, while in other cases the widgetlock command seems not to make the axes available.
Here are parts of my code:
def scatter(self,data):
#create scatter plot
fig = self._view_frame.figure
fig.clf()
Data = []
self.lmans = []
self.points_colors = []
Data2 = []
self.lmans_2 = []
Data3 = []
self.lmans_2 = []
ax = fig.add_subplot('111')
datum = []
datum_2 = []
datum_3 = []
for x,y in zip(self.data[:,0],self.data[:,1]):
datum.append(Datum(x,y))
datum_2.append(Datum2(x,y))
datum_3.append(Datum3(x,y))
ax.scatter(self.data[:, 0], self.data[:, 1], s=150, marker='d')
ax.set_xlim((min(self.data[:,0]), max(self.data[:,0])))
ax.set_ylim((min(self.data[:,1]), max(self.data[:,1])))
ax.set_aspect('auto')
Data.append(datum)
Data2.append(datum_2)
Data3.append(datum_3)
lman = self.LassoManager(ax, datum, Data)
lman_2 = self.LassoManager2(ax, datum_2, Data2)
lman_3 = self.LassoManager3(ax, datum_3, Data3)
fig.canvas.draw()
self.lmans.append(lman)
self.lmans_2.append(lman_2)
self.lmans_3.append(lman_3)
fig.canvas.mpl_connect('axes_enter_event', self.enter_axes)
class Lasso(AxesWidget):
"""Selection curve of an arbitrary shape.
The selected path can be used in conjunction with
:func:`~matplotlib.path.Path.contains_point` to select data points
from an image.
Unlike :class:`LassoSelector`, this must be initialized with a starting
point `xy`, and the `Lasso` events are destroyed upon release.
Parameters:
*ax* : :class:`~matplotlib.axes.Axes`
The parent axes for the widget.
*xy* : array
Coordinates of the start of the lasso.
*callback* : function
Whenever the lasso is released, the `callback` function is called and
passed the vertices of the selected path.
"""
def __init__(self, ax, xy, callback=None, useblit=True):
AxesWidget.__init__(self, ax)
self.useblit = useblit and self.canvas.supports_blit
if self.useblit:
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
x, y = xy
self.verts = [(x, y)]
self.line = Line2D([x], [y], linestyle='-', color='black', lw=2)
self.ax.add_line(self.line)
self.callback = callback
self.connect_event('button_release_event', self.onrelease)
self.connect_event('motion_notify_event', self.onmove)
def onrelease(self, event):
if self.ignore(event):
return
if self.verts is not None:
self.verts.append((event.xdata, event.ydata))
if len(self.verts) > 2:
self.callback(self.verts)
self.ax.lines.remove(self.line)
self.verts = None
self.disconnect_events()
def onmove(self, event):
if self.ignore(event):
return
if self.verts is None:
return
if event.inaxes != self.ax:
return
if event.button != 1:
return
self.verts.append((event.xdata, event.ydata))
self.line.set_data(list(zip(*self.verts)))
if self.useblit:
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
else:
self.canvas.draw_idle()
def enter_axes(self, event):
self.idfig = event.inaxes.colNum
self._view_frame.figure.canvas.mpl_connect('button_press_event', self.onpress_2)
self._view_frame.figure.canvas.mpl_connect('key_press_event', self.onkey_press_2)
self._view_frame.figure.canvas.mpl_connect('key_release_event', self.onkey_release_2)
self._view_frame.figure.canvas.mpl_connect('button_press_event', self.onpress_3)
self._view_frame.figure.canvas.mpl_connect('key_press_event', self.onkey_press_3)
self._view_frame.figure.canvas.mpl_connect('key_release_event', self.onkey_release_3)
def LassoManager(self, ax, data, Data):
self.axes = ax
self.canvas = ax.figure.canvas
self.data = data
self.Data = Data
self.Nxy = len(data)
# self.facecolors = [d.color for d in data]
self.xys = [(d.x, d.y) for d in data]
fig = ax.figure
#self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
def callback(self, verts):
#facecolors = self.facecolors#collection.get_facecolors()
#colorin = colorConverter.to_rgba('red')
#colorout = colorConverter.to_rgba('blue')
p = path.Path(verts)
self.ind = p.contains_points([(d.x, d.y) for d in self.Data[self.where.colNum]])
self._view_frame.figure.canvas.mpl_connect('button_press_event', self.onpress)
#Functionality 1
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso)
del self.lasso
def onpress(self,event):
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
self.where = event.inaxes
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso)
def onkey_press_2(self,event):
if event.key =='shift':
self.merge_is_held = True
def onkey_press_3(self,event):
if event.key == 'control':
self.split_is_held = True
def onkey_release_2(self, event):
if event.key == 'shift':
self.merge_is_held = False
def onkey_release_3(self, event):
if event.key == 'control':
self.split_is_held = False
def LassoManagerMerge(self, ax, data2, Data2):
self.axes = ax
self.canvas = ax.figure.canvas
self.data2 = data2
self.Data2 = Data2
self.Nxy = len(dataMerge)
self.facecolors_2 = [d.color for d in data2]
# print "facecolors",self.facecolors
self.xys = [(d.x, d.y) for d in data2]
# print "xys",self.xys
fig = ax.figure
self.collection_2 = RegularPolyCollection(
fig.dpi, 6, sizes=(0,),
facecolors=self.facecolors_2,
offsets = self.xys,
transOffset = ax.transData)
ax.add_collection(self.collection_2)
def callback_2(self, verts):
self.facecolors_2 = self.collection_2.get_facecolors()
#colorin = colorConverter.to_rgba('red')
#colorout = colorConverter.to_rgba('blue')
p = path.Path(verts)
self.ind = p.contains_points([(d.x, d.y) for d in self.Data2[self.where.colNum]])
#Functionality 2
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso_2)
del self.lasso_2
def onpress_2(self, event):
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
if event.button == 1:
if self.shift_is_held == True:
print "Shift pressed"
self.lasso_2 = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback_2)
print "Shift pressed"
self.where = event.inaxes
self.canvas.widgetlock(self.lasso_2)
def LassoManager3(self, ax, data3, Data3):
self.axes = ax
self.canvas = ax.figure.canvas
self.data3 = data3
self.Data3 = Data3
self.Nxy = len(data3)
self.facecolors_3= [d.color for d in data3]
# print "facecolors",self.facecolors
self.xys = [(d.x, d.y) for d in data3]
# print "xys",self.xys
fig = ax.figure
self.collection_3 = RegularPolyCollection(
fig.dpi, 6, sizes=(0,),
facecolors=self.facecolors_3,
offsets = self.xys,
transOffset = ax.transData)
ax.add_collection(self.collection_3)
def callback_3(self, verts):
self.facecolors_3 = self.collection_3.get_facecolors()
#colorin = colorConverter.to_rgba('red')
#colorout = colorConverter.to_rgba('blue')
p = path.Path(verts)
self.ind = p.contains_points([(d.x, d.y) for d in self.Data3[self.where.colNum]])
#Functionality 3
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso_3)
del self.lasso_3
def onpress_3(self, event):
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
if event.button == 1:
if self.split_is_held == True:
print " Split pressed"
self.lasso_3 = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback_3)
print "Split pressed"
self.where = event.inaxes
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso_3)
Any suggestions?