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

970 lines
33 KiB
Python
Raw Normal View History

import os,sys
2006-10-09 20:04:39 +02:00
from itertools import izip
import pygtk
2006-06-01 15:51:16 +02:00
import gobject
import gtk
2006-10-09 20:04:39 +02:00
import fluents
from system import logger
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
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
import networkx
2006-10-09 20:04:39 +02:00
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):
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.
"""
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:
2006-08-04 11:32:11 +02:00
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
2006-06-01 15:51:16 +02:00
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
2006-06-01 15:51:16 +02:00
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)
2006-10-09 20:04:39 +02:00
obj = treestore.get_value(iter, 2)
if isinstance(obj, Plot):
self.set_view(obj)
2006-08-31 15:27:58 +02:00
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()
2006-06-01 15:51:16 +02:00
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)
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-08-30 15:39:32 +02:00
class Plot (gtk.Frame):
def __init__(self, title):
gtk.Frame.__init__(self)
self.title = title
2006-10-09 20:04:39 +02:00
self.sel_obj = None
self.selection_listener = None
2006-10-09 20:04:39 +02:00
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.set_shadow_type(gtk.SHADOW_NONE)
2006-08-14 17:01:34 +02:00
self._background = None
self._sel_sensitive = True
2006-10-09 20:04:39 +02:00
self.canvas.add_events(gtk.gdk.ENTER_NOTIFY_MASK)
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
2006-08-28 14:06:05 +02:00
2006-10-09 20:04:39 +02:00
def get_title(self):
return self.title
def selection_changed(self, selection):
if not self._sel_sensitive or not self.get_property('visible'):
return
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
2006-10-09 20:04:39 +02:00
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)
"""
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 = []
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())
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
#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-30 15:39:32 +02:00
#FIXME: Lineview plot cannot do selections -> disable in toolbar
2006-10-09 20:04:39 +02:00
self._toolbar = PlotToolbar(self.canvas,self)
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
self.canvas.mpl_connect('resize_event', self.clear_background)
2006-04-27 13:03:11 +02:00
2006-04-27 13:03:11 +02:00
def get_toolbar(self):
return self._toolbar
2006-08-14 17:01:34 +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
def set_current_selection(self, selection):
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))
self._toolbar.forward()
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
#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)
2006-08-28 14:06:05 +02:00
self.canvas.blit()
2006-10-06 12:20:53 +02:00
#self.ax.draw_artist(line_coll)
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-04-27 13:03:11 +02:00
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)
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)
self.current_dim = id_dim
self.dataset_1 = dataset_1
self.ms = s
2006-08-28 14:06:05 +02:00
self._selection_line = None
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())
self.add(self.canvas)
self.canvas.show()
2006-08-30 15:39:32 +02:00
# add toolbar
2006-10-09 20:04:39 +02:00
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):
ydata = self.yaxis_data
xdata = self.xaxis_data
2006-04-25 12:08:12 +02:00
# 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)
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
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
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:
self.canvas.draw()
2006-08-30 15:39:32 +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"):
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)
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]
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())
# collection
self.coll = self.ax.collections[0]
# add canvas to widget
self.add(self.canvas)
self.canvas.show()
# create toolbar
2006-10-09 20:04:39 +02:00
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):
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
2006-09-18 19:23:34 +02:00
if len(ids)==0:
return
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)
lw = scipy.zeros(self.xaxis_data.shape)
2006-09-18 19:23:34 +02:00
if len(index)>0:
lw.put(2.,index)
self.coll.set_linewidth(lw)
self._toolbar.forward() #update data lims before draw
2006-10-06 12:20:53 +02:00
if self.use_blit:
self.canvas.blit()
self.ax.draw_artist(self.coll)
else:
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)
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)
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([])
# 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
2006-10-09 20:04:39 +02:00
self._toolbar = PlotToolbar(self.canvas, self)
self._toolbar.chk.connect ('toggled' , self.set_selection_sensitive)
2006-08-31 17:59:17 +02:00
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):
'event1 and event2 are the press and release events'
pos = self.keywords['pos']
2006-10-09 20:04:39 +02:00
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
2006-09-18 19:23:34 +02:00
index = scipy.nonzero((xdata>x1) & (xdata<x2) & (ydata>y1) & (ydata<y2))[0]
2006-10-06 12:20:53 +02:00
ids = [node_ids[i] for i in index]
self.selection_listener(self.dataset.get_dim_name(0), ids)
def set_current_selection(self, selection):
ids = selection[self.dataset.get_dim_name(0)] # 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)
2006-08-28 14:06:05 +02:00
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()
2006-10-09 20:04:39 +02:00
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)
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,))