Projects/laydi
Projects
/
laydi
Archived
7
0
Fork 0

The toolbar functionality is almost back to normal.

This commit is contained in:
Einar Ryeng 2006-10-12 11:44:49 +00:00
parent f435b37046
commit 28cab35cd5
1 changed files with 183 additions and 318 deletions

View File

@ -309,10 +309,8 @@ class Plot (View):
if self._frozen \ if self._frozen \
or not self.get_property('visible') \ or not self.get_property('visible') \
or self.current_dim != dim_name: or self.current_dim != dim_name:
print "Ignored a selection changed call in plot: %s" %self.get_title()
return return
print "Setting current selection in: %s " %self.get_title()
self.set_current_selection(selection) self.set_current_selection(selection)
def set_selection_listener(self, listener): def set_selection_listener(self, listener):
@ -443,7 +441,6 @@ class ScatterMarkerPlot(Plot):
self.canvas.show() self.canvas.show()
def rectangle_select_callback(self, x1, y1, x2, y2): def rectangle_select_callback(self, x1, y1, x2, y2):
print "Rectangle select happened in: %s" %self.get_title()
ydata = self.yaxis_data ydata = self.yaxis_data
xdata = self.xaxis_data xdata = self.xaxis_data
@ -480,7 +477,6 @@ class ScatterMarkerPlot(Plot):
self.ax.draw_artist(self._selection_line) self.ax.draw_artist(self._selection_line)
self.canvas.blit() self.canvas.blit()
else: else:
print "A draw happened in: %s" %self.get_title()
self.canvas.draw() self.canvas.draw()
@ -514,7 +510,6 @@ class ScatterPlot(Plot):
self.canvas.show() self.canvas.show()
def rectangle_select_callback(self, x1, y1, x2, y2): def rectangle_select_callback(self, x1, y1, x2, y2):
print "Rectangle select happened in: %s" %self.get_title()
ydata = self.yaxis_data ydata = self.yaxis_data
xdata = self.xaxis_data xdata = self.xaxis_data
@ -547,11 +542,9 @@ class ScatterPlot(Plot):
self.coll.set_linewidth(lw) self.coll.set_linewidth(lw)
if self.use_blit: if self.use_blit:
print "A blit happened in : %s " %self.get_title()
self.canvas.blit() self.canvas.blit()
self.ax.draw_artist(self.coll) self.ax.draw_artist(self.coll)
else: else:
print "A draw happened in : %s " %self.get_title()
self.canvas.draw() self.canvas.draw()
@ -688,31 +681,64 @@ class PlotMode:
return image return image
def activate(self): def activate(self):
"""Subclasses of PlotMode should do their initialization here.
The activate method is called when a mode is activated, and is
used primarily to set up callback functions on events in the
canvas.
"""
pass pass
def deactivate(self): def deactivate(self):
"""Subclasses of PlotMode should do their cleanup here.
The deactivate method is primarily by subclasses of PlotMode to
remove any callbacks they might have on the matplotlib canvas.
"""
pass pass
def _mpl_disconnect_all(self):
"""Disconnects all matplotlib callbacks defined on the canvas.
This is a hack because the RectangleSelector in matplotlib does
not store its callbacks, so we need a workaround to remove them.
"""
callbacks = self.plot.canvas.callbacks
for callbackd in callbacks.values():
for c in callbackd.keys():
del callbackd[c]
class DefaultPlotMode (PlotMode): class DefaultPlotMode (PlotMode):
def __init__(self, plot): def __init__(self, plot):
PlotMode.__init__(self, plot, 'default', 'Default mode', 'cursor.png') PlotMode.__init__(self, plot, 'default', 'Default mode', 'cursor.png')
def activate(self):
for k, v in self.canvas.callbacks.items():
print k, v
class PanPlotMode (PlotMode): class PanPlotMode (PlotMode):
def __init__(self, plot): def __init__(self, plot):
PlotMode.__init__(self, plot, 'pan', PlotMode.__init__(self, plot, 'pan',
'Pan axes with left mouse, zoom with right', 'Pan axes with left mouse, zoom with right',
'move.png') 'move.png')
# Holds handler IDs for callbacks.
self._button_press = None self._button_press = None
self._button_release = None self._button_release = None
self._motion_notify = None
self._button_pressed = None
def activate(self): def activate(self):
self._button_press = self.canvas.mpl_connect( self._button_press = self.canvas.mpl_connect(
'button_press_event', self._on_button_press) 'button_press_event', self._on_button_press)
self._button_relese = self.canvas.mpl_connect( self._button_relese = self.canvas.mpl_connect(
'button_release_event', self._on_button_release) 'button_release_event', self._on_button_release)
self.mode = 'pan/zoom mode' #self._drag = self.canvas.mpl_connect(
# 'mouse_drag_event', self._on_drag)
def deactivate(self): def deactivate(self):
if self._button_press: if self._button_press:
@ -722,10 +748,132 @@ class PanPlotMode (PlotMode):
self.canvas.mpl_disconnect(self._button_release) self.canvas.mpl_disconnect(self._button_release)
def _on_button_press(self, event): def _on_button_press(self, event):
pass
if event.button == 1:
self._button_pressed = 1
elif event.button == 3:
self._button_pressed = 3
else:
self._button_pressed=None
return
x, y = event.x, event.y
# push the current view to define home if stack is empty
# if self._views.empty(): self.push_current()
self._xypress=[]
for i, a in enumerate(self.canvas.figure.get_axes()):
if x is not None and y is not None and a.in_axes(x, y) \
and a.get_navigate():
xmin, xmax = a.get_xlim()
ymin, ymax = a.get_ylim()
lim = xmin, xmax, ymin, ymax
self._xypress.append((x, y, a, i, lim,a.transData.deepcopy()))
self.canvas.mpl_disconnect(self._motion_notify)
cid = self.canvas.mpl_connect('motion_notify_event',
self._on_motion_notify)
self._motion_notify = cid
def _on_motion_notify(self, event):
"""The drag callback in pan/zoom mode"""
def format_deltas(event, dx, dy):
"""Returns the correct dx and dy based on the modifier keys"""
if event.key=='control':
if(abs(dx)>abs(dy)):
dy = dx
else:
dx = dy
elif event.key=='x':
dy = 0
elif event.key=='y':
dx = 0
elif event.key=='shift':
if 2*abs(dx) < abs(dy):
dx=0
elif 2*abs(dy) < abs(dx):
dy=0
elif(abs(dx)>abs(dy)):
dy=dy/abs(dy)*abs(dx)
else:
dx=dx/abs(dx)*abs(dy)
return (dx,dy)
for cur_xypress in self._xypress:
lastx, lasty, a, ind, lim, trans = cur_xypress
xmin, xmax, ymin, ymax = lim
#safer to use the recorded button at the press than current button:
#multiple button can get pressed during motion...
if self._button_pressed==1:
lastx, lasty = trans.inverse_xy_tup( (lastx, lasty) )
x, y = trans.inverse_xy_tup( (event.x, event.y) )
if a.get_xscale()=='log':
dx=1-lastx/x
else:
dx=x-lastx
if a.get_yscale()=='log':
dy=1-lasty/y
else:
dy=y-lasty
dx,dy=format_deltas(event,dx,dy)
if a.get_xscale()=='log':
xmin *= 1-dx
xmax *= 1-dx
else:
xmin -= dx
xmax -= dx
if a.get_yscale()=='log':
ymin *= 1-dy
ymax *= 1-dy
else:
ymin -= dy
ymax -= dy
elif self._button_pressed==3:
try:
dx=(lastx-event.x)/float(a.bbox.width())
dy=(lasty-event.y)/float(a.bbox.height())
dx,dy=format_deltas(event,dx,dy)
if a.get_aspect() != 'auto':
dx = 0.5*(dx + dy)
dy = dx
alphax = pow(10.0,dx)
alphay = pow(10.0,dy)
lastx, lasty = trans.inverse_xy_tup( (lastx, lasty) )
if a.get_xscale()=='log':
xmin = lastx*(xmin/lastx)**alphax
xmax = lastx*(xmax/lastx)**alphax
else:
xmin = lastx+alphax*(xmin-lastx)
xmax = lastx+alphax*(xmax-lastx)
if a.get_yscale()=='log':
ymin = lasty*(ymin/lasty)**alphay
ymax = lasty*(ymax/lasty)**alphay
else:
ymin = lasty+alphay*(ymin-lasty)
ymax = lasty+alphay*(ymax-lasty)
except OverflowError:
warnings.warn('Overflow while panning')
return
a.set_xlim(xmin, xmax)
a.set_ylim(ymin, ymax)
self.canvas.draw()
def _on_button_release(self, event): def _on_button_release(self, event):
pass 'the release mouse button callback in pan/zoom mode'
self.canvas.mpl_disconnect(self._motion_notify)
if not self._xypress: return
self._xypress = None
self._button_pressed=None
self.canvas.draw()
class ZoomPlotMode (PlotMode): class ZoomPlotMode (PlotMode):
@ -747,18 +895,15 @@ class ZoomPlotMode (PlotMode):
self._selectors[rs] = ax self._selectors[rs] = ax
def deactivate(self): def deactivate(self):
for sel in self.selectors: self._mpl_disconnect_all()
self.canvas.mpl_disconnect(sel.onmove)
self.canvas.mpl_disconnect(sel.press)
self.canvas.mpl_disconnect(sel.release)
self.canvas.mpl_disconnect(sel.update_background)
self._selectors = {} self._selectors = {}
def _on_select(self, start, end): def _on_select(self, start, end):
min_x = min(start.xdata, end.xdata) ax = start.inaxes
min_y = min(start.ydata, end.ydata)
max_x = max(start.xdata, end.xdata) ax.set_xlim((min(start.xdata, end.xdata), max(start.xdata, end.xdata)))
max_y = max(start.ydata, end.ydata) ax.set_ylim((min(start.ydata, end.ydata), max(start.ydata, end.ydata)))
self.canvas.draw()
class SelectPlotMode (PlotMode): class SelectPlotMode (PlotMode):
@ -780,11 +925,7 @@ class SelectPlotMode (PlotMode):
self._selectors[rs] = ax self._selectors[rs] = ax
def deactivate(self): def deactivate(self):
for sel in self.selectors: self._mpl_disconnect_all()
self.canvas.mpl_disconnect(sel.onmove)
self.canvas.mpl_disconnect(sel.press)
self.canvas.mpl_disconnect(sel.release)
self.canvas.mpl_disconnect(sel.update_background)
self._selectors = {} self._selectors = {}
def _on_select(self, start, end): def _on_select(self, start, end):
@ -812,6 +953,20 @@ class PlotToolbar(gtk.Toolbar):
self.add_mode(PanPlotMode(self.plot)) self.add_mode(PanPlotMode(self.plot))
self.add_mode(ZoomPlotMode(self.plot)) self.add_mode(ZoomPlotMode(self.plot))
self.add_mode(SelectPlotMode(self.plot)) self.add_mode(SelectPlotMode(self.plot))
self.insert(gtk.SeparatorToolItem(), -1)
# Set up freeze button
btn = gtk.ToggleToolButton()
fname = os.path.join(fluents.ICONDIR, "freeze.png")
image = gtk.Image()
image.set_from_file(fname)
btn.set_icon_widget(image)
btn.connect('toggled', self._on_freeze_toggle)
self.insert(btn, -1)
self.show_all() self.show_all()
def add_mode(self, mode): def add_mode(self, mode):
@ -850,9 +1005,7 @@ class PlotToolbar(gtk.Toolbar):
"""Returns the button that corresponds to a mode name.""" """Returns the button that corresponds to a mode name."""
for b, m in self._mode_buttons.items(): for b, m in self._mode_buttons.items():
if m.name == mode_name: if m.name == mode_name:
print "Found button for mode: %s" % mode_name
return b return b
print "Couldn't find button for mode: %s" % mode_name
return None return None
def set_mode(self, mode_name): def set_mode(self, mode_name):
@ -870,7 +1023,8 @@ class PlotToolbar(gtk.Toolbar):
else: else:
logger.log('warning', 'No such mode: %s' % mode_name) logger.log('warning', 'No such mode: %s' % mode_name)
if self.get_button(mode_name) and not self.get_button(mode_name).get_active(): if self.get_button(mode_name) and \
not self.get_button(mode_name).get_active():
self.get_button(mode_name).set_active(True) self.get_button(mode_name).set_active(True)
return self._current_mode return self._current_mode
@ -879,298 +1033,9 @@ class PlotToolbar(gtk.Toolbar):
if button.get_active(): if button.get_active():
self.set_mode(self._mode_buttons[button].name) self.set_mode(self._mode_buttons[button].name)
# def show(self): def _on_freeze_toggle(self, button):
# for b in self._mode_buttons.keys(): self.plot.set_frozen(button.get_active())
# b.show()
# gtk.Toolbar.show(self)
# class PlotToolbar(NavigationToolbar2,gtk.Toolbar):
# # list of toolitems to add to the toolbar, format is:
# # text, tooltip_text, image_file, callback(str)
# toolitems = (
# ('Home', 'Reset original view', 'home.png', 'home'),
# #('Back', 'Back to previous view','back.png', 'back'),
# #('Forward', 'Forward to next view','forward.png', 'forward'),
# #('Subplots', 'Configure subplots','subplots.png', 'configure_subplots'),
# ('Save', 'Save the figure','filesave.png', 'save_figure'),
# )
# def __init__(self, canvas, plot):
# self.win = None
# self.plot = plot
# gtk.Toolbar.__init__(self)
# NavigationToolbar2.__init__(self, canvas)
# self._idleId = 0
# self._select_callback = None
# canvas.connect('enter-notify-event', self.on_enter_notify)
# def _init_toolbar(self):
# self.set_style(gtk.TOOLBAR_ICONS)
# self.tooltips = gtk.Tooltips()
# self._modes = {}
# self._selector = None
# self.set_property('show-arrow', False)
# basedir = fluents.ICONDIR
# # setup base buttons
# for text, tooltip_text, image_file, callback in self.toolitems:
# if text is None:
# self.insert(gtk.SeparatorToolItem(), -1 )
# continue
# fname = os.path.join(basedir, image_file)
# image = gtk.Image()
# image.set_from_file(fname)
# tbutton = gtk.ToolButton(image, text)
# self.insert(tbutton, -1)
# tbutton.connect('clicked', getattr(self, callback))
# tbutton.set_tooltip(self.tooltips, tooltip_text, 'Private')
# self.insert(gtk.SeparatorToolItem(), -1)
# # mode/state buttons
# rbutton = None
# for text,tooltip_text,image_file,callback in self.radiobuttons:
# if text is None:
# self.insert(gtk.SeparatorToolItem(), -1 )
# continue
# fname = os.path.join(basedir, image_file)
# image = gtk.Image()
# image.set_from_file(fname)
# rbutton = gtk.RadioToolButton(rbutton)
# rbutton.set_icon_widget(image)
# rbutton.connect('toggled', getattr(self, callback))
# rbutton.set_tooltip(self.tooltips, tooltip_text, 'Private')
# self._modes[text] = rbutton
# a self.insert(rbutton, -1)
# self.insert(gtk.SeparatorToolItem(), -1)
# toolitem = gtk.ToolItem()
# self.insert(toolitem, -1)
# self.message = gtk.Label()
# toolitem.add(self.message)
# self.tb_freeze = gtk.ToolItem()
# self.chk = gtk.CheckButton ()
# self.chk.set_label ('Freeze')
# self.tb_freeze.add (self.chk)
# self.tb_freeze.set_tooltip(self.tooltips, 'Freeze current selection')
# self.insert(self.tb_freeze,-1)
# toolitem = gtk.SeparatorToolItem()
# self.insert(toolitem, -1)
# self.show_all()
# self.fileselect = FileChooserDialog(title='Save the figure', parent=self.win,)
# def on_enter_notify(self, widget, event):
# if self._active != active_mode:
# self.set_mode(active_mode)
# self.set_mode(active_mode)
# def set_mode(self, mode):
# ## Do nothing if this mode is already active
# if self.mode == mode:
# print "set_mode: already in mode '%s': returning" % mode
# return mode
# ## Remove current Selector if set.
# if self._selector != None:
# self.canvas.mpl_disconnect(self._selector.onmove)
# self.canvas.mpl_disconnect(self._selector.press)
# self.canvas.mpl_disconnect(self._selector.release)
# self.canvas.mpl_disconnect(self._selector.update_background)
# print "set_mode: Removing selector in: %s" %self.plot.get_title()
# self._selector = None
# ## Remove current mouse button bindings
# if self._idPress != None:
# self._idPress = self.canvas.mpl_disconnect(self._idPress)
# self.mode = ''
# if self._idRelease != None:
# self._idRelease = self.canvas.mpl_disconnect(self._idRelease)
# self.mode = ''
# ## Set state, and do state initialization
# self.mode = mode
# def set_mode(self, active):
# print "Set mode called in toolbar from: %s" %self.plot.get_title()
# # if state is unkown or not set, set to default
# if active == None or active not in self._modes.keys():
# active = 'DEFAULT'
# # remove current Selector:
# if self._selector != None:
# # problem is ... i have mutliple selectors still connected
# # trying to remove old selectors connections
# #
# # blah
# # Her Einar ...
# #
# self.canvas.mpl_disconnect(self._selector.onmove)
# self.canvas.mpl_disconnect(self._selector.press)
# self.canvas.mpl_disconnect(self._selector.release)
# self.canvas.mpl_disconnect(self._selector.update_background)
# print "Removing selector in: %s" %self.plot.get_title()
# self._selector = None
# # remove current button bindings
# if self._idPress != None:
# self._idPress = self.canvas.mpl_disconnect(self._idPress)
# self.mode = ''
# if self._idRelease != None:
# self._idRelease = self.canvas.mpl_disconnect(self._idRelease)
# self.mode = ''
# self._modes[active]
# for state, button in self._modes.items():
# if state != active:
# continue
# if state == 'SELECT':
# for ax in self.canvas.figure.get_axes():
# props = dict(facecolor='blue', edgecolor = 'black',
# alpha=0.3, fill=True)
# print "creating a selector"
# self._selector = RectangleSelector(ax, self.on_select,
# drawtype='box', useblit=True,
# rectprops=props)
# self.mode = 'Select rectangle mode'
# 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, selector):
# 'eclick and erelease are matplotlib events at press and release'
# if self._select_callback:
# print "Onselect called:"
# print " %s" % selector
# self._select_callback(eclick.xdata, eclick.ydata, erelease.xdata, erelease.ydata)
# 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 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.