2006-08-29 11:03:28 +02:00
|
|
|
import os,sys
|
2006-10-09 20:04:39 +02:00
|
|
|
from itertools import izip
|
2006-04-16 20:25:54 +02:00
|
|
|
import pygtk
|
2006-06-01 15:51:16 +02:00
|
|
|
import gobject
|
2006-04-16 20:25:54 +02:00
|
|
|
import gtk
|
2006-10-09 20:04:39 +02:00
|
|
|
import fluents
|
|
|
|
from system import logger
|
2006-04-16 20:25:54 +02:00
|
|
|
import matplotlib
|
|
|
|
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
|
2006-10-09 20:04:39 +02:00
|
|
|
from matplotlib.backend_bases import NavigationToolbar2,cursors
|
|
|
|
from matplotlib.backends.backend_gtk import FileChooserDialog,cursord
|
|
|
|
from matplotlib.widgets import SubplotTool,RectangleSelector
|
2006-04-16 20:25:54 +02:00
|
|
|
from matplotlib.axes import Subplot
|
|
|
|
from matplotlib.figure import Figure
|
2006-09-18 19:23:34 +02:00
|
|
|
from matplotlib import cm,cbook
|
|
|
|
from pylab import Polygon
|
|
|
|
from matplotlib.collections import LineCollection
|
|
|
|
from matplotlib.mlab import prctile
|
2006-08-01 15:22:39 +02:00
|
|
|
import networkx
|
2006-10-09 20:04:39 +02:00
|
|
|
import scipy
|
|
|
|
|
|
|
|
# global active mode. Used by toolbars to communicate correct mode
|
2006-10-10 23:15:13 +02:00
|
|
|
active_mode = 'default'
|
2006-04-16 20:25:54 +02:00
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
class ObjectTable:
|
|
|
|
"""A 2D table of elements."""
|
|
|
|
|
|
|
|
def __init__(self, xsize=0, ysize=0, creator=None):
|
|
|
|
self._elements = []
|
|
|
|
self._creator = creator or (lambda : None)
|
|
|
|
self.xsize = xsize
|
|
|
|
self.ysize = ysize
|
|
|
|
self.resize(xsize, ysize)
|
|
|
|
|
|
|
|
def resize(self, xsize, ysize):
|
|
|
|
"""Resizes the table by removing and creating elements as required."""
|
|
|
|
# Delete or append new rows
|
|
|
|
del self._elements[ysize:]
|
|
|
|
new_rows = ysize - len(self._elements)
|
|
|
|
self._elements.extend([list() for i in range(new_rows)])
|
|
|
|
|
|
|
|
# Delete or append new columns
|
|
|
|
for row in self._elements:
|
|
|
|
del row[xsize:]
|
|
|
|
new_elems = xsize - len(row)
|
|
|
|
row.extend([self._creator() for i in range(new_elems)])
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
x, y = index
|
|
|
|
return self._elements[y][x]
|
|
|
|
|
|
|
|
def __setitem__(self, index, value):
|
|
|
|
x, y = index
|
|
|
|
self._elements[y][x] = value
|
|
|
|
|
|
|
|
|
|
|
|
class ViewFrame (gtk.Frame):
|
2006-06-01 15:51:16 +02:00
|
|
|
"""
|
|
|
|
A ViewFrame is a gtk bin that contains a view.
|
|
|
|
The ViewFrame is either active or inactive, and belongs to a group of
|
|
|
|
VeiwFrames of which only one can be active at any time.
|
|
|
|
"""
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
def __init__(self, view_frames):
|
|
|
|
gtk.Frame.__init__(self)
|
|
|
|
self.focused = False
|
|
|
|
self.view_frames = view_frames
|
|
|
|
self.empty_view = EmptyView()
|
2006-05-29 13:24:33 +02:00
|
|
|
self._button_event = None
|
2006-05-22 23:43:24 +02:00
|
|
|
|
|
|
|
view_frames.append(self)
|
|
|
|
if len(view_frames) == 1:
|
|
|
|
self.focus()
|
|
|
|
else:
|
2006-08-04 11:32:11 +02:00
|
|
|
self.focused = True
|
2006-05-22 23:43:24 +02:00
|
|
|
self.unfocus()
|
|
|
|
|
2006-05-29 21:14:48 +02:00
|
|
|
# Get dropped views
|
|
|
|
self.drag_dest_set(gtk.DEST_DEFAULT_ALL,
|
|
|
|
[("GTK_TREE_MODEL_ROW", gtk.TARGET_SAME_APP, 7)],
|
|
|
|
gtk.gdk.ACTION_LINK)
|
|
|
|
self.connect("drag-data-received", self.on_drag_data_received)
|
|
|
|
|
2006-05-29 13:24:33 +02:00
|
|
|
# Set view
|
2006-05-22 23:43:24 +02:00
|
|
|
self._view = self.empty_view
|
2006-05-29 13:24:33 +02:00
|
|
|
self._view.connect("button-press-event", self.on_button_press_event)
|
|
|
|
self.add(self._view)
|
|
|
|
self._view.show()
|
2006-05-22 23:43:24 +02:00
|
|
|
self.show()
|
|
|
|
|
|
|
|
def focus(self):
|
|
|
|
"""Gets focus and ensures that no other window is in focus."""
|
|
|
|
if self.focused:
|
2006-08-31 17:35:55 +02:00
|
|
|
self.emit('focus-changed', self, True)
|
2006-05-22 23:43:24 +02:00
|
|
|
return self
|
|
|
|
|
|
|
|
for frame in self.view_frames:
|
|
|
|
frame.unfocus()
|
|
|
|
|
|
|
|
self.set_shadow_type(gtk.SHADOW_IN)
|
|
|
|
self.focused = True
|
2006-06-01 15:51:16 +02:00
|
|
|
self.emit('focus-changed', self, True)
|
2006-05-22 23:43:24 +02:00
|
|
|
return self
|
|
|
|
|
|
|
|
def unfocus(self):
|
2006-05-29 21:14:48 +02:00
|
|
|
"""Removes focus from the ViewFrame. Does nothing if unfocused."""
|
2006-05-22 23:43:24 +02:00
|
|
|
if not self.focused:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.set_shadow_type(gtk.SHADOW_OUT)
|
|
|
|
self.focused = False
|
2006-06-01 15:51:16 +02:00
|
|
|
self.emit('focus-changed', self, False)
|
2006-05-22 23:43:24 +02:00
|
|
|
|
|
|
|
def set_view(self, view):
|
|
|
|
"""Set view to view or to empty view if parameter is None"""
|
2006-05-29 21:14:48 +02:00
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
# if None is passed, use empty view
|
|
|
|
if view == None:
|
|
|
|
view = self.empty_view
|
|
|
|
|
2006-05-29 13:24:33 +02:00
|
|
|
# do nothing if the view is already there
|
|
|
|
if view == self._view:
|
|
|
|
return
|
2006-05-22 23:43:24 +02:00
|
|
|
|
2006-05-29 13:24:33 +02:00
|
|
|
# detach view from current parent
|
|
|
|
view_parent = view.get_parent()
|
|
|
|
if view_parent:
|
|
|
|
view_parent.set_view(None)
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
# switch which widget we are listening to
|
2006-05-29 13:24:33 +02:00
|
|
|
if self._button_event:
|
|
|
|
self._view.disconnect(self._button_event)
|
2006-05-29 21:14:48 +02:00
|
|
|
|
2006-08-31 17:35:55 +02:00
|
|
|
self._button_event = view.connect("button-press-event",
|
|
|
|
self.on_button_press_event)
|
2006-05-22 23:43:24 +02:00
|
|
|
|
|
|
|
# remove old view, set new view
|
|
|
|
self._view.hide()
|
|
|
|
self.remove(self._view)
|
|
|
|
self.add(view)
|
|
|
|
view.show()
|
|
|
|
|
|
|
|
self._view = view
|
|
|
|
|
|
|
|
def get_view(self):
|
|
|
|
"""Returns current view, or None if the empty view is set."""
|
|
|
|
if self._view == self.empty_view:
|
|
|
|
return None
|
|
|
|
return self._view
|
|
|
|
|
|
|
|
def on_button_press_event(self, widget, event):
|
|
|
|
if not self.focused:
|
|
|
|
self.focus()
|
|
|
|
|
2006-08-31 17:35:55 +02:00
|
|
|
def on_drag_data_received(self, widget, drag_context, x, y,
|
|
|
|
selection, info, timestamp):
|
2006-05-29 21:14:48 +02:00
|
|
|
treestore, path = selection.tree_get_row_drag_data()
|
|
|
|
iter = treestore.get_iter(path)
|
2006-10-09 20:04:39 +02:00
|
|
|
obj = treestore.get_value(iter, 2)
|
2006-08-31 17:45:33 +02:00
|
|
|
|
2006-05-29 21:14:48 +02:00
|
|
|
if isinstance(obj, Plot):
|
|
|
|
self.set_view(obj)
|
2006-08-31 15:27:58 +02:00
|
|
|
self.focus()
|
2006-05-29 21:14:48 +02:00
|
|
|
|
|
|
|
|
2006-04-18 00:30:53 +02:00
|
|
|
class MainView (gtk.Notebook):
|
2006-05-22 23:43:24 +02:00
|
|
|
def __init__(self):
|
2006-04-18 00:30:53 +02:00
|
|
|
gtk.Notebook.__init__(self)
|
|
|
|
self.set_show_tabs(False)
|
|
|
|
self.set_show_border(False)
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
self._view_frames = []
|
|
|
|
self._views = ObjectTable(2, 2, lambda : ViewFrame(self._view_frames))
|
|
|
|
self._small_views = gtk.Table(2, 2, True)
|
|
|
|
self._small_views.set_col_spacings(4)
|
|
|
|
self._small_views.set_row_spacings(4)
|
|
|
|
self._large_view = ViewFrame(list())
|
|
|
|
self.update_small_views()
|
2006-06-01 15:51:16 +02:00
|
|
|
|
|
|
|
for vf in self._view_frames:
|
|
|
|
vf.connect('focus-changed', self.on_view_focus_changed)
|
2006-05-22 23:43:24 +02:00
|
|
|
|
|
|
|
self.append_page(self._small_views)
|
|
|
|
self.append_page(self._large_view)
|
|
|
|
self.show()
|
2006-05-29 13:24:33 +02:00
|
|
|
self.set_current_page(0)
|
2006-05-22 23:43:24 +02:00
|
|
|
|
|
|
|
def __getitem__(self, x, y):
|
|
|
|
return self._views[x, y]
|
|
|
|
|
|
|
|
def update_small_views(self):
|
|
|
|
for x in range(self._views.xsize):
|
|
|
|
for y in range(self._views.ysize):
|
|
|
|
child = self._views[x,y]
|
|
|
|
self._small_views.attach(child, x, x+1, y, y+1)
|
2006-04-18 00:30:53 +02:00
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
def get_active_small_view(self):
|
|
|
|
for vf in self._view_frames:
|
|
|
|
if vf.focused:
|
|
|
|
return vf
|
|
|
|
return None
|
|
|
|
|
2006-04-18 00:30:53 +02:00
|
|
|
def goto_large(self):
|
2006-05-29 13:24:33 +02:00
|
|
|
if self.get_current_page() == 1:
|
|
|
|
return
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
vf = self.get_active_small_view()
|
|
|
|
view = vf.get_view()
|
|
|
|
vf.set_view(None)
|
|
|
|
self._large_view.set_view(view)
|
2006-04-18 00:30:53 +02:00
|
|
|
self.set_current_page(1)
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
def goto_small(self):
|
2006-05-29 13:24:33 +02:00
|
|
|
if self.get_current_page() == 0:
|
|
|
|
return
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
vf = self.get_active_small_view()
|
|
|
|
view = self._large_view.get_view()
|
|
|
|
self._large_view.set_view(None)
|
|
|
|
vf.set_view(view)
|
|
|
|
self.set_current_page(0)
|
2006-04-18 00:30:53 +02:00
|
|
|
|
|
|
|
def insert_view(self, view):
|
2006-07-21 16:30:09 +02:00
|
|
|
if self.get_current_page() == 0:
|
|
|
|
vf = self.get_active_small_view()
|
|
|
|
else:
|
|
|
|
vf = self._large_view
|
2006-05-22 23:43:24 +02:00
|
|
|
vf.set_view(view)
|
2006-08-31 12:57:44 +02:00
|
|
|
|
|
|
|
def set_all_plots(self, plots):
|
|
|
|
for vf in self._view_frames:
|
|
|
|
if plots:
|
|
|
|
vf.set_view(plots.pop())
|
|
|
|
else:
|
|
|
|
vf.set_view(None)
|
|
|
|
|
2006-05-22 23:43:24 +02:00
|
|
|
def show(self):
|
|
|
|
for vf in self._view_frames:
|
|
|
|
vf.show()
|
|
|
|
self._small_views.show()
|
|
|
|
gtk.Notebook.show(self)
|
|
|
|
|
2006-06-01 15:51:16 +02:00
|
|
|
def on_view_focus_changed(self, widget, vf, focused):
|
|
|
|
if focused:
|
|
|
|
self.emit('view-changed', vf)
|
2006-05-22 23:43:24 +02:00
|
|
|
|
2006-04-26 14:11:23 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
class View (gtk.Frame):
|
|
|
|
"""The base class of everything that is shown in the center view of fluents.
|
|
|
|
|
|
|
|
Most views should rather subclass Plot, which automatically handles freezing and
|
|
|
|
toolbars, and sets up matplotlib Figure and Canvas objects.
|
|
|
|
"""
|
|
|
|
|
2006-04-26 14:11:23 +02:00
|
|
|
def __init__(self, title):
|
|
|
|
gtk.Frame.__init__(self)
|
|
|
|
self.title = title
|
2006-10-10 23:15:13 +02:00
|
|
|
self.set_shadow_type(gtk.SHADOW_NONE)
|
|
|
|
|
|
|
|
def get_toolbar(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
class EmptyView (View):
|
|
|
|
"""EmptyView is shown in ViewFrames that are unused."""
|
|
|
|
def __init__(self):
|
|
|
|
View.__init__(self, 'Empty view')
|
|
|
|
label = gtk.Label('No view')
|
|
|
|
ebox = gtk.EventBox()
|
|
|
|
ebox.add(label)
|
|
|
|
self.add(ebox)
|
|
|
|
label.show()
|
|
|
|
ebox.show()
|
|
|
|
self.show()
|
|
|
|
|
|
|
|
|
|
|
|
class Plot (View):
|
|
|
|
def __init__(self, title):
|
|
|
|
View.__init__(self, title)
|
|
|
|
|
2006-04-27 16:38:48 +02:00
|
|
|
self.selection_listener = None
|
2006-10-09 20:04:39 +02:00
|
|
|
self.fig = Figure()
|
|
|
|
self.canvas = FigureCanvas(self.fig)
|
2006-08-14 17:01:34 +02:00
|
|
|
self._background = None
|
2006-10-10 23:15:13 +02:00
|
|
|
self._frozen = False
|
|
|
|
self._toolbar = PlotToolbar(self)
|
2006-10-09 20:04:39 +02:00
|
|
|
self.canvas.add_events(gtk.gdk.ENTER_NOTIFY_MASK)
|
2006-10-10 17:23:35 +02:00
|
|
|
self.current_dim = None
|
2006-08-28 14:06:05 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
def set_frozen(self, frozen):
|
|
|
|
"""A frozen plot will not be updated when the current selection is changed."""
|
|
|
|
self._frozen = frozen
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-04-26 14:11:23 +02:00
|
|
|
def get_title(self):
|
|
|
|
return self.title
|
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def get_toolbar(self):
|
|
|
|
return self._toolbar
|
|
|
|
|
2006-10-10 17:23:35 +02:00
|
|
|
def selection_changed(self, dim_name, selection):
|
|
|
|
""" Selection observer handle.
|
|
|
|
|
|
|
|
A selection change in a plot is only drawn if:
|
|
|
|
1.) plot is sensitive to selections (not freezed)
|
|
|
|
2.) plot is visible (has a view)
|
|
|
|
3.) the selections dim_name is the plot's dimension.
|
|
|
|
"""
|
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
if self._frozen \
|
2006-10-10 23:15:13 +02:00
|
|
|
or not self.get_property('visible') \
|
|
|
|
or self.current_dim != dim_name:
|
2006-10-10 17:23:35 +02:00
|
|
|
print "Ignored a selection changed call in plot: %s" %self.get_title()
|
2006-08-30 15:21:08 +02:00
|
|
|
return
|
2006-10-10 23:15:13 +02:00
|
|
|
|
2006-10-10 17:23:35 +02:00
|
|
|
print "Setting current selection in: %s " %self.get_title()
|
2006-08-30 15:21:08 +02:00
|
|
|
self.set_current_selection(selection)
|
2006-04-26 14:11:23 +02:00
|
|
|
|
2006-04-27 16:38:48 +02:00
|
|
|
def set_selection_listener(self, listener):
|
|
|
|
"""Allow project to listen to selections.
|
|
|
|
|
|
|
|
The selection will propagate back to all plots through the
|
|
|
|
selection_changed() method. The listener will be called as
|
|
|
|
listener(dimension_name, ids).
|
|
|
|
"""
|
|
|
|
self.selection_listener = listener
|
2006-04-26 14:11:23 +02:00
|
|
|
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-08-14 11:26:54 +02:00
|
|
|
class LineViewPlot(Plot):
|
|
|
|
"""Line view of current selection, no interaction
|
|
|
|
Only works on 2d-arrays
|
|
|
|
input:
|
|
|
|
-- major_axis : dim_number for line dim (see scipy.ndarray for axis def.)
|
|
|
|
-- minor_axis : needs definition only for higher order arrays
|
|
|
|
ps: slow (cant get linecollection and blit to work)
|
|
|
|
"""
|
2006-10-09 20:04:39 +02:00
|
|
|
def __init__(self, dataset, major_axis=1, minor_axis=None, name="Line view"):
|
2006-08-28 14:06:05 +02:00
|
|
|
self.use_blit = False
|
|
|
|
self._last_index = []
|
2006-08-14 11:26:54 +02:00
|
|
|
self._data = dataset.asarray()
|
|
|
|
self.dataset = dataset
|
2006-04-27 13:03:11 +02:00
|
|
|
Plot.__init__(self, name)
|
2006-08-14 17:01:34 +02:00
|
|
|
self.ax = self.fig.add_subplot(111)
|
|
|
|
self.ax.set_title(self.get_title())
|
2006-08-14 11:26:54 +02:00
|
|
|
self.current_dim = self.dataset.get_dim_name(major_axis)
|
|
|
|
if len(self._data.shape)==2 and not minor_axis:
|
|
|
|
minor_axis = major_axis-1
|
2006-08-30 15:39:32 +02:00
|
|
|
|
2006-08-14 11:26:54 +02:00
|
|
|
#initial draw
|
2006-09-18 19:23:34 +02:00
|
|
|
x_axis = scipy.arange(self._data.shape[minor_axis])
|
|
|
|
self.line_segs=[]
|
|
|
|
for xi in range(self._data.shape[major_axis]):
|
2006-10-09 20:04:39 +02:00
|
|
|
yi = self._data.take([xi], major_axis)
|
2006-09-18 19:23:34 +02:00
|
|
|
self.line_segs.append([(xx,yy) for xx,yy in izip(x_axis,yi)])
|
|
|
|
|
|
|
|
#background
|
|
|
|
xax = scipy.arange(self._data.shape[0])
|
|
|
|
verts_0 = [] #100,0
|
|
|
|
verts_1 = [] # 90,10
|
|
|
|
verts_2 = [] # 75,25
|
|
|
|
med = []
|
|
|
|
for i in xax:
|
2006-10-09 20:04:39 +02:00
|
|
|
pp = prctile(self._data[i,:], [0.,5.,25,50.,75.,95.,100])
|
2006-09-18 19:23:34 +02:00
|
|
|
verts_0.append((i,pp[0]))
|
|
|
|
verts_1.append((i,pp[1]))
|
|
|
|
verts_2.append((i,pp[2]))
|
|
|
|
for i in xax[::-1]:
|
2006-10-09 20:04:39 +02:00
|
|
|
pp = prctile(self._data[i,:], [0.,5.,25,50.,75.,95.,100])
|
|
|
|
verts_0.append((i, pp[-1]))
|
|
|
|
verts_1.append((i, pp[-2]))
|
|
|
|
verts_2.append((i, pp[-3]))
|
2006-09-18 19:23:34 +02:00
|
|
|
med.append(pp[3])
|
|
|
|
|
2006-10-09 20:04:39 +02:00
|
|
|
bck0 = Polygon(verts_0, alpha=.15, lw=0)
|
|
|
|
bck1 = Polygon(verts_1, alpha=.15, lw=0)
|
|
|
|
bck2 = Polygon(verts_2, alpha=.15, lw=0)
|
2006-09-18 19:23:34 +02:00
|
|
|
|
|
|
|
self.ax.add_patch(bck0)
|
|
|
|
self.ax.add_patch(bck1)
|
|
|
|
self.ax.add_patch(bck2)
|
2006-10-09 20:04:39 +02:00
|
|
|
self.ax.plot(xax,med, 'b')
|
2006-09-18 19:23:34 +02:00
|
|
|
self.ax.autoscale_view()
|
2006-08-14 17:01:34 +02:00
|
|
|
|
2006-04-27 13:03:11 +02:00
|
|
|
self.add(self.canvas)
|
|
|
|
self.canvas.show()
|
2006-08-29 11:03:28 +02:00
|
|
|
|
2006-08-30 15:39:32 +02:00
|
|
|
#FIXME: Lineview plot cannot do selections -> disable in toolbar
|
2006-10-10 23:15:13 +02:00
|
|
|
self._toolbar = PlotToolbar(self)
|
2006-10-09 20:04:39 +02:00
|
|
|
self.canvas.mpl_connect('resize_event', self.clear_background)
|
2006-04-27 13:03:11 +02:00
|
|
|
|
2006-10-09 20:04:39 +02:00
|
|
|
def clear_background(self, event):
|
2006-08-14 17:01:34 +02:00
|
|
|
self._background = None
|
|
|
|
|
2006-08-30 15:21:08 +02:00
|
|
|
def set_current_selection(self, selection):
|
2006-08-14 11:26:54 +02:00
|
|
|
ids = selection[self.current_dim] # current identifiers
|
|
|
|
index = self.dataset.get_indices(self.current_dim, ids)
|
2006-08-28 14:06:05 +02:00
|
|
|
if self.use_blit:
|
|
|
|
if self._background is None:
|
2006-10-06 12:20:53 +02:00
|
|
|
self._bbox = self.ax.bbox.deepcopy()
|
2006-08-28 14:06:05 +02:00
|
|
|
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
|
|
self.canvas.restore_region(self._background)
|
2006-08-30 15:39:32 +02:00
|
|
|
|
2006-09-18 19:23:34 +02:00
|
|
|
if len(index)>0: # do we have a selection
|
|
|
|
if len(self.ax.collections)>0:
|
|
|
|
self.ax.collections = []
|
|
|
|
segs = [self.line_segs[i] for i in index]
|
2006-10-09 20:04:39 +02:00
|
|
|
line_coll = LineCollection(segs, colors=(1,0,0,1))
|
2006-10-06 12:20:53 +02:00
|
|
|
line_coll.set_clip_box(self.ax.bbox)
|
|
|
|
self.ax.update_datalim(line_coll.get_verts(self.ax.transData))
|
2006-10-11 14:05:13 +02:00
|
|
|
|
2006-09-18 19:23:34 +02:00
|
|
|
if self.use_blit:
|
|
|
|
self.ax.draw_artist(line_coll)
|
2006-10-06 12:20:53 +02:00
|
|
|
line_coll.get_clip_box().get_bounds()
|
2006-08-28 14:06:05 +02:00
|
|
|
self.canvas.blit()
|
2006-10-06 12:20:53 +02:00
|
|
|
|
2006-08-28 14:06:05 +02:00
|
|
|
else:
|
2006-09-18 19:23:34 +02:00
|
|
|
self.ax.add_collection(line_coll)
|
2006-08-28 14:06:05 +02:00
|
|
|
self.canvas.draw()
|
2006-10-11 14:05:13 +02:00
|
|
|
|
2006-04-27 13:03:11 +02:00
|
|
|
|
2006-08-14 11:26:54 +02:00
|
|
|
class ScatterMarkerPlot(Plot):
|
|
|
|
"""The ScatterMarkerPlot is faster than regular scatterplot, but
|
2006-10-11 14:05:13 +02:00
|
|
|
has no color and size options."""
|
|
|
|
|
|
|
|
def __init__(self, dataset_1, dataset_2, id_dim, sel_dim,
|
|
|
|
id_1, id_2, s=6, name="Scatter plot"):
|
2006-04-27 13:38:40 +02:00
|
|
|
Plot.__init__(self, name)
|
2006-10-06 12:20:53 +02:00
|
|
|
self.use_blit = False
|
|
|
|
self._background = None
|
2006-08-30 15:39:32 +02:00
|
|
|
self.ax = self.fig.add_subplot(111)
|
2006-10-09 20:04:39 +02:00
|
|
|
self.ax.axhline(0, color='k', lw=1., zorder=1)
|
|
|
|
self.ax.axvline(0, color='k', lw=1., zorder=1)
|
2006-04-24 11:53:07 +02:00
|
|
|
self.current_dim = id_dim
|
2006-05-09 15:17:17 +02:00
|
|
|
self.dataset_1 = dataset_1
|
2006-08-29 11:03:28 +02:00
|
|
|
self.ms = s
|
2006-08-28 14:06:05 +02:00
|
|
|
self._selection_line = None
|
2006-05-09 15:17:17 +02:00
|
|
|
x_index = dataset_1[sel_dim][id_1]
|
|
|
|
y_index = dataset_2[sel_dim][id_2]
|
2006-10-09 20:04:39 +02:00
|
|
|
self.xaxis_data = dataset_1._array[:, x_index]
|
|
|
|
self.yaxis_data = dataset_2._array[:, y_index]
|
|
|
|
self.ax.plot(self.xaxis_data, self.yaxis_data, 'o', markeredgewidth=0, markersize=s)
|
2006-08-30 15:39:32 +02:00
|
|
|
self.ax.set_title(self.get_title())
|
2006-04-16 20:25:54 +02:00
|
|
|
self.add(self.canvas)
|
|
|
|
self.canvas.show()
|
|
|
|
|
2006-04-26 14:11:23 +02:00
|
|
|
def rectangle_select_callback(self, x1, y1, x2, y2):
|
2006-10-10 17:23:35 +02:00
|
|
|
print "Rectangle select happened in: %s" %self.get_title()
|
2006-04-19 12:37:44 +02:00
|
|
|
ydata = self.yaxis_data
|
|
|
|
xdata = self.xaxis_data
|
2006-04-25 12:08:12 +02:00
|
|
|
|
|
|
|
# find indices of selected area
|
2006-04-19 12:37:44 +02:00
|
|
|
if x1>x2:
|
2006-08-01 15:22:39 +02:00
|
|
|
x1, x2 = x2, x1
|
|
|
|
if y1>y2:
|
|
|
|
y1, y2 = y2, y1
|
|
|
|
assert x1<=x2
|
|
|
|
assert y1<=y2
|
2006-08-31 12:04:19 +02:00
|
|
|
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
2006-05-09 15:17:17 +02:00
|
|
|
ids = self.dataset_1.get_identifiers(self.current_dim, index)
|
2006-05-03 13:40:12 +02:00
|
|
|
self.selection_listener(self.current_dim, ids)
|
2006-04-19 20:25:44 +02:00
|
|
|
|
2006-08-30 15:21:08 +02:00
|
|
|
def set_current_selection(self, selection):
|
2006-04-27 16:38:48 +02:00
|
|
|
ids = selection[self.current_dim] # current identifiers
|
2006-05-09 15:17:17 +02:00
|
|
|
index = self.dataset_1.get_indices(self.current_dim, ids)
|
2006-10-06 12:20:53 +02:00
|
|
|
if self.use_blit:
|
|
|
|
if self._background is None:
|
|
|
|
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
|
|
self.canvas.restore_region(self._background)
|
|
|
|
if not len(index)>0:
|
|
|
|
return
|
2006-08-31 12:04:19 +02:00
|
|
|
xdata_new = self.xaxis_data.take(index) #take data
|
|
|
|
ydata_new = self.yaxis_data.take(index)
|
2006-08-08 13:09:59 +02:00
|
|
|
#remove old selection
|
2006-08-28 14:06:05 +02:00
|
|
|
if self._selection_line:
|
|
|
|
self.ax.lines.remove(self._selection_line)
|
2006-08-30 15:39:32 +02:00
|
|
|
|
2006-10-09 20:04:39 +02:00
|
|
|
self._selection_line, = self.ax.plot(xdata_new, ydata_new,marker='o', markersize=self.ms, linestyle=None, markerfacecolor='r')
|
2006-08-30 15:39:32 +02:00
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
# self._toolbar.forward() #update data lims before draw
|
2006-10-06 12:20:53 +02:00
|
|
|
if self.use_blit:
|
|
|
|
self.ax.draw_artist(self._selection_line)
|
|
|
|
self.canvas.blit()
|
|
|
|
else:
|
2006-10-10 17:23:35 +02:00
|
|
|
print "A draw happened in: %s" %self.get_title()
|
2006-10-06 12:20:53 +02:00
|
|
|
self.canvas.draw()
|
2006-04-26 14:11:23 +02:00
|
|
|
|
2006-08-30 15:39:32 +02:00
|
|
|
|
2006-08-14 18:19:51 +02:00
|
|
|
class ScatterPlot(Plot):
|
2006-10-06 12:20:53 +02:00
|
|
|
"""The ScatterPlot is slower than scattermarker, but has size option."""
|
|
|
|
def __init__(self, dataset_1, dataset_2, id_dim, sel_dim, id_1, id_2,c='b',s=30,sel_dim_2=None, name="Scatter plot"):
|
2006-08-14 18:19:51 +02:00
|
|
|
Plot.__init__(self, name)
|
2006-10-06 12:20:53 +02:00
|
|
|
self.use_blit = False
|
2006-08-30 15:39:32 +02:00
|
|
|
self.ax = self.fig.add_subplot(111)
|
2006-08-14 18:19:51 +02:00
|
|
|
self.current_dim = id_dim
|
|
|
|
self.dataset_1 = dataset_1
|
|
|
|
x_index = dataset_1[sel_dim][id_1]
|
2006-10-06 12:20:53 +02:00
|
|
|
if sel_dim_2:
|
|
|
|
y_index = dataset_2[sel_dim_2][id_2]
|
|
|
|
else:
|
|
|
|
y_index = dataset_2[sel_dim][id_2]
|
2006-10-09 20:04:39 +02:00
|
|
|
self.xaxis_data = dataset_1._array[:, x_index]
|
|
|
|
self.yaxis_data = dataset_2._array[:, y_index]
|
2006-08-31 12:04:19 +02:00
|
|
|
lw = scipy.zeros(self.xaxis_data.shape)
|
2006-10-09 20:04:39 +02:00
|
|
|
sc = self.ax.scatter(self.xaxis_data, self.yaxis_data, s=s, c=c, linewidth=lw, edgecolor='k', alpha=.6, cmap = cm.jet)
|
2006-09-18 19:23:34 +02:00
|
|
|
if len(c)>1:
|
2006-10-09 20:04:39 +02:00
|
|
|
self.fig.colorbar(sc,ticks=[], fraction=.05)
|
|
|
|
self.ax.axhline(0, color='k', lw=1., zorder=1)
|
|
|
|
self.ax.axvline(0, color='k', lw=1., zorder=1)
|
2006-08-30 15:39:32 +02:00
|
|
|
self.ax.set_title(self.get_title())
|
2006-08-14 18:19:51 +02:00
|
|
|
# collection
|
2006-08-31 12:04:19 +02:00
|
|
|
self.coll = self.ax.collections[0]
|
2006-08-30 15:21:08 +02:00
|
|
|
|
|
|
|
# add canvas to widget
|
2006-08-14 18:19:51 +02:00
|
|
|
self.add(self.canvas)
|
|
|
|
self.canvas.show()
|
|
|
|
|
|
|
|
def rectangle_select_callback(self, x1, y1, x2, y2):
|
2006-10-10 17:23:35 +02:00
|
|
|
print "Rectangle select happened in: %s" %self.get_title()
|
2006-08-14 18:19:51 +02:00
|
|
|
ydata = self.yaxis_data
|
|
|
|
xdata = self.xaxis_data
|
|
|
|
|
|
|
|
# find indices of selected area
|
|
|
|
if x1>x2:
|
|
|
|
x1, x2 = x2, x1
|
|
|
|
if y1>y2:
|
|
|
|
y1, y2 = y2, y1
|
|
|
|
assert x1<=x2
|
|
|
|
assert y1<=y2
|
|
|
|
|
2006-08-31 12:04:19 +02:00
|
|
|
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
2006-08-14 18:19:51 +02:00
|
|
|
ids = self.dataset_1.get_identifiers(self.current_dim, index)
|
|
|
|
self.selection_listener(self.current_dim, ids)
|
|
|
|
|
2006-08-30 15:21:08 +02:00
|
|
|
def set_current_selection(self, selection):
|
2006-08-14 18:19:51 +02:00
|
|
|
ids = selection[self.current_dim] # current identifiers
|
2006-09-18 19:23:34 +02:00
|
|
|
if len(ids)==0:
|
2006-10-10 17:23:35 +02:00
|
|
|
print "nothing selected"
|
2006-09-18 19:23:34 +02:00
|
|
|
return
|
2006-10-11 14:05:13 +02:00
|
|
|
#self._toolbar.forward() #update data lims before draw
|
2006-08-14 18:19:51 +02:00
|
|
|
index = self.dataset_1.get_indices(self.current_dim, ids)
|
2006-10-06 12:20:53 +02:00
|
|
|
if self.use_blit:
|
|
|
|
if self._background is None:
|
|
|
|
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
|
|
self.canvas.restore_region(self._background)
|
2006-08-31 12:04:19 +02:00
|
|
|
lw = scipy.zeros(self.xaxis_data.shape)
|
2006-09-18 19:23:34 +02:00
|
|
|
if len(index)>0:
|
|
|
|
lw.put(2.,index)
|
2006-08-14 18:19:51 +02:00
|
|
|
self.coll.set_linewidth(lw)
|
2006-10-10 17:23:35 +02:00
|
|
|
|
2006-10-06 12:20:53 +02:00
|
|
|
if self.use_blit:
|
2006-10-10 17:23:35 +02:00
|
|
|
print "A blit happened in : %s " %self.get_title()
|
2006-10-06 12:20:53 +02:00
|
|
|
self.canvas.blit()
|
|
|
|
self.ax.draw_artist(self.coll)
|
|
|
|
else:
|
2006-10-10 17:23:35 +02:00
|
|
|
print "A draw happened in : %s " %self.get_title()
|
2006-10-06 12:20:53 +02:00
|
|
|
self.canvas.draw()
|
2006-08-31 12:04:19 +02:00
|
|
|
|
2006-08-14 18:19:51 +02:00
|
|
|
|
2006-07-31 16:57:24 +02:00
|
|
|
class NetworkPlot(Plot):
|
2006-08-03 16:30:06 +02:00
|
|
|
def __init__(self, dataset, **kw):
|
2006-08-01 15:22:39 +02:00
|
|
|
# Set member variables and call superclass' constructor
|
2006-08-03 16:30:06 +02:00
|
|
|
self.graph = dataset.asnetworkx()
|
|
|
|
self.dataset = dataset
|
2006-08-01 15:22:39 +02:00
|
|
|
self.keywords = kw
|
|
|
|
self.dim_name = self.dataset.get_dim_name(0)
|
2006-10-10 17:23:35 +02:00
|
|
|
self.current_dim = self.dim_name
|
2006-08-01 15:22:39 +02:00
|
|
|
if not kw.has_key('name'):
|
|
|
|
kw['name'] = self.dataset.get_name()
|
|
|
|
if not kw.has_key('prog'):
|
|
|
|
kw['prog'] = 'neato'
|
|
|
|
if not kw.has_key('pos') or kw['pos']:
|
2006-10-03 23:06:19 +02:00
|
|
|
kw['pos'] = networkx.pygraphviz_layout(self.graph, kw['prog'])
|
2006-08-01 15:22:39 +02:00
|
|
|
Plot.__init__(self, kw['name'])
|
|
|
|
|
|
|
|
# Keep node size and color as dicts for fast lookup
|
2006-08-03 16:30:06 +02:00
|
|
|
self.node_size = {}
|
2006-08-01 15:22:39 +02:00
|
|
|
if kw.has_key('node_size') and cb.iterable(kw['node_size']):
|
|
|
|
kw.remove('node_size')
|
|
|
|
for id, size in zip(self.dataset[self.dim_name], kw['node_size']):
|
|
|
|
self.node_size[id] = size
|
2006-08-03 16:30:06 +02:00
|
|
|
else:
|
|
|
|
for id in dataset[self.dim_name]:
|
|
|
|
self.node_size[id] = 40
|
2006-08-01 15:22:39 +02:00
|
|
|
|
2006-08-03 16:30:06 +02:00
|
|
|
self.node_color = {}
|
2006-08-01 15:22:39 +02:00
|
|
|
if kw.has_key('node_color') and cb.iterable(kw['node_color']):
|
|
|
|
kw.remove('node_color')
|
|
|
|
for id, color in zip(self.dataset[self.dim_name], kw['node_color']):
|
|
|
|
self.node_color[id] = color
|
2006-08-03 16:30:06 +02:00
|
|
|
else:
|
|
|
|
self.node_color = None
|
|
|
|
# for id in self.dataset[self.dim_name]:
|
|
|
|
# self.node_color[id] = 'red'
|
|
|
|
|
|
|
|
if kw.has_key('node_color'):
|
|
|
|
kw.pop('node_color')
|
2006-08-01 15:22:39 +02:00
|
|
|
|
|
|
|
self.ax = self.fig.add_subplot(111)
|
2006-08-28 14:06:05 +02:00
|
|
|
self.ax.set_position([0.01,0.01,.99,.99])
|
|
|
|
self.ax.set_xticks([])
|
|
|
|
self.ax.set_yticks([])
|
2006-08-01 15:22:39 +02:00
|
|
|
# FIXME: ax shouldn't be in kw at all
|
|
|
|
if kw.has_key('ax'):
|
|
|
|
kw.pop('ax')
|
|
|
|
|
|
|
|
# Add canvas and show
|
2006-07-31 16:57:24 +02:00
|
|
|
self.add(self.canvas)
|
|
|
|
self.canvas.show()
|
|
|
|
|
2006-08-01 15:22:39 +02:00
|
|
|
# Initial draw
|
|
|
|
networkx.draw_networkx(self.graph, ax=self.ax, **kw)
|
|
|
|
|
2006-07-31 16:57:24 +02:00
|
|
|
def get_toolbar(self):
|
|
|
|
return self._toolbar
|
|
|
|
|
2006-08-01 15:22:39 +02:00
|
|
|
def rectangle_select_callback(self, x1, y1, x2, y2):
|
2006-08-01 16:26:33 +02:00
|
|
|
pos = self.keywords['pos']
|
2006-10-09 20:04:39 +02:00
|
|
|
ydata = scipy.zeros((len(pos),), 'l')
|
|
|
|
xdata = scipy.zeros((len(pos),), 'l')
|
2006-08-01 15:22:39 +02:00
|
|
|
node_ids = []
|
|
|
|
c = 0
|
|
|
|
for name,(x,y) in pos.items():
|
|
|
|
node_ids.append(name)
|
|
|
|
xdata[c] = x
|
|
|
|
ydata[c] = y
|
|
|
|
c+=1
|
|
|
|
|
|
|
|
# find indices of selected area
|
|
|
|
if x1 > x2:
|
|
|
|
x1, x2 = x2, x1
|
|
|
|
if y1 > y2:
|
|
|
|
y1, y2 = y2, y1
|
2006-09-18 19:23:34 +02:00
|
|
|
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
|
|
|
|
|
2006-08-01 15:22:39 +02:00
|
|
|
|
2006-10-06 12:20:53 +02:00
|
|
|
ids = [node_ids[i] for i in index]
|
2006-10-10 17:23:35 +02:00
|
|
|
self.selection_listener(self.current_dim, ids)
|
2006-08-01 15:22:39 +02:00
|
|
|
|
2006-08-30 15:21:08 +02:00
|
|
|
def set_current_selection(self, selection):
|
2006-10-10 17:23:35 +02:00
|
|
|
ids = selection[self.current_dim] # current identifiers
|
2006-08-03 16:30:06 +02:00
|
|
|
node_set = set(self.graph.nodes())
|
|
|
|
|
|
|
|
selected_nodes = list(ids.intersection(node_set))
|
|
|
|
unselected_nodes = list(node_set.difference(ids))
|
|
|
|
|
|
|
|
if self.node_color:
|
|
|
|
unselected_colors = [self.node_color[x] for x in unselected_nodes]
|
|
|
|
else:
|
|
|
|
unselected_colors = 'red'
|
2006-08-01 15:22:39 +02:00
|
|
|
|
2006-08-03 16:30:06 +02:00
|
|
|
if self.node_size:
|
|
|
|
unselected_sizes = [self.node_size[x] for x in unselected_nodes]
|
|
|
|
selected_sizes = [self.node_size[x] for x in selected_nodes]
|
2006-08-01 15:22:39 +02:00
|
|
|
|
|
|
|
self.ax.clear()
|
2006-08-01 16:26:33 +02:00
|
|
|
networkx.draw_networkx_edges(self.graph, edge_list=self.graph.edges(), \
|
|
|
|
ax=self.ax, **self.keywords)
|
2006-08-28 14:06:05 +02:00
|
|
|
networkx.draw_networkx_labels(self.graph,**self.keywords)
|
2006-08-03 16:30:06 +02:00
|
|
|
if unselected_nodes:
|
|
|
|
networkx.draw_networkx_nodes(self.graph, nodelist=unselected_nodes, \
|
|
|
|
node_color='r', node_size=unselected_sizes, ax=self.ax, **self.keywords)
|
2006-08-01 15:22:39 +02:00
|
|
|
|
2006-08-03 16:30:06 +02:00
|
|
|
if selected_nodes:
|
|
|
|
networkx.draw_networkx_nodes(self.graph, nodelist=selected_nodes, \
|
|
|
|
node_color='k', node_size=selected_sizes, ax=self.ax, **self.keywords)
|
2006-08-01 15:22:39 +02:00
|
|
|
|
|
|
|
self.canvas.draw()
|
|
|
|
|
2006-07-31 16:57:24 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
class PlotMode:
|
|
|
|
"""A PlotMode object corresponds to a mouse mode in a plot.
|
|
|
|
|
|
|
|
When a mode is selected in the toolbar, the PlotMode corresponding
|
|
|
|
to the toolbar button is activated by calling setup(ax) for the axis
|
|
|
|
system ax.
|
|
|
|
"""
|
2006-10-11 14:05:13 +02:00
|
|
|
def __init__(self, plot, name, tooltip, image_file):
|
2006-10-10 23:15:13 +02:00
|
|
|
self.name = name
|
|
|
|
self.tooltip = tooltip
|
|
|
|
self.image_file = image_file
|
2006-10-11 14:05:13 +02:00
|
|
|
self.plot = plot
|
|
|
|
self.canvas = plot.canvas
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
def get_icon(self):
|
|
|
|
"""Returns the icon for the PlotMode"""
|
|
|
|
fname = os.path.join(fluents.ICONDIR, self.image_file)
|
|
|
|
image = gtk.Image()
|
|
|
|
image.set_from_file(fname)
|
|
|
|
return image
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def activate(self):
|
2006-10-10 23:15:13 +02:00
|
|
|
pass
|
|
|
|
|
|
|
|
def deactivate(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class DefaultPlotMode (PlotMode):
|
2006-10-11 14:05:13 +02:00
|
|
|
def __init__(self, plot):
|
|
|
|
PlotMode.__init__(self, plot, 'default', 'Default mode', 'cursor.png')
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
class PanPlotMode (PlotMode):
|
2006-10-11 14:05:13 +02:00
|
|
|
def __init__(self, plot):
|
|
|
|
PlotMode.__init__(self, plot, 'pan',
|
2006-10-10 23:15:13 +02:00
|
|
|
'Pan axes with left mouse, zoom with right',
|
|
|
|
'move.png')
|
|
|
|
self._button_press = None
|
|
|
|
self._button_release = None
|
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def activate(self):
|
2006-10-10 23:15:13 +02:00
|
|
|
self._button_press = self.canvas.mpl_connect(
|
|
|
|
'button_press_event', self._on_button_press)
|
|
|
|
self._button_relese = self.canvas.mpl_connect(
|
|
|
|
'button_release_event', self._on_button_release)
|
|
|
|
self.mode = 'pan/zoom mode'
|
|
|
|
|
|
|
|
def deactivate(self):
|
|
|
|
if self._button_press:
|
|
|
|
self.canvas.mpl_disconnect(self._button_press)
|
|
|
|
|
|
|
|
if self._button_release:
|
|
|
|
self.canvas.mpl_disconnect(self._button_release)
|
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def _on_button_press(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def _on_button_release(self, event):
|
|
|
|
pass
|
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
class ZoomPlotMode (PlotMode):
|
2006-10-11 14:05:13 +02:00
|
|
|
def __init__(self, plot):
|
|
|
|
PlotMode.__init__(self, plot, 'zoom',
|
2006-10-10 23:15:13 +02:00
|
|
|
'Zoom to rectangle','zoom_to_rect.png')
|
2006-10-11 14:05:13 +02:00
|
|
|
self._selectors = {}
|
2006-10-10 23:15:13 +02:00
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def activate(self):
|
|
|
|
for ax in self.canvas.figure.get_axes():
|
|
|
|
props = dict(facecolor = 'blue',
|
|
|
|
edgecolor = 'black',
|
|
|
|
alpha = 0.3,
|
|
|
|
fill = True)
|
|
|
|
|
|
|
|
rs = RectangleSelector(ax, self._on_select, drawtype='box',
|
|
|
|
useblit=True, rectprops = props)
|
|
|
|
self.canvas.draw()
|
|
|
|
self._selectors[rs] = ax
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
def deactivate(self):
|
2006-10-11 14:05:13 +02:00
|
|
|
for sel in self.selectors:
|
|
|
|
self.canvas.mpl_disconnect(sel.onmove)
|
|
|
|
self.canvas.mpl_disconnect(sel.press)
|
|
|
|
self.canvas.mpl_disconnect(sel.release)
|
|
|
|
self.canvas.mpl_disconnect(sel.update_background)
|
|
|
|
self._selectors = {}
|
2006-10-10 23:15:13 +02:00
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def _on_select(self, start, end):
|
|
|
|
min_x = min(start.xdata, end.xdata)
|
|
|
|
min_y = min(start.ydata, end.ydata)
|
|
|
|
max_x = max(start.xdata, end.xdata)
|
|
|
|
max_y = max(start.ydata, end.ydata)
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
class SelectPlotMode (PlotMode):
|
2006-10-11 14:05:13 +02:00
|
|
|
def __init__(self, plot):
|
|
|
|
PlotMode.__init__(self, plot, 'select',
|
2006-10-10 23:15:13 +02:00
|
|
|
'Select within rectangle', 'select.png')
|
2006-10-11 14:05:13 +02:00
|
|
|
self._selectors = {}
|
2006-10-10 23:15:13 +02:00
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
def activate(self):
|
|
|
|
for ax in self.canvas.figure.get_axes():
|
|
|
|
props = dict(facecolor = 'blue',
|
|
|
|
edgecolor = 'black',
|
|
|
|
alpha = 0.3,
|
|
|
|
fill = True)
|
2006-10-10 23:15:13 +02:00
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
rs = RectangleSelector(ax, self._on_select, drawtype='box',
|
2006-10-10 23:15:13 +02:00
|
|
|
useblit=True, rectprops = props)
|
2006-10-11 14:05:13 +02:00
|
|
|
self.canvas.draw()
|
|
|
|
self._selectors[rs] = ax
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
def deactivate(self):
|
|
|
|
for sel in self.selectors:
|
|
|
|
self.canvas.mpl_disconnect(sel.onmove)
|
|
|
|
self.canvas.mpl_disconnect(sel.press)
|
|
|
|
self.canvas.mpl_disconnect(sel.release)
|
|
|
|
self.canvas.mpl_disconnect(sel.update_background)
|
2006-10-11 14:05:13 +02:00
|
|
|
self._selectors = {}
|
|
|
|
|
|
|
|
def _on_select(self, start, end):
|
|
|
|
self.plot.rectangle_select_callback(start.xdata, start.ydata,
|
|
|
|
end.xdata, end.ydata)
|
2006-10-10 23:15:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
class PlotToolbar(gtk.Toolbar):
|
|
|
|
|
|
|
|
def __init__(self, plot):
|
|
|
|
gtk.Toolbar.__init__(self)
|
|
|
|
self.plot = plot
|
|
|
|
self.canvas = plot.canvas
|
|
|
|
self._current_mode = None
|
2006-10-09 20:04:39 +02:00
|
|
|
self.tooltips = gtk.Tooltips()
|
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
## Maps toolbar buttons to PlotMode objects.
|
|
|
|
self._mode_buttons = {}
|
|
|
|
|
|
|
|
self.set_property('show-arrow', False)
|
|
|
|
|
|
|
|
#canvas.connect('enter-notify-event', self.on_enter_notify)
|
|
|
|
self.show()
|
2006-10-11 14:05:13 +02:00
|
|
|
self.add_mode(DefaultPlotMode(self.plot))
|
|
|
|
self.add_mode(PanPlotMode(self.plot))
|
|
|
|
self.add_mode(ZoomPlotMode(self.plot))
|
|
|
|
self.add_mode(SelectPlotMode(self.plot))
|
2006-10-09 20:04:39 +02:00
|
|
|
self.show_all()
|
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
def add_mode(self, mode):
|
|
|
|
"""Adds a new mode to the toolbar."""
|
|
|
|
|
|
|
|
if len(self._mode_buttons) > 0:
|
|
|
|
other = self._mode_buttons.keys()[0]
|
|
|
|
else:
|
|
|
|
other = None
|
|
|
|
|
|
|
|
btn = gtk.RadioToolButton(other)
|
|
|
|
btn.set_icon_widget(mode.get_icon())
|
|
|
|
btn.set_tooltip(self.tooltips, mode.tooltip, 'Private')
|
|
|
|
btn.connect('toggled', self._on_mode_toggle)
|
|
|
|
|
|
|
|
self._mode_buttons[btn] = mode
|
|
|
|
self.insert(btn, -1)
|
|
|
|
|
|
|
|
if self._current_mode == None:
|
|
|
|
self._current_mode = mode
|
|
|
|
|
|
|
|
def get_mode(self):
|
|
|
|
"""Returns the active mode name."""
|
|
|
|
if self._current_mode:
|
|
|
|
return self._current_mode.name
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_mode_by_name(self, mode_name):
|
|
|
|
"""Returns the mode with the given name or None."""
|
|
|
|
for m in self._mode_buttons.values():
|
|
|
|
if m.name == mode_name:
|
|
|
|
return m
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_button(self, mode_name):
|
|
|
|
"""Returns the button that corresponds to a mode name."""
|
|
|
|
for b, m in self._mode_buttons.items():
|
2006-10-11 14:05:13 +02:00
|
|
|
if m.name == mode_name:
|
|
|
|
print "Found button for mode: %s" % mode_name
|
2006-10-10 23:15:13 +02:00
|
|
|
return b
|
2006-10-11 14:05:13 +02:00
|
|
|
print "Couldn't find button for mode: %s" % mode_name
|
2006-10-10 23:15:13 +02:00
|
|
|
return None
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
def set_mode(self, mode_name):
|
|
|
|
"""Sets a mode by name. Returns the mode or None"""
|
|
|
|
if mode_name == self._current_mode.name:
|
|
|
|
return None
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
if self._current_mode:
|
|
|
|
self._current_mode.deactivate()
|
|
|
|
|
|
|
|
new_mode = self.get_mode_by_name(mode_name)
|
|
|
|
if new_mode:
|
2006-10-11 14:05:13 +02:00
|
|
|
new_mode.activate()
|
2006-10-10 23:15:13 +02:00
|
|
|
self._current_mode = self.get_mode_by_name(mode_name)
|
|
|
|
else:
|
|
|
|
logger.log('warning', 'No such mode: %s' % mode_name)
|
2006-10-11 14:05:13 +02:00
|
|
|
|
|
|
|
if self.get_button(mode_name) and not self.get_button(mode_name).get_active():
|
|
|
|
self.get_button(mode_name).set_active(True)
|
2006-10-10 23:15:13 +02:00
|
|
|
return self._current_mode
|
|
|
|
|
2006-10-11 14:05:13 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
def _on_mode_toggle(self, button):
|
|
|
|
if button.get_active():
|
|
|
|
self.set_mode(self._mode_buttons[button].name)
|
|
|
|
|
|
|
|
# def show(self):
|
|
|
|
# for b in self._mode_buttons.keys():
|
|
|
|
# b.show()
|
|
|
|
# gtk.Toolbar.show(self)
|
|
|
|
|
|
|
|
# class PlotToolbar(NavigationToolbar2,gtk.Toolbar):
|
|
|
|
# # list of toolitems to add to the toolbar, format is:
|
|
|
|
# # text, tooltip_text, image_file, callback(str)
|
|
|
|
# toolitems = (
|
|
|
|
# ('Home', 'Reset original view', 'home.png', 'home'),
|
|
|
|
# #('Back', 'Back to previous view','back.png', 'back'),
|
|
|
|
# #('Forward', 'Forward to next view','forward.png', 'forward'),
|
|
|
|
# #('Subplots', 'Configure subplots','subplots.png', 'configure_subplots'),
|
|
|
|
# ('Save', 'Save the figure','filesave.png', 'save_figure'),
|
|
|
|
# )
|
|
|
|
|
|
|
|
# def __init__(self, canvas, plot):
|
|
|
|
# self.win = None
|
|
|
|
# self.plot = plot
|
|
|
|
# gtk.Toolbar.__init__(self)
|
|
|
|
# NavigationToolbar2.__init__(self, canvas)
|
|
|
|
# self._idleId = 0
|
|
|
|
# self._select_callback = None
|
|
|
|
# canvas.connect('enter-notify-event', self.on_enter_notify)
|
|
|
|
|
|
|
|
# def _init_toolbar(self):
|
|
|
|
# self.set_style(gtk.TOOLBAR_ICONS)
|
|
|
|
# self.tooltips = gtk.Tooltips()
|
|
|
|
# self._modes = {}
|
|
|
|
# self._selector = None
|
|
|
|
# self.set_property('show-arrow', False)
|
|
|
|
# basedir = fluents.ICONDIR
|
|
|
|
|
|
|
|
# # setup base buttons
|
|
|
|
# for text, tooltip_text, image_file, callback in self.toolitems:
|
|
|
|
# if text is None:
|
|
|
|
# self.insert(gtk.SeparatorToolItem(), -1 )
|
|
|
|
# continue
|
|
|
|
# fname = os.path.join(basedir, image_file)
|
|
|
|
# image = gtk.Image()
|
|
|
|
# image.set_from_file(fname)
|
|
|
|
# tbutton = gtk.ToolButton(image, text)
|
|
|
|
# self.insert(tbutton, -1)
|
|
|
|
# tbutton.connect('clicked', getattr(self, callback))
|
|
|
|
# tbutton.set_tooltip(self.tooltips, tooltip_text, 'Private')
|
|
|
|
|
|
|
|
# self.insert(gtk.SeparatorToolItem(), -1)
|
|
|
|
|
|
|
|
# # mode/state buttons
|
|
|
|
# rbutton = None
|
|
|
|
# for text,tooltip_text,image_file,callback in self.radiobuttons:
|
|
|
|
# if text is None:
|
|
|
|
# self.insert(gtk.SeparatorToolItem(), -1 )
|
|
|
|
# continue
|
|
|
|
# fname = os.path.join(basedir, image_file)
|
|
|
|
# image = gtk.Image()
|
|
|
|
# image.set_from_file(fname)
|
|
|
|
# rbutton = gtk.RadioToolButton(rbutton)
|
|
|
|
# rbutton.set_icon_widget(image)
|
|
|
|
# rbutton.connect('toggled', getattr(self, callback))
|
|
|
|
# rbutton.set_tooltip(self.tooltips, tooltip_text, 'Private')
|
|
|
|
# self._modes[text] = rbutton
|
|
|
|
# a self.insert(rbutton, -1)
|
|
|
|
|
|
|
|
# self.insert(gtk.SeparatorToolItem(), -1)
|
|
|
|
|
|
|
|
# toolitem = gtk.ToolItem()
|
|
|
|
# self.insert(toolitem, -1)
|
|
|
|
# self.message = gtk.Label()
|
|
|
|
# toolitem.add(self.message)
|
|
|
|
|
|
|
|
# self.tb_freeze = gtk.ToolItem()
|
|
|
|
# self.chk = gtk.CheckButton ()
|
|
|
|
# self.chk.set_label ('Freeze')
|
|
|
|
# self.tb_freeze.add (self.chk)
|
|
|
|
# self.tb_freeze.set_tooltip(self.tooltips, 'Freeze current selection')
|
|
|
|
# self.insert(self.tb_freeze,-1)
|
|
|
|
|
|
|
|
# toolitem = gtk.SeparatorToolItem()
|
|
|
|
# self.insert(toolitem, -1)
|
|
|
|
|
|
|
|
# self.show_all()
|
|
|
|
|
|
|
|
# self.fileselect = FileChooserDialog(title='Save the figure', parent=self.win,)
|
|
|
|
|
|
|
|
|
|
|
|
# def on_enter_notify(self, widget, event):
|
|
|
|
# if self._active != active_mode:
|
|
|
|
# self.set_mode(active_mode)
|
|
|
|
# self.set_mode(active_mode)
|
|
|
|
|
|
|
|
# def set_mode(self, mode):
|
|
|
|
# ## Do nothing if this mode is already active
|
|
|
|
# if self.mode == mode:
|
|
|
|
# print "set_mode: already in mode '%s': returning" % mode
|
|
|
|
# return mode
|
|
|
|
|
|
|
|
# ## Remove current Selector if set.
|
|
|
|
# if self._selector != None:
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.onmove)
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.press)
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.release)
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.update_background)
|
|
|
|
# print "set_mode: Removing selector in: %s" %self.plot.get_title()
|
|
|
|
# self._selector = None
|
|
|
|
|
|
|
|
# ## Remove current mouse button bindings
|
|
|
|
# if self._idPress != None:
|
|
|
|
# self._idPress = self.canvas.mpl_disconnect(self._idPress)
|
|
|
|
# self.mode = ''
|
|
|
|
|
|
|
|
# if self._idRelease != None:
|
|
|
|
# self._idRelease = self.canvas.mpl_disconnect(self._idRelease)
|
|
|
|
# self.mode = ''
|
|
|
|
|
|
|
|
# ## Set state, and do state initialization
|
|
|
|
# self.mode = mode
|
|
|
|
|
|
|
|
|
|
|
|
# def set_mode(self, active):
|
|
|
|
# print "Set mode called in toolbar from: %s" %self.plot.get_title()
|
|
|
|
# # if state is unkown or not set, set to default
|
|
|
|
# if active == None or active not in self._modes.keys():
|
|
|
|
# active = 'DEFAULT'
|
|
|
|
|
|
|
|
# # remove current Selector:
|
|
|
|
# if self._selector != None:
|
|
|
|
# # problem is ... i have mutliple selectors still connected
|
|
|
|
# # trying to remove old selectors connections
|
|
|
|
# #
|
|
|
|
# # blah
|
|
|
|
# # Her Einar ...
|
|
|
|
# #
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.onmove)
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.press)
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.release)
|
|
|
|
# self.canvas.mpl_disconnect(self._selector.update_background)
|
|
|
|
# print "Removing selector in: %s" %self.plot.get_title()
|
|
|
|
# self._selector = None
|
|
|
|
|
|
|
|
# # remove current button bindings
|
|
|
|
# if self._idPress != None:
|
|
|
|
# self._idPress = self.canvas.mpl_disconnect(self._idPress)
|
|
|
|
# self.mode = ''
|
|
|
|
|
|
|
|
# if self._idRelease != None:
|
|
|
|
# self._idRelease = self.canvas.mpl_disconnect(self._idRelease)
|
|
|
|
# self.mode = ''
|
|
|
|
|
|
|
|
# self._modes[active]
|
|
|
|
|
|
|
|
# for state, button in self._modes.items():
|
|
|
|
# if state != active:
|
|
|
|
# continue
|
|
|
|
|
|
|
|
# if state == 'SELECT':
|
|
|
|
# for ax in self.canvas.figure.get_axes():
|
|
|
|
# props = dict(facecolor='blue', edgecolor = 'black',
|
|
|
|
# alpha=0.3, fill=True)
|
|
|
|
# print "creating a selector"
|
|
|
|
# self._selector = RectangleSelector(ax, self.on_select,
|
|
|
|
# drawtype='box', useblit=True,
|
|
|
|
# rectprops=props)
|
|
|
|
# self.mode = 'Select rectangle mode'
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# elif state == 'PAN':
|
|
|
|
# self._idPress = self.canvas.mpl_connect(
|
|
|
|
# 'button_press_event', self.press_pan)
|
|
|
|
# self._idRelease = self.canvas.mpl_connect(
|
|
|
|
# 'button_release_event', self.release_pan)
|
|
|
|
# self.mode = 'pan/zoom mode'
|
|
|
|
|
|
|
|
# elif state == 'ZOOM':
|
|
|
|
# self._idPress = self.canvas.mpl_connect('button_press_event', self.press_zoom)
|
|
|
|
# self._idRelease = self.canvas.mpl_connect('button_release_event', self.release_zoom)
|
|
|
|
# self.mode = 'Zoom to rect mode'
|
|
|
|
|
|
|
|
# elif state == 'DEFAULT':
|
|
|
|
# pass
|
|
|
|
# else:
|
|
|
|
# pass
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# if not button.get_active():
|
|
|
|
# button.set_active(True)
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# for a in self.canvas.figure.get_axes():
|
|
|
|
# a.set_navigate_mode(self._active)
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# self.set_message(self.mode)
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# self._active = active
|
|
|
|
# # update global active_mode (for all toolbar)
|
|
|
|
# globals()['active_mode'] = active
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def get_mode(self):
|
|
|
|
# if self._active == None:
|
|
|
|
# return 'DEFAULT'
|
|
|
|
# return self._active
|
|
|
|
|
|
|
|
# def default(self, button):
|
|
|
|
# """Activates default mode"""
|
|
|
|
# if not button.get_active():
|
|
|
|
# return
|
|
|
|
# self.set_mode('DEFAULT')
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def select(self, button):
|
|
|
|
# """Activate select mode"""
|
|
|
|
# if not button.get_active():
|
|
|
|
# return
|
|
|
|
# self.set_mode('SELECT')
|
|
|
|
|
|
|
|
# def on_select(self, eclick, erelease, selector):
|
|
|
|
# 'eclick and erelease are matplotlib events at press and release'
|
|
|
|
# if self._select_callback:
|
|
|
|
# print "Onselect called:"
|
|
|
|
# print " %s" % selector
|
|
|
|
# self._select_callback(eclick.xdata, eclick.ydata, erelease.xdata, erelease.ydata)
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def pan(self, button):
|
|
|
|
# """Activate the pan/zoom tool. pan with left button, zoom with right"""
|
|
|
|
# if not button.get_active():
|
|
|
|
# return
|
|
|
|
# self.set_mode('PAN')
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def zoom(self, button):
|
|
|
|
# """Activate zoom to rect mode"""
|
|
|
|
# if not button.get_active():
|
|
|
|
# return
|
|
|
|
# self.set_mode('ZOOM')
|
|
|
|
|
|
|
|
# def mouse_move(self, event):
|
|
|
|
# """Extend NavigationToolbar2.mouse_move to provide selection support."""
|
|
|
|
# # Only update the rubberband for selection mode when mouse is
|
|
|
|
# # within the plotting area.
|
|
|
|
|
|
|
|
# #if event.inaxes and self._active=='SELECT':
|
|
|
|
# # if self._lastCursor != cursors.SELECT_REGION:
|
|
|
|
# # self.set_cursor(cursors.SELECT_REGION)
|
|
|
|
# # self._lastCursor = cursors.SELECT_REGION
|
|
|
|
# # if self._xypress is not None:
|
|
|
|
# # x, y = event.x, event.y
|
|
|
|
# # lastx, lasty, a, ind, lim, trans= self._xypress
|
|
|
|
# # self.draw_rubberband(event, x, y, lastx, lasty)
|
|
|
|
|
|
|
|
# NavigationToolbar2.mouse_move(self, event)
|
|
|
|
|
|
|
|
# def set_select_callback(self, listener):
|
|
|
|
# """Allow plots to register a callback for selection events.
|
|
|
|
|
|
|
|
# The callback will be called as listener(x1, y1, x2, y2). All
|
|
|
|
# coordinates are in the plot coordinate system, not pixels or
|
|
|
|
# widget coordinates.
|
|
|
|
# """
|
|
|
|
# self._select_callback = listener
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def set_cursor(self, cursor):
|
|
|
|
# self.canvas.window.set_cursor(cursord[cursor])
|
2006-10-09 20:04:39 +02:00
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def dynamic_update(self):
|
|
|
|
# # legacy method; new method is canvas.draw_idle
|
|
|
|
# self.canvas.draw_idle()
|
2006-10-09 20:04:39 +02:00
|
|
|
|
|
|
|
|
2006-10-10 23:15:13 +02:00
|
|
|
# def save_figure(self, button):
|
|
|
|
# fname = self.fileselect.get_filename_from_user()
|
|
|
|
# if fname:
|
|
|
|
# self.canvas.print_figure(fname)
|
|
|
|
|
|
|
|
# def configure_subplots(self, button):
|
|
|
|
# toolfig = Figure(figsize=(6,3))
|
|
|
|
# canvas = self._get_canvas(toolfig)
|
|
|
|
# toolfig.subplots_adjust(top=0.9)
|
|
|
|
# tool = SubplotTool(self.canvas.figure, toolfig)
|
|
|
|
|
|
|
|
# w = int (toolfig.bbox.width())
|
|
|
|
# h = int (toolfig.bbox.height())
|
|
|
|
|
|
|
|
|
|
|
|
# window = gtk.Window()
|
|
|
|
# window.set_title("Subplot Configuration Tool")
|
|
|
|
# window.set_default_size(w, h)
|
|
|
|
# vbox = gtk.VBox()
|
|
|
|
# window.add(vbox)
|
|
|
|
# vbox.show()
|
|
|
|
|
|
|
|
# canvas.show()
|
|
|
|
# vbox.pack_start(canvas, True, True)
|
|
|
|
# window.show()
|
|
|
|
|
|
|
|
# def _get_canvas(self, fig):
|
|
|
|
# return FigureCanvas(fig)
|
2006-10-09 20:04:39 +02:00
|
|
|
|
|
|
|
|
2006-06-01 15:51:16 +02:00
|
|
|
# Create a view-changed signal that should be emitted every time
|
|
|
|
# the active view changes.
|
|
|
|
gobject.signal_new('view-changed', MainView, gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE,
|
|
|
|
(gobject.TYPE_PYOBJECT,))
|
|
|
|
|
|
|
|
# Create focus-changed signal
|
|
|
|
gobject.signal_new('focus-changed', ViewFrame, gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE,
|
|
|
|
(gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN,))
|
|
|
|
|