Toolbar update
This commit is contained in:
parent
9bfe4a30df
commit
e6bf49c34b
500
system/plots.py
500
system/plots.py
|
@ -1,11 +1,15 @@
|
||||||
import os,sys
|
import os,sys
|
||||||
|
from itertools import izip
|
||||||
import pygtk
|
import pygtk
|
||||||
import gobject
|
import gobject
|
||||||
import gtk
|
import gtk
|
||||||
|
import fluents
|
||||||
|
from system import logger
|
||||||
import matplotlib
|
import matplotlib
|
||||||
import scipy
|
|
||||||
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
|
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
|
||||||
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTK as NavigationToolbar2
|
from matplotlib.backend_bases import NavigationToolbar2,cursors
|
||||||
|
from matplotlib.backends.backend_gtk import FileChooserDialog,cursord
|
||||||
|
from matplotlib.widgets import SubplotTool,RectangleSelector
|
||||||
from matplotlib.axes import Subplot
|
from matplotlib.axes import Subplot
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
from matplotlib import cm,cbook
|
from matplotlib import cm,cbook
|
||||||
|
@ -13,9 +17,10 @@ from pylab import Polygon
|
||||||
from matplotlib.collections import LineCollection
|
from matplotlib.collections import LineCollection
|
||||||
from matplotlib.mlab import prctile
|
from matplotlib.mlab import prctile
|
||||||
import networkx
|
import networkx
|
||||||
from system import logger
|
import scipy
|
||||||
from itertools import izip
|
|
||||||
|
|
||||||
|
# global active mode. Used by toolbars to communicate correct mode
|
||||||
|
active_mode = 'DEFAULT'
|
||||||
|
|
||||||
class ObjectTable:
|
class ObjectTable:
|
||||||
"""A 2D table of elements."""
|
"""A 2D table of elements."""
|
||||||
|
@ -151,7 +156,7 @@ class ViewFrame (gtk.Frame):
|
||||||
selection, info, timestamp):
|
selection, info, timestamp):
|
||||||
treestore, path = selection.tree_get_row_drag_data()
|
treestore, path = selection.tree_get_row_drag_data()
|
||||||
iter = treestore.get_iter(path)
|
iter = treestore.get_iter(path)
|
||||||
obj = treestore.get_value(iter,2)
|
obj = treestore.get_value(iter, 2)
|
||||||
|
|
||||||
if isinstance(obj, Plot):
|
if isinstance(obj, Plot):
|
||||||
self.set_view(obj)
|
self.set_view(obj)
|
||||||
|
@ -243,16 +248,15 @@ class MainView (gtk.Notebook):
|
||||||
class Plot (gtk.Frame):
|
class Plot (gtk.Frame):
|
||||||
def __init__(self, title):
|
def __init__(self, title):
|
||||||
gtk.Frame.__init__(self)
|
gtk.Frame.__init__(self)
|
||||||
self.sel_obj = None
|
|
||||||
self.title = title
|
self.title = title
|
||||||
|
self.sel_obj = None
|
||||||
self.selection_listener = None
|
self.selection_listener = None
|
||||||
|
self.fig = Figure()
|
||||||
|
self.canvas = FigureCanvas(self.fig)
|
||||||
self.set_shadow_type(gtk.SHADOW_NONE)
|
self.set_shadow_type(gtk.SHADOW_NONE)
|
||||||
self._background = None
|
self._background = None
|
||||||
self.canvas = None
|
|
||||||
self.fig = Figure(figsize=(5,4), dpi=72)
|
|
||||||
self.canvas = FigureCanvas(self.fig)
|
|
||||||
self.fig.set_facecolor('white')
|
|
||||||
self._sel_sensitive = True
|
self._sel_sensitive = True
|
||||||
|
self.canvas.add_events(gtk.gdk.ENTER_NOTIFY_MASK)
|
||||||
|
|
||||||
def set_selection_sensitive(self,event):
|
def set_selection_sensitive(self,event):
|
||||||
if event:
|
if event:
|
||||||
|
@ -263,6 +267,7 @@ class Plot (gtk.Frame):
|
||||||
logger.log('debug','Selections active')
|
logger.log('debug','Selections active')
|
||||||
self._sel_sensitive = True
|
self._sel_sensitive = True
|
||||||
|
|
||||||
|
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
@ -291,124 +296,10 @@ class EmptyView (Plot):
|
||||||
ebox = gtk.EventBox()
|
ebox = gtk.EventBox()
|
||||||
ebox.add(label)
|
ebox.add(label)
|
||||||
self.add(ebox)
|
self.add(ebox)
|
||||||
|
|
||||||
label.show()
|
label.show()
|
||||||
ebox.show()
|
ebox.show()
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
class NavToolbar(NavigationToolbar2):
|
|
||||||
toolitems = (('Select', 'Select within rectangle', 'zoom_to_rect.png',
|
|
||||||
'select'),) + NavigationToolbar2.toolitems
|
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
NavigationToolbar2.__init__(self, *args)
|
|
||||||
self._select_callback = None
|
|
||||||
self.message.hide()
|
|
||||||
|
|
||||||
def select(self, *args):
|
|
||||||
"""Selection mode selected handler."""
|
|
||||||
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._idPress = self.canvas.mpl_connect('button_press_event', self.press_select)
|
|
||||||
self._idRelease = self.canvas.mpl_connect('button_release_event', self.release_select)
|
|
||||||
self.mode = 'Select rectangle mode'
|
|
||||||
self.set_message(self.mode)
|
|
||||||
|
|
||||||
def set_message(self, s):
|
|
||||||
"""Set status in toolbar to string s.
|
|
||||||
|
|
||||||
Overrided to make sure message can be updated even when
|
|
||||||
drawing rubberband.
|
|
||||||
"""
|
|
||||||
self.message.set_label(s)
|
|
||||||
|
|
||||||
def press_select(self, event):
|
|
||||||
"""Mouse button pressed handler for selection mode."""
|
|
||||||
x, y = event.x, event.y
|
|
||||||
|
|
||||||
for i, a in enumerate(self.canvas.figure.get_axes()):
|
|
||||||
if event.inaxes==a and event.inaxes.get_navigate():
|
|
||||||
xmin, xmax = a.get_xlim()
|
|
||||||
ymin, ymax = a.get_ylim()
|
|
||||||
lim = xmin, xmax, ymin, ymax
|
|
||||||
self._xypress = x, y, a, i, lim, a.transData.deepcopy()
|
|
||||||
break
|
|
||||||
|
|
||||||
self.press(event)
|
|
||||||
|
|
||||||
def release_select(self, event):
|
|
||||||
"""Mouse button released handler for selection mode."""
|
|
||||||
# only release if button was pressed inside first?
|
|
||||||
if self._xypress:
|
|
||||||
x, y = event.x, event.y
|
|
||||||
lastx, lasty, a, ind, lim, trans = self._xypress
|
|
||||||
lastx, lasty = a.transData.inverse_xy_tup( (lastx, lasty) )
|
|
||||||
x, y = a.transData.inverse_xy_tup( (x, y) )
|
|
||||||
|
|
||||||
if self._select_callback:
|
|
||||||
self._select_callback(lastx, lasty, x, y)
|
|
||||||
|
|
||||||
self._xypress = None
|
|
||||||
self.push_current()
|
|
||||||
self.release(event)
|
|
||||||
|
|
||||||
def mouse_move(self, event):
|
|
||||||
"""Extend NavigationToolbar2.mouse_move to provide selection support."""
|
|
||||||
from matplotlib.backend_bases import cursors
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
class PlotToolbar(NavToolbar):
|
|
||||||
"""Extensions to existing toolbar
|
|
||||||
"""
|
|
||||||
def __init__(self, *args):
|
|
||||||
NavToolbar.__init__(self, *args)
|
|
||||||
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.message.hide()
|
|
||||||
|
|
||||||
|
|
||||||
class LineViewPlot(Plot):
|
class LineViewPlot(Plot):
|
||||||
"""Line view of current selection, no interaction
|
"""Line view of current selection, no interaction
|
||||||
Only works on 2d-arrays
|
Only works on 2d-arrays
|
||||||
|
@ -417,7 +308,7 @@ class LineViewPlot(Plot):
|
||||||
-- minor_axis : needs definition only for higher order arrays
|
-- minor_axis : needs definition only for higher order arrays
|
||||||
ps: slow (cant get linecollection and blit to work)
|
ps: slow (cant get linecollection and blit to work)
|
||||||
"""
|
"""
|
||||||
def __init__(self, dataset,major_axis=1,minor_axis=None, name="Line view"):
|
def __init__(self, dataset, major_axis=1, minor_axis=None, name="Line view"):
|
||||||
self.use_blit = False
|
self.use_blit = False
|
||||||
self._last_index = []
|
self._last_index = []
|
||||||
self._data = dataset.asarray()
|
self._data = dataset.asarray()
|
||||||
|
@ -433,7 +324,7 @@ class LineViewPlot(Plot):
|
||||||
x_axis = scipy.arange(self._data.shape[minor_axis])
|
x_axis = scipy.arange(self._data.shape[minor_axis])
|
||||||
self.line_segs=[]
|
self.line_segs=[]
|
||||||
for xi in range(self._data.shape[major_axis]):
|
for xi in range(self._data.shape[major_axis]):
|
||||||
yi = self._data.take([xi],major_axis)
|
yi = self._data.take([xi], major_axis)
|
||||||
self.line_segs.append([(xx,yy) for xx,yy in izip(x_axis,yi)])
|
self.line_segs.append([(xx,yy) for xx,yy in izip(x_axis,yi)])
|
||||||
|
|
||||||
#background
|
#background
|
||||||
|
@ -443,41 +334,40 @@ class LineViewPlot(Plot):
|
||||||
verts_2 = [] # 75,25
|
verts_2 = [] # 75,25
|
||||||
med = []
|
med = []
|
||||||
for i in xax:
|
for i in xax:
|
||||||
pp = prctile(self._data[i,:],[0.,5.,25,50.,75.,95.,100])
|
pp = prctile(self._data[i,:], [0.,5.,25,50.,75.,95.,100])
|
||||||
verts_0.append((i,pp[0]))
|
verts_0.append((i,pp[0]))
|
||||||
verts_1.append((i,pp[1]))
|
verts_1.append((i,pp[1]))
|
||||||
verts_2.append((i,pp[2]))
|
verts_2.append((i,pp[2]))
|
||||||
for i in xax[::-1]:
|
for i in xax[::-1]:
|
||||||
pp = prctile(self._data[i,:],[0.,5.,25,50.,75.,95.,100])
|
pp = prctile(self._data[i,:], [0.,5.,25,50.,75.,95.,100])
|
||||||
verts_0.append((i,pp[-1]))
|
verts_0.append((i, pp[-1]))
|
||||||
verts_1.append((i,pp[-2]))
|
verts_1.append((i, pp[-2]))
|
||||||
verts_2.append((i,pp[-3]))
|
verts_2.append((i, pp[-3]))
|
||||||
med.append(pp[3])
|
med.append(pp[3])
|
||||||
|
|
||||||
bck0 = Polygon(verts_0,alpha=.15,lw=0)
|
bck0 = Polygon(verts_0, alpha=.15, lw=0)
|
||||||
bck1 = Polygon(verts_1,alpha=.15,lw=0)
|
bck1 = Polygon(verts_1, alpha=.15, lw=0)
|
||||||
bck2 = Polygon(verts_2,alpha=.15,lw=0)
|
bck2 = Polygon(verts_2, alpha=.15, lw=0)
|
||||||
|
|
||||||
self.ax.add_patch(bck0)
|
self.ax.add_patch(bck0)
|
||||||
self.ax.add_patch(bck1)
|
self.ax.add_patch(bck1)
|
||||||
self.ax.add_patch(bck2)
|
self.ax.add_patch(bck2)
|
||||||
self.ax.plot(xax,med,'b')
|
self.ax.plot(xax,med, 'b')
|
||||||
self.ax.autoscale_view()
|
self.ax.autoscale_view()
|
||||||
|
|
||||||
self.add(self.canvas)
|
self.add(self.canvas)
|
||||||
self.canvas.show()
|
self.canvas.show()
|
||||||
|
|
||||||
#FIXME: Lineview plot cannot do selections -> disable in toolbar
|
#FIXME: Lineview plot cannot do selections -> disable in toolbar
|
||||||
self._toolbar = PlotToolbar(self.canvas, None)
|
self._toolbar = PlotToolbar(self.canvas,self)
|
||||||
self._toolbar.set_property('show-arrow', False)
|
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
|
||||||
self._toolbar.chk.connect ('toggled' ,self.set_selection_sensitive)
|
self.canvas.mpl_connect('resize_event', self.clear_background)
|
||||||
self.canvas.mpl_connect('resize_event',self.clear_background)
|
|
||||||
|
|
||||||
|
|
||||||
def get_toolbar(self):
|
def get_toolbar(self):
|
||||||
return self._toolbar
|
return self._toolbar
|
||||||
|
|
||||||
def clear_background(self,event):
|
def clear_background(self, event):
|
||||||
self._background = None
|
self._background = None
|
||||||
|
|
||||||
def set_current_selection(self, selection):
|
def set_current_selection(self, selection):
|
||||||
|
@ -493,7 +383,7 @@ class LineViewPlot(Plot):
|
||||||
if len(self.ax.collections)>0:
|
if len(self.ax.collections)>0:
|
||||||
self.ax.collections = []
|
self.ax.collections = []
|
||||||
segs = [self.line_segs[i] for i in index]
|
segs = [self.line_segs[i] for i in index]
|
||||||
line_coll = LineCollection(segs,colors=(1,0,0,1))
|
line_coll = LineCollection(segs, colors=(1,0,0,1))
|
||||||
line_coll.set_clip_box(self.ax.bbox)
|
line_coll.set_clip_box(self.ax.bbox)
|
||||||
self.ax.update_datalim(line_coll.get_verts(self.ax.transData))
|
self.ax.update_datalim(line_coll.get_verts(self.ax.transData))
|
||||||
self._toolbar.forward()
|
self._toolbar.forward()
|
||||||
|
@ -521,24 +411,24 @@ has no color and size options."""
|
||||||
self.use_blit = False
|
self.use_blit = False
|
||||||
self._background = None
|
self._background = None
|
||||||
self.ax = self.fig.add_subplot(111)
|
self.ax = self.fig.add_subplot(111)
|
||||||
self.ax.axhline(0,color='k',lw=1.,zorder=1)
|
self.ax.axhline(0, color='k', lw=1., zorder=1)
|
||||||
self.ax.axvline(0,color='k',lw=1.,zorder=1)
|
self.ax.axvline(0, color='k', lw=1., zorder=1)
|
||||||
self.current_dim = id_dim
|
self.current_dim = id_dim
|
||||||
self.dataset_1 = dataset_1
|
self.dataset_1 = dataset_1
|
||||||
self.ms = s
|
self.ms = s
|
||||||
self._selection_line = None
|
self._selection_line = None
|
||||||
x_index = dataset_1[sel_dim][id_1]
|
x_index = dataset_1[sel_dim][id_1]
|
||||||
y_index = dataset_2[sel_dim][id_2]
|
y_index = dataset_2[sel_dim][id_2]
|
||||||
self.xaxis_data = dataset_1._array[:,x_index]
|
self.xaxis_data = dataset_1._array[:, x_index]
|
||||||
self.yaxis_data = dataset_2._array[:,y_index]
|
self.yaxis_data = dataset_2._array[:, y_index]
|
||||||
self.ax.plot(self.xaxis_data,self.yaxis_data,'o',markeredgewidth=0,markersize=s)
|
self.ax.plot(self.xaxis_data, self.yaxis_data, 'o', markeredgewidth=0, markersize=s)
|
||||||
self.ax.set_title(self.get_title())
|
self.ax.set_title(self.get_title())
|
||||||
self.add(self.canvas)
|
self.add(self.canvas)
|
||||||
self.canvas.show()
|
self.canvas.show()
|
||||||
|
|
||||||
# add toolbar
|
# add toolbar
|
||||||
self._toolbar = PlotToolbar(self.canvas, None)
|
self._toolbar = PlotToolbar(self.canvas, self)
|
||||||
self._toolbar.chk.connect ('toggled' ,self.set_selection_sensitive)
|
self._toolbar.chk.connect ('toggled', self.set_selection_sensitive)
|
||||||
self._toolbar.set_property('show-arrow', False)
|
self._toolbar.set_property('show-arrow', False)
|
||||||
self._toolbar.set_select_callback(self.rectangle_select_callback)
|
self._toolbar.set_select_callback(self.rectangle_select_callback)
|
||||||
|
|
||||||
|
@ -575,7 +465,7 @@ has no color and size options."""
|
||||||
if self._selection_line:
|
if self._selection_line:
|
||||||
self.ax.lines.remove(self._selection_line)
|
self.ax.lines.remove(self._selection_line)
|
||||||
|
|
||||||
self._selection_line, = self.ax.plot(xdata_new,ydata_new,marker='o',markersize=self.ms,linestyle=None,markerfacecolor='r')
|
self._selection_line, = self.ax.plot(xdata_new, ydata_new,marker='o', markersize=self.ms, linestyle=None, markerfacecolor='r')
|
||||||
|
|
||||||
self._toolbar.forward() #update data lims before draw
|
self._toolbar.forward() #update data lims before draw
|
||||||
if self.use_blit:
|
if self.use_blit:
|
||||||
|
@ -598,14 +488,14 @@ class ScatterPlot(Plot):
|
||||||
y_index = dataset_2[sel_dim_2][id_2]
|
y_index = dataset_2[sel_dim_2][id_2]
|
||||||
else:
|
else:
|
||||||
y_index = dataset_2[sel_dim][id_2]
|
y_index = dataset_2[sel_dim][id_2]
|
||||||
self.xaxis_data = dataset_1._array[:,x_index]
|
self.xaxis_data = dataset_1._array[:, x_index]
|
||||||
self.yaxis_data = dataset_2._array[:,y_index]
|
self.yaxis_data = dataset_2._array[:, y_index]
|
||||||
lw = scipy.zeros(self.xaxis_data.shape)
|
lw = scipy.zeros(self.xaxis_data.shape)
|
||||||
sc = self.ax.scatter(self.xaxis_data,self.yaxis_data,s=s,c=c,linewidth=lw,edgecolor='k',alpha=.6,cmap = cm.jet)
|
sc = self.ax.scatter(self.xaxis_data, self.yaxis_data, s=s, c=c, linewidth=lw, edgecolor='k', alpha=.6, cmap = cm.jet)
|
||||||
if len(c)>1:
|
if len(c)>1:
|
||||||
self.fig.colorbar(sc,ticks=[],fraction=.05)
|
self.fig.colorbar(sc,ticks=[], fraction=.05)
|
||||||
self.ax.axhline(0,color='k',lw=1.,zorder=1)
|
self.ax.axhline(0, color='k', lw=1., zorder=1)
|
||||||
self.ax.axvline(0,color='k',lw=1.,zorder=1)
|
self.ax.axvline(0, color='k', lw=1., zorder=1)
|
||||||
self.ax.set_title(self.get_title())
|
self.ax.set_title(self.get_title())
|
||||||
# collection
|
# collection
|
||||||
self.coll = self.ax.collections[0]
|
self.coll = self.ax.collections[0]
|
||||||
|
@ -615,8 +505,8 @@ class ScatterPlot(Plot):
|
||||||
self.canvas.show()
|
self.canvas.show()
|
||||||
|
|
||||||
# create toolbar
|
# create toolbar
|
||||||
self._toolbar = PlotToolbar(self.canvas, None)
|
self._toolbar = PlotToolbar(self.canvas, self)
|
||||||
self._toolbar.chk.connect ('toggled' ,self.set_selection_sensitive)
|
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
|
||||||
self._toolbar.set_property('show-arrow', False)
|
self._toolbar.set_property('show-arrow', False)
|
||||||
self._toolbar.set_select_callback(self.rectangle_select_callback)
|
self._toolbar.set_select_callback(self.rectangle_select_callback)
|
||||||
|
|
||||||
|
@ -715,8 +605,8 @@ class NetworkPlot(Plot):
|
||||||
networkx.draw_networkx(self.graph, ax=self.ax, **kw)
|
networkx.draw_networkx(self.graph, ax=self.ax, **kw)
|
||||||
|
|
||||||
# Setup toolbar
|
# Setup toolbar
|
||||||
self._toolbar = PlotToolbar(self.canvas, None)
|
self._toolbar = PlotToolbar(self.canvas, self)
|
||||||
self._toolbar.chk.connect ('toggled' ,self.set_selection_sensitive)
|
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
|
||||||
self._toolbar.set_property('show-arrow', False)
|
self._toolbar.set_property('show-arrow', False)
|
||||||
self._toolbar.set_select_callback(self.rectangle_select_callback)
|
self._toolbar.set_select_callback(self.rectangle_select_callback)
|
||||||
|
|
||||||
|
@ -726,8 +616,8 @@ class NetworkPlot(Plot):
|
||||||
def rectangle_select_callback(self, x1, y1, x2, y2):
|
def rectangle_select_callback(self, x1, y1, x2, y2):
|
||||||
'event1 and event2 are the press and release events'
|
'event1 and event2 are the press and release events'
|
||||||
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')
|
||||||
node_ids = []
|
node_ids = []
|
||||||
c = 0
|
c = 0
|
||||||
for name,(x,y) in pos.items():
|
for name,(x,y) in pos.items():
|
||||||
|
@ -778,6 +668,294 @@ class NetworkPlot(Plot):
|
||||||
self.canvas.draw()
|
self.canvas.draw()
|
||||||
|
|
||||||
|
|
||||||
|
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'),
|
||||||
|
)
|
||||||
|
|
||||||
|
radiobuttons = (
|
||||||
|
('DEFAULT', 'Default mode', 'cursor.png', 'default'),
|
||||||
|
('PAN', 'Pan axes with left mouse, zoom with right', 'move.png', 'pan'),
|
||||||
|
('ZOOM', 'Zoom to rectangle','zoom_to_rect.png', 'zoom'),
|
||||||
|
('SELECT', 'Select within rectangle', 'select.png', 'select'),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, canvas, plot):
|
||||||
|
self.win = None
|
||||||
|
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._states = {}
|
||||||
|
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._states[text] = rbutton
|
||||||
|
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)
|
||||||
|
|
||||||
|
def set_mode(self, active):
|
||||||
|
# if state is unkown or not set, set to default
|
||||||
|
if active == None or active not in self._states.keys():
|
||||||
|
active = 'DEFAULT'
|
||||||
|
|
||||||
|
# remove current Selector:
|
||||||
|
if self._selector:
|
||||||
|
print "Removing selector"
|
||||||
|
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 = ''
|
||||||
|
|
||||||
|
for state, button in self._states.items():
|
||||||
|
if state != active:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if state == 'SELECT':
|
||||||
|
ax, = self.canvas.figure.get_axes()
|
||||||
|
props = dict(facecolor='blue', edgecolor = 'black',
|
||||||
|
alpha=0.3, fill=True)
|
||||||
|
self._selector = RectangleSelector(ax, self.onselect,
|
||||||
|
drawtype='box', useblit=True,
|
||||||
|
rectprops=props)
|
||||||
|
self.mode = 'Select rectangle mode'
|
||||||
|
print self.mode
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
if not button.get_active():
|
||||||
|
button.set_active(True)
|
||||||
|
|
||||||
|
for a in self.canvas.figure.get_axes():
|
||||||
|
a.set_navigate_mode(self._active)
|
||||||
|
|
||||||
|
self.set_message(self.mode)
|
||||||
|
|
||||||
|
self._active = active
|
||||||
|
# update global active_mode (for all toolbar)
|
||||||
|
globals()['active_mode'] = active
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
def select(self, button):
|
||||||
|
"""Activate select mode"""
|
||||||
|
if not button.get_active():
|
||||||
|
return
|
||||||
|
self.set_mode('SELECT')
|
||||||
|
|
||||||
|
def onselect(self,eclick, erelease):
|
||||||
|
'eclick and erelease are matplotlib events at press and release'
|
||||||
|
if self._select_callback:
|
||||||
|
self._select_callback(eclick.xdata, eclick.ydata, erelease.xdata, erelease.ydata)
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def set_cursor(self, cursor):
|
||||||
|
self.canvas.window.set_cursor(cursord[cursor])
|
||||||
|
|
||||||
|
def dynamic_update(self):
|
||||||
|
# legacy method; new method is canvas.draw_idle
|
||||||
|
self.canvas.draw_idle()
|
||||||
|
|
||||||
|
def mpl_draw_rubberband(self,event):
|
||||||
|
"""Use RectangleSelector for rubberband drawing"""
|
||||||
|
|
||||||
|
def draw_rubberband(self, event, x0, y0, x1, y1):
|
||||||
|
'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744'
|
||||||
|
drawable = self.canvas.window
|
||||||
|
if drawable is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
gc = drawable.new_gc()
|
||||||
|
|
||||||
|
height = self.canvas.figure.bbox.height()
|
||||||
|
y1 = height - y1
|
||||||
|
y0 = height - y0
|
||||||
|
|
||||||
|
w = abs(x1 - x0)
|
||||||
|
h = abs(y1 - y0)
|
||||||
|
rect = [int(val)for val in min(x0,x1), min(y0, y1), w, h]
|
||||||
|
try: lastrect, imageBack = self._imageBack
|
||||||
|
except AttributeError:
|
||||||
|
#snap image back
|
||||||
|
if event.inaxes is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
ax = event.inaxes
|
||||||
|
l,b,w,h = [int(val) for val in ax.bbox.get_bounds()]
|
||||||
|
b = int(height)-(b+h)
|
||||||
|
axrect = l,b,w,h
|
||||||
|
self._imageBack = axrect, drawable.get_image(*axrect)
|
||||||
|
drawable.draw_rectangle(gc, False, *rect)
|
||||||
|
self._idleId = 0
|
||||||
|
else:
|
||||||
|
def idle_draw(*args):
|
||||||
|
drawable.draw_image(gc, imageBack, 0, 0, *lastrect)
|
||||||
|
drawable.draw_rectangle(gc, False, *rect)
|
||||||
|
self._idleId = 0
|
||||||
|
return False
|
||||||
|
if self._idleId == 0:
|
||||||
|
self._idleId = gobject.idle_add(idle_draw)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
# 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.
|
||||||
gobject.signal_new('view-changed', MainView, gobject.SIGNAL_RUN_LAST,
|
gobject.signal_new('view-changed', MainView, gobject.SIGNAL_RUN_LAST,
|
||||||
|
|
Reference in New Issue