Add toolbar support to plots, with home made selection support <phew>.
This commit is contained in:
parent
490038d9bf
commit
21edeecdc3
|
@ -24,6 +24,8 @@ class FluentApp:
|
|||
# Application variables
|
||||
self.project = None
|
||||
self.current_data = None
|
||||
self._last_view = None
|
||||
self._plot_toolbar = None
|
||||
|
||||
gtk.glade.set_custom_handler(self.custom_object_factory)
|
||||
self.widget_tree = gtk.glade.XML(GLADEFILENAME, 'appwindow')
|
||||
|
@ -52,10 +54,29 @@ class FluentApp:
|
|||
return self.log_view
|
||||
|
||||
def create_main_view(self, str1, str2, int1, int2):
|
||||
self.main_view = plots.MainView()
|
||||
self.main_view = plots.MainView(self._update_toolbar)
|
||||
self.main_view.show()
|
||||
return self.main_view
|
||||
|
||||
def _update_toolbar(self, view):
|
||||
logger.log("debug", "view changed to %s" % view)
|
||||
# don't do anything on no change
|
||||
if self._last_view == view:
|
||||
return
|
||||
self._last_view = view
|
||||
|
||||
window = self.widget_tree.get_widget('plot_toolbar_dock')
|
||||
if self._plot_toolbar:
|
||||
print "removing", self._plot_toolbar
|
||||
window.remove(self._plot_toolbar)
|
||||
|
||||
self._plot_toolbar = view.get_toolbar()
|
||||
if self._plot_toolbar:
|
||||
print "adding", self._plot_toolbar
|
||||
window.add(self._plot_toolbar)
|
||||
|
||||
print "window contents:", window.get_children()
|
||||
|
||||
def create_small_view(self, str1, str2, int1, int2):
|
||||
self.small_view = plots.SmallView()
|
||||
self.small_view.show()
|
||||
|
|
197
system/plots.py
197
system/plots.py
|
@ -4,6 +4,7 @@ import gtk
|
|||
import matplotlib
|
||||
import scipy
|
||||
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTK as NavigationToolbar2
|
||||
from matplotlib.axes import Subplot
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.numerix import arange, sin, pi
|
||||
|
@ -12,13 +13,14 @@ from system import logger
|
|||
|
||||
|
||||
class MainView (gtk.Notebook):
|
||||
def __init__(self):
|
||||
def __init__(self, view_listener):
|
||||
gtk.Notebook.__init__(self)
|
||||
self.set_show_tabs(False)
|
||||
self.set_show_border(False)
|
||||
|
||||
# Add a multiple pane view and a single pane view.
|
||||
self.small_view = SmallView()
|
||||
self.small_view.set_view_listener(view_listener)
|
||||
self.small_view.show()
|
||||
self.large_view = LargeView()
|
||||
self.large_view.show()
|
||||
|
@ -47,7 +49,43 @@ class MainView (gtk.Notebook):
|
|||
def insert_view(self, view):
|
||||
self.small_view.insert_view(view)
|
||||
|
||||
|
||||
class Plot (gtk.Frame):
|
||||
|
||||
def __init__(self, title):
|
||||
gtk.Frame.__init__(self)
|
||||
self.mark_active(False)
|
||||
self.connect('button_press_event', self.on_button_press)
|
||||
self.sel_obj = None
|
||||
self.active = False
|
||||
self.title = title
|
||||
|
||||
def get_title(self):
|
||||
return self.title
|
||||
|
||||
def on_button_press(self, *rest):
|
||||
# logger.log('debug', 'button pressed in plot')
|
||||
self.mark_active(True)
|
||||
|
||||
def mark_active(self, active):
|
||||
if active:
|
||||
self.set_shadow_type(gtk.SHADOW_IN)
|
||||
else:
|
||||
self.set_shadow_type(gtk.SHADOW_OUT)
|
||||
self.active = active
|
||||
|
||||
def update(self, key):
|
||||
pass
|
||||
|
||||
def set_project(self, project):
|
||||
self.project = project
|
||||
|
||||
def get_toolbar(self):
|
||||
return None
|
||||
|
||||
|
||||
class SmallView (gtk.Table):
|
||||
|
||||
def __init__(self):
|
||||
gtk.Table.__init__(self, 2, 2, True)
|
||||
|
||||
|
@ -61,6 +99,7 @@ class SmallView (gtk.Table):
|
|||
|
||||
self.set_row_spacings(3)
|
||||
self.set_col_spacings(3)
|
||||
self._listener = None
|
||||
|
||||
for x in range(self.cols):
|
||||
for y in range(self.rows):
|
||||
|
@ -68,6 +107,9 @@ class SmallView (gtk.Table):
|
|||
child.parent_signalling = child.connect('button_press_event', self.__view_button_event__)
|
||||
self.attach(child, x, x+1, y, y+1)
|
||||
|
||||
def set_view_listener(self, listener):
|
||||
self._listener = listener
|
||||
|
||||
def set_child(self, child, col, row):
|
||||
cur_widget = self.child_views[col][row]
|
||||
cur_widget.disconnect(cur_widget.parent_signalling)
|
||||
|
@ -115,6 +157,9 @@ class SmallView (gtk.Table):
|
|||
new_focus.mark_active(True)
|
||||
self.active_x = x
|
||||
self.active_y = y
|
||||
if self._listener:
|
||||
logger.log("debug", "emitting")
|
||||
self._listener(new_focus)
|
||||
|
||||
def find_child(self, child):
|
||||
for i, row in enumerate(self.child_views):
|
||||
|
@ -157,37 +202,7 @@ class LargeView (gtk.Frame):
|
|||
child.hide()
|
||||
self.remove(child)
|
||||
return child
|
||||
|
||||
class Plot (gtk.Frame):
|
||||
|
||||
def __init__(self, title):
|
||||
gtk.Frame.__init__(self)
|
||||
self.mark_active(False)
|
||||
self.connect('button_press_event', self.on_button_press)
|
||||
self.sel_obj = None
|
||||
self.active = False
|
||||
self.title = title
|
||||
|
||||
def get_title(self):
|
||||
return self.title
|
||||
|
||||
def on_button_press(self, *rest):
|
||||
# logger.log('debug', 'button pressed in plot')
|
||||
self.mark_active(True)
|
||||
|
||||
def mark_active(self, active):
|
||||
if active:
|
||||
self.set_shadow_type(gtk.SHADOW_IN)
|
||||
else:
|
||||
self.set_shadow_type(gtk.SHADOW_OUT)
|
||||
self.active = active
|
||||
|
||||
def update(self, key):
|
||||
pass
|
||||
|
||||
def set_project(self, project):
|
||||
self.project = project
|
||||
|
||||
|
||||
|
||||
class EmptyView (Plot):
|
||||
def __init__(self):
|
||||
|
@ -212,6 +227,101 @@ class EmptyView (Plot):
|
|||
self.label.hide()
|
||||
self.ebox.hide()
|
||||
Plot.hide(self)
|
||||
|
||||
|
||||
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
|
||||
|
||||
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.draw()
|
||||
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 SinePlot(Plot):
|
||||
|
@ -225,9 +335,14 @@ class SinePlot(Plot):
|
|||
ax.plot(t,s)
|
||||
|
||||
self.canvas = FigureCanvas(fig)
|
||||
self._toolbar = NavToolbar(self.canvas, None)
|
||||
self._toolbar.set_property('show-arrow', False)
|
||||
self.add(self.canvas)
|
||||
self.canvas.show()
|
||||
|
||||
def get_toolbar(self):
|
||||
return self._toolbar
|
||||
|
||||
|
||||
class ScatterPlot(Plot):
|
||||
def __init__(self, dataset,id_dim, sel_dim,id_1,id_2):
|
||||
|
@ -243,21 +358,22 @@ class ScatterPlot(Plot):
|
|||
self.xaxis_data = dataset._array[:,x_index]
|
||||
self.yaxis_data = dataset._array[:,y_index]
|
||||
ax.plot(self.xaxis_data,self.yaxis_data,'og')
|
||||
|
||||
###
|
||||
|
||||
self.canvas = FigureCanvas(fig)
|
||||
self.add(self.canvas)
|
||||
rectprops = dict(facecolor='gray', edgecolor = 'black',
|
||||
alpha=0.2, fill=True) #cool
|
||||
self.sel = RectangleSelector(ax, self.rectangle_select_callback,
|
||||
drawtype='box',useblit=True,rectprops=rectprops)
|
||||
|
||||
self.canvas.show()
|
||||
|
||||
def rectangle_select_callback(self,event1, event2):
|
||||
self._toolbar = NavToolbar(self.canvas, None)
|
||||
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'
|
||||
x1, y1 = event1.xdata, event1.ydata
|
||||
x2, y2 = event2.xdata, event2.ydata
|
||||
ydata = self.yaxis_data
|
||||
xdata = self.xaxis_data
|
||||
|
||||
|
@ -297,3 +413,4 @@ class ScatterPlot(Plot):
|
|||
self.ax.plot(self.xaxis_data,self.yaxis_data,'og')
|
||||
self.ax.plot(xdata_new,ydata_new,'or')
|
||||
self.canvas.draw()
|
||||
|
||||
|
|
Reference in New Issue