Projects/laydi
Projects
/
laydi
Archived
7
0
Fork 0
This repository has been archived on 2024-07-04. You can view files and clone it, but cannot push or open issues or pull requests.
laydi/system/plots.py

996 lines
34 KiB
Python

import os,sys
from itertools import izip
import pygtk
import gobject
import gtk
import fluents
from system import logger
import matplotlib
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
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.figure import Figure
from matplotlib import cm,cbook
from pylab import Polygon
from matplotlib.collections import LineCollection
from matplotlib.mlab import prctile
import networkx
import scipy
# global active mode. Used by toolbars to communicate correct mode
active_mode = 'DEFAULT'
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):
"""
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.
"""
def __init__(self, view_frames):
gtk.Frame.__init__(self)
self.focused = False
self.view_frames = view_frames
self.empty_view = EmptyView()
self._button_event = None
view_frames.append(self)
if len(view_frames) == 1:
self.focus()
else:
self.focused = True
self.unfocus()
# 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)
# Set view
self._view = self.empty_view
self._view.connect("button-press-event", self.on_button_press_event)
self.add(self._view)
self._view.show()
self.show()
def focus(self):
"""Gets focus and ensures that no other window is in focus."""
if self.focused:
self.emit('focus-changed', self, True)
return self
for frame in self.view_frames:
frame.unfocus()
self.set_shadow_type(gtk.SHADOW_IN)
self.focused = True
self.emit('focus-changed', self, True)
return self
def unfocus(self):
"""Removes focus from the ViewFrame. Does nothing if unfocused."""
if not self.focused:
return
self.set_shadow_type(gtk.SHADOW_OUT)
self.focused = False
self.emit('focus-changed', self, False)
def set_view(self, view):
"""Set view to view or to empty view if parameter is None"""
# if None is passed, use empty view
if view == None:
view = self.empty_view
# do nothing if the view is already there
if view == self._view:
return
# detach view from current parent
view_parent = view.get_parent()
if view_parent:
view_parent.set_view(None)
# switch which widget we are listening to
if self._button_event:
self._view.disconnect(self._button_event)
self._button_event = view.connect("button-press-event",
self.on_button_press_event)
# 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()
def on_drag_data_received(self, widget, drag_context, x, y,
selection, info, timestamp):
treestore, path = selection.tree_get_row_drag_data()
iter = treestore.get_iter(path)
obj = treestore.get_value(iter, 2)
if isinstance(obj, Plot):
self.set_view(obj)
self.focus()
class MainView (gtk.Notebook):
def __init__(self):
gtk.Notebook.__init__(self)
self.set_show_tabs(False)
self.set_show_border(False)
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()
for vf in self._view_frames:
vf.connect('focus-changed', self.on_view_focus_changed)
self.append_page(self._small_views)
self.append_page(self._large_view)
self.show()
self.set_current_page(0)
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)
def get_active_small_view(self):
for vf in self._view_frames:
if vf.focused:
return vf
return None
def goto_large(self):
if self.get_current_page() == 1:
return
vf = self.get_active_small_view()
view = vf.get_view()
vf.set_view(None)
self._large_view.set_view(view)
self.set_current_page(1)
def goto_small(self):
if self.get_current_page() == 0:
return
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)
def insert_view(self, view):
if self.get_current_page() == 0:
vf = self.get_active_small_view()
else:
vf = self._large_view
vf.set_view(view)
def set_all_plots(self, plots):
for vf in self._view_frames:
if plots:
vf.set_view(plots.pop())
else:
vf.set_view(None)
def show(self):
for vf in self._view_frames:
vf.show()
self._small_views.show()
gtk.Notebook.show(self)
def on_view_focus_changed(self, widget, vf, focused):
if focused:
self.emit('view-changed', vf)
class Plot (gtk.Frame):
def __init__(self, title):
gtk.Frame.__init__(self)
self.title = title
self.selection_listener = None
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.set_shadow_type(gtk.SHADOW_NONE)
self._background = None
self._sel_sensitive = True
self.canvas.add_events(gtk.gdk.ENTER_NOTIFY_MASK)
self.current_dim = None
def set_selection_sensitive(self,event):
if event:
if event.get_active():
logger.log('debug','Selection freezed')
self._sel_sensitive = False
else:
logger.log('debug','Selections active')
self._sel_sensitive = True
def get_title(self):
return self.title
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.
"""
if not self._sel_sensitive or not self.get_property('visible') or self.current_dim!=dim_name:
print "Ignored a selection changed call in plot: %s" %self.get_title()
return
print "Setting current selection in: %s " %self.get_title()
self.set_current_selection(selection)
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
def get_toolbar(self):
return None
class EmptyView (Plot):
def __init__(self):
Plot.__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 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)
"""
def __init__(self, dataset, major_axis=1, minor_axis=None, name="Line view"):
self.use_blit = False
self._last_index = []
self._data = dataset.asarray()
self.dataset = dataset
Plot.__init__(self, name)
self.ax = self.fig.add_subplot(111)
self.ax.set_title(self.get_title())
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
#initial draw
x_axis = scipy.arange(self._data.shape[minor_axis])
self.line_segs=[]
for xi in range(self._data.shape[major_axis]):
yi = self._data.take([xi], major_axis)
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:
pp = prctile(self._data[i,:], [0.,5.,25,50.,75.,95.,100])
verts_0.append((i,pp[0]))
verts_1.append((i,pp[1]))
verts_2.append((i,pp[2]))
for i in xax[::-1]:
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]))
med.append(pp[3])
bck0 = Polygon(verts_0, alpha=.15, lw=0)
bck1 = Polygon(verts_1, alpha=.15, lw=0)
bck2 = Polygon(verts_2, alpha=.15, lw=0)
self.ax.add_patch(bck0)
self.ax.add_patch(bck1)
self.ax.add_patch(bck2)
self.ax.plot(xax,med, 'b')
self.ax.autoscale_view()
self.add(self.canvas)
self.canvas.show()
#FIXME: Lineview plot cannot do selections -> disable in toolbar
self._toolbar = PlotToolbar(self.canvas,self)
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
self.canvas.mpl_connect('resize_event', self.clear_background)
def get_toolbar(self):
return self._toolbar
def clear_background(self, event):
self._background = None
def set_current_selection(self, selection):
ids = selection[self.current_dim] # current identifiers
index = self.dataset.get_indices(self.current_dim, ids)
if self.use_blit:
if self._background is None:
self._bbox = self.ax.bbox.deepcopy()
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
self.canvas.restore_region(self._background)
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]
line_coll = LineCollection(segs, colors=(1,0,0,1))
line_coll.set_clip_box(self.ax.bbox)
self.ax.update_datalim(line_coll.get_verts(self.ax.transData))
self._toolbar.forward()
if self.use_blit:
self.ax.draw_artist(line_coll)
#print "\nLine collection clip box:"
line_coll.get_clip_box().get_bounds()
#print "\nLine collection bbox:"
#print self.ax.bbox.get_bounds()
#print "Background bbox:"
#print self._bbox.get_bounds()
#self.canvas.blit(self._bbox)
self.canvas.blit()
#self.ax.draw_artist(line_coll)
else:
self.ax.add_collection(line_coll)
self.canvas.draw()
class ScatterMarkerPlot(Plot):
"""The ScatterMarkerPlot is faster than regular scatterplot, but
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"):
Plot.__init__(self, name)
self.use_blit = False
self._background = None
self.ax = self.fig.add_subplot(111)
self.ax.axhline(0, color='k', lw=1., zorder=1)
self.ax.axvline(0, color='k', lw=1., zorder=1)
self.current_dim = id_dim
self.dataset_1 = dataset_1
self.ms = s
self._selection_line = None
x_index = dataset_1[sel_dim][id_1]
y_index = dataset_2[sel_dim][id_2]
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)
self.ax.set_title(self.get_title())
self.add(self.canvas)
self.canvas.show()
# add toolbar
self._toolbar = PlotToolbar(self.canvas, self)
self._toolbar.chk.connect ('toggled', self.set_selection_sensitive)
self._toolbar.set_property('show-arrow', False)
self._toolbar.set_select_callback(self.rectangle_select_callback)
def get_toolbar(self):
return self._toolbar
def rectangle_select_callback(self, x1, y1, x2, y2):
print "Rectangle select happened in: %s" %self.get_title()
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
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
ids = self.dataset_1.get_identifiers(self.current_dim, index)
self.selection_listener(self.current_dim, ids)
def set_current_selection(self, selection):
ids = selection[self.current_dim] # current identifiers
index = self.dataset_1.get_indices(self.current_dim, ids)
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
xdata_new = self.xaxis_data.take(index) #take data
ydata_new = self.yaxis_data.take(index)
#remove old selection
if 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._toolbar.forward() #update data lims before draw
if self.use_blit:
self.ax.draw_artist(self._selection_line)
self.canvas.blit()
else:
print "A draw happened in: %s" %self.get_title()
self.canvas.draw()
class ScatterPlot(Plot):
"""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"):
Plot.__init__(self, name)
self.use_blit = False
self.ax = self.fig.add_subplot(111)
self.current_dim = id_dim
self.dataset_1 = dataset_1
x_index = dataset_1[sel_dim][id_1]
if sel_dim_2:
y_index = dataset_2[sel_dim_2][id_2]
else:
y_index = dataset_2[sel_dim][id_2]
self.xaxis_data = dataset_1._array[:, x_index]
self.yaxis_data = dataset_2._array[:, y_index]
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)
if len(c)>1:
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)
self.ax.set_title(self.get_title())
# collection
self.coll = self.ax.collections[0]
# add canvas to widget
self.add(self.canvas)
self.canvas.show()
# create toolbar
self._toolbar = PlotToolbar(self.canvas, self)
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
self._toolbar.set_select_callback(self.rectangle_select_callback)
def get_toolbar(self):
return self._toolbar
def rectangle_select_callback(self, x1, y1, x2, y2):
print "Rectangle select happened in: %s" %self.get_title()
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
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
ids = self.dataset_1.get_identifiers(self.current_dim, index)
self.selection_listener(self.current_dim, ids)
def set_current_selection(self, selection):
ids = selection[self.current_dim] # current identifiers
if len(ids)==0:
print "nothing selected"
return
self._toolbar.forward() #update data lims before draw
index = self.dataset_1.get_indices(self.current_dim, ids)
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)
lw = scipy.zeros(self.xaxis_data.shape)
if len(index)>0:
lw.put(2.,index)
self.coll.set_linewidth(lw)
if self.use_blit:
print "A blit happened in : %s " %self.get_title()
self.canvas.blit()
self.ax.draw_artist(self.coll)
else:
print "A draw happened in : %s " %self.get_title()
self.canvas.draw()
class NetworkPlot(Plot):
def __init__(self, dataset, **kw):
# Set member variables and call superclass' constructor
self.graph = dataset.asnetworkx()
self.dataset = dataset
self.keywords = kw
self.dim_name = self.dataset.get_dim_name(0)
self.current_dim = self.dim_name
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']:
kw['pos'] = networkx.pygraphviz_layout(self.graph, kw['prog'])
Plot.__init__(self, kw['name'])
# Keep node size and color as dicts for fast lookup
self.node_size = {}
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
else:
for id in dataset[self.dim_name]:
self.node_size[id] = 40
self.node_color = {}
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
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')
self.ax = self.fig.add_subplot(111)
self.ax.set_position([0.01,0.01,.99,.99])
self.ax.set_xticks([])
self.ax.set_yticks([])
# FIXME: ax shouldn't be in kw at all
if kw.has_key('ax'):
kw.pop('ax')
# Add canvas and show
self.add(self.canvas)
self.canvas.show()
# Initial draw
networkx.draw_networkx(self.graph, ax=self.ax, **kw)
# Setup toolbar
self._toolbar = PlotToolbar(self.canvas, self)
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
self._toolbar.set_select_callback(self.rectangle_select_callback)
def get_toolbar(self):
return self._toolbar
def rectangle_select_callback(self, x1, y1, x2, y2):
pos = self.keywords['pos']
ydata = scipy.zeros((len(pos),), 'l')
xdata = scipy.zeros((len(pos),), 'l')
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
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
ids = [node_ids[i] for i in index]
self.selection_listener(self.current_dim, ids)
def set_current_selection(self, selection):
ids = selection[self.current_dim] # current identifiers
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'
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]
self.ax.clear()
networkx.draw_networkx_edges(self.graph, edge_list=self.graph.edges(), \
ax=self.ax, **self.keywords)
networkx.draw_networkx_labels(self.graph,**self.keywords)
if unselected_nodes:
networkx.draw_networkx_nodes(self.graph, nodelist=unselected_nodes, \
node_color='r', node_size=unselected_sizes, ax=self.ax, **self.keywords)
if selected_nodes:
networkx.draw_networkx_nodes(self.graph, nodelist=selected_nodes, \
node_color='k', node_size=selected_sizes, ax=self.ax, **self.keywords)
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
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._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)
self.set_mode(active_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._states.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 = ''
for state, button in self._states.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'
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 on_select(self,eclick, erelease):
'eclick and erelease are matplotlib events at press and release'
if self._select_callback:
print "Onselect called"
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 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
# 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,))