Added support for union/intersection selections
This commit is contained in:
parent
d4f5a92010
commit
3340b1b7ac
|
@ -459,6 +459,22 @@ class Plot (View):
|
||||||
"""
|
"""
|
||||||
self.selection_listener = listener
|
self.selection_listener = listener
|
||||||
|
|
||||||
|
def update_selection(self, ids, key):
|
||||||
|
"""Returns updated current selection from ids.
|
||||||
|
If a key is pressed we use the appropriate mode.
|
||||||
|
|
||||||
|
key map:
|
||||||
|
shift : union
|
||||||
|
control : intersection
|
||||||
|
"""
|
||||||
|
if key == 'shift':
|
||||||
|
ids = set(ids).union(self._current_selection[self.current_dim])
|
||||||
|
elif key == 'control':
|
||||||
|
ids = set(ids).intersection(self._current_selection[self.current_dim])
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return ids
|
||||||
|
|
||||||
class LineViewPlot(Plot):
|
class LineViewPlot(Plot):
|
||||||
"""Line view plot with percentiles.
|
"""Line view plot with percentiles.
|
||||||
|
@ -609,7 +625,7 @@ class ScatterMarkerPlot(Plot):
|
||||||
self.add(self.canvas)
|
self.add(self.canvas)
|
||||||
self.canvas.show()
|
self.canvas.show()
|
||||||
|
|
||||||
def rectangle_select_callback(self, x1, y1, x2, y2):
|
def rectangle_select_callback(self, x1, y1, x2, y2, key):
|
||||||
ydata = self.yaxis_data
|
ydata = self.yaxis_data
|
||||||
xdata = self.xaxis_data
|
xdata = self.xaxis_data
|
||||||
|
|
||||||
|
@ -622,6 +638,7 @@ class ScatterMarkerPlot(Plot):
|
||||||
assert y1<=y2
|
assert y1<=y2
|
||||||
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
||||||
ids = self.dataset_1.get_identifiers(self.current_dim, index)
|
ids = self.dataset_1.get_identifiers(self.current_dim, index)
|
||||||
|
ids = self.update_selection(ids, key)
|
||||||
self.selection_listener(self.current_dim, ids)
|
self.selection_listener(self.current_dim, ids)
|
||||||
|
|
||||||
def set_current_selection(self, selection):
|
def set_current_selection(self, selection):
|
||||||
|
@ -716,7 +733,7 @@ class ScatterPlot(Plot):
|
||||||
self.ax.draw_artist(self.sc)
|
self.ax.draw_artist(self.sc)
|
||||||
self.canvas.draw()
|
self.canvas.draw()
|
||||||
|
|
||||||
def rectangle_select_callback(self, x1, y1, x2, y2):
|
def rectangle_select_callback(self, x1, y1, x2, y2, key):
|
||||||
ydata = self.yaxis_data
|
ydata = self.yaxis_data
|
||||||
xdata = self.xaxis_data
|
xdata = self.xaxis_data
|
||||||
|
|
||||||
|
@ -729,14 +746,13 @@ class ScatterPlot(Plot):
|
||||||
assert y1<=y2
|
assert y1<=y2
|
||||||
|
|
||||||
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
||||||
|
|
||||||
ids = self.dataset_1.get_identifiers(self.current_dim, index)
|
ids = self.dataset_1.get_identifiers(self.current_dim, index)
|
||||||
|
ids = self.update_selection(ids, key)
|
||||||
self.selection_listener(self.current_dim, ids)
|
self.selection_listener(self.current_dim, ids)
|
||||||
|
|
||||||
def set_current_selection(self, selection):
|
def set_current_selection(self, selection):
|
||||||
ids = selection[self.current_dim] # current identifiers
|
ids = selection[self.current_dim] # current identifiers
|
||||||
if len(ids)==0:
|
if len(ids)==0:
|
||||||
print "nothing selected"
|
|
||||||
return
|
return
|
||||||
#self._toolbar.forward() #update data lims before draw
|
#self._toolbar.forward() #update data lims before draw
|
||||||
index = self.dataset_1.get_indices(self.current_dim, ids)
|
index = self.dataset_1.get_indices(self.current_dim, ids)
|
||||||
|
@ -744,9 +760,9 @@ class ScatterPlot(Plot):
|
||||||
if self._background is None:
|
if self._background is None:
|
||||||
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
|
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
|
||||||
self.canvas.restore_region(self._background)
|
self.canvas.restore_region(self._background)
|
||||||
lw = scipy.zeros(self.xaxis_data.shape,'f')
|
lw = scipy.zeros(self.xaxis_data.shape, 'f')
|
||||||
if len(index)>0:
|
if len(index)>0:
|
||||||
lw.put(2.,index)
|
lw.put(2., index)
|
||||||
self.coll.set_linewidth(lw)
|
self.coll.set_linewidth(lw)
|
||||||
|
|
||||||
if self.use_blit:
|
if self.use_blit:
|
||||||
|
@ -772,12 +788,14 @@ class NetworkPlot(Plot):
|
||||||
kw['prog'] = 'neato'
|
kw['prog'] = 'neato'
|
||||||
if not kw.has_key('pos') or kw['pos']:
|
if not kw.has_key('pos') or kw['pos']:
|
||||||
kw['pos'] = networkx.graphviz_layout(self.graph, kw['prog'])
|
kw['pos'] = networkx.graphviz_layout(self.graph, kw['prog'])
|
||||||
|
if not kw.has_key('nodelist'):
|
||||||
|
kw['nodelist'] = self.dataset.get_identifiers(self.dim_name, sorted=True)
|
||||||
Plot.__init__(self, kw['name'])
|
Plot.__init__(self, kw['name'])
|
||||||
self.current_dim = self.dim_name
|
self.current_dim = self.dim_name
|
||||||
|
|
||||||
# Keep node size and color as dicts for fast lookup
|
# Keep node size and color as dicts for fast lookup
|
||||||
self.node_size = {}
|
self.node_size = {}
|
||||||
if kw.has_key('node_size') and cb.iterable(kw['node_size']):
|
if kw.has_key('node_size') and cbook.iterable(kw['node_size']):
|
||||||
kw.remove('node_size')
|
kw.remove('node_size')
|
||||||
for id, size in zip(self.dataset[self.dim_name], kw['node_size']):
|
for id, size in zip(self.dataset[self.dim_name], kw['node_size']):
|
||||||
self.node_size[id] = size
|
self.node_size[id] = size
|
||||||
|
@ -786,7 +804,7 @@ class NetworkPlot(Plot):
|
||||||
self.node_size[id] = 30
|
self.node_size[id] = 30
|
||||||
|
|
||||||
self.node_color = {}
|
self.node_color = {}
|
||||||
if kw.has_key('node_color') and cb.iterable(kw['node_color']):
|
if kw.has_key('node_color') and cbook.iterable(kw['node_color']):
|
||||||
kw.remove('node_color')
|
kw.remove('node_color')
|
||||||
for id, color in zip(self.dataset[self.dim_name], kw['node_color']):
|
for id, color in zip(self.dataset[self.dim_name], kw['node_color']):
|
||||||
self.node_color[id] = color
|
self.node_color[id] = color
|
||||||
|
@ -812,13 +830,12 @@ class NetworkPlot(Plot):
|
||||||
|
|
||||||
# Initial draw
|
# Initial draw
|
||||||
networkx.draw_networkx(self.graph, ax=self.ax, **kw)
|
networkx.draw_networkx(self.graph, ax=self.ax, **kw)
|
||||||
print "Current dim is now: %s" %self.current_dim
|
del kw['nodelist']
|
||||||
|
|
||||||
def get_toolbar(self):
|
def get_toolbar(self):
|
||||||
return self._toolbar
|
return self._toolbar
|
||||||
|
|
||||||
def rectangle_select_callback(self, x1, y1, x2, y2):
|
def rectangle_select_callback(self, x1, y1, x2, y2, key):
|
||||||
print "In select callbak, current dim is now: %s" %self.current_dim
|
|
||||||
pos = self.keywords['pos']
|
pos = self.keywords['pos']
|
||||||
ydata = scipy.zeros((len(pos),), 'l')
|
ydata = scipy.zeros((len(pos),), 'l')
|
||||||
xdata = scipy.zeros((len(pos),), 'l')
|
xdata = scipy.zeros((len(pos),), 'l')
|
||||||
|
@ -837,9 +854,7 @@ class NetworkPlot(Plot):
|
||||||
y1, y2 = y2, y1
|
y1, y2 = y2, y1
|
||||||
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
||||||
ids = [node_ids[i] for i in index]
|
ids = [node_ids[i] for i in index]
|
||||||
print "Updating listener from network with dim: %s" %self.current_dim
|
ids = self.update_selection(ids, key)
|
||||||
print "ids: "
|
|
||||||
print ids
|
|
||||||
self.selection_listener(self.current_dim, ids)
|
self.selection_listener(self.current_dim, ids)
|
||||||
|
|
||||||
def set_current_selection(self, selection):
|
def set_current_selection(self, selection):
|
||||||
|
@ -943,7 +958,7 @@ class PanPlotMode (PlotMode):
|
||||||
self._button_press = None
|
self._button_press = None
|
||||||
self._button_release = None
|
self._button_release = None
|
||||||
self._motion_notify = None
|
self._motion_notify = None
|
||||||
|
self._xypress = None
|
||||||
self._button_pressed = None
|
self._button_pressed = None
|
||||||
|
|
||||||
def activate(self):
|
def activate(self):
|
||||||
|
@ -1086,7 +1101,7 @@ class PanPlotMode (PlotMode):
|
||||||
self.canvas.mpl_disconnect(self._motion_notify)
|
self.canvas.mpl_disconnect(self._motion_notify)
|
||||||
if not self._xypress: return
|
if not self._xypress: return
|
||||||
self._xypress = None
|
self._xypress = None
|
||||||
self._button_pressed=None
|
self._button_pressed = None
|
||||||
self.canvas.draw()
|
self.canvas.draw()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1144,7 +1159,8 @@ class SelectPlotMode (PlotMode):
|
||||||
|
|
||||||
def _on_select(self, start, end):
|
def _on_select(self, start, end):
|
||||||
self.plot.rectangle_select_callback(start.xdata, start.ydata,
|
self.plot.rectangle_select_callback(start.xdata, start.ydata,
|
||||||
end.xdata, end.ydata)
|
end.xdata, end.ydata, end.key)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PlotToolbar(gtk.Toolbar):
|
class PlotToolbar(gtk.Toolbar):
|
||||||
|
@ -1158,11 +1174,10 @@ class PlotToolbar(gtk.Toolbar):
|
||||||
|
|
||||||
## Maps toolbar buttons to PlotMode objects.
|
## Maps toolbar buttons to PlotMode objects.
|
||||||
self._mode_buttons = {}
|
self._mode_buttons = {}
|
||||||
|
|
||||||
self.set_property('show-arrow', False)
|
self.set_property('show-arrow', False)
|
||||||
|
|
||||||
self.canvas.connect('enter-notify-event', self.on_enter_notify)
|
self.canvas.connect('enter-notify-event', self.on_enter_notify)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
self.add_mode(DefaultPlotMode(self.plot))
|
self.add_mode(DefaultPlotMode(self.plot))
|
||||||
self.add_mode(PanPlotMode(self.plot))
|
self.add_mode(PanPlotMode(self.plot))
|
||||||
self.add_mode(ZoomPlotMode(self.plot))
|
self.add_mode(ZoomPlotMode(self.plot))
|
||||||
|
@ -1254,7 +1269,8 @@ class PlotToolbar(gtk.Toolbar):
|
||||||
|
|
||||||
def on_enter_notify(self, widget, event):
|
def on_enter_notify(self, widget, event):
|
||||||
self.set_mode(active_mode)
|
self.set_mode(active_mode)
|
||||||
|
# need views (plots) to grab key-events
|
||||||
|
widget.grab_focus()
|
||||||
|
|
||||||
# Create a view-changed signal that should be emitted every time
|
# Create a view-changed signal that should be emitted every time
|
||||||
# the active view changes.
|
# the active view changes.
|
||||||
|
|
Reference in New Issue