X-Git-Url: http://git.tremily.us/?p=hooke.git;a=blobdiff_plain;f=hooke%2Fplugin%2Fcurve.py;h=5df5629f776d1b2c48a096deae4c8e006d8f2778;hp=308124b2549fd541a774d9c1a9ba6dbc3eff5931;hb=07189adf9b2bea4d5ead900693972ebc2dc631e1;hpb=4cf263aabeac8f1c45ce69d08c401cb54fa1eb34 diff --git a/hooke/plugin/curve.py b/hooke/plugin/curve.py index 308124b..5df5629 100644 --- a/hooke/plugin/curve.py +++ b/hooke/plugin/curve.py @@ -1,5 +1,5 @@ -# Copyright (C) 2008-2010 Alberto Gomez-Kasai -# Fabiano's Benedetti +# Copyright (C) 2008-2010 Alberto Gomez-Casado +# Fabrizio Benedetti # Massimo Sandal # W. Trevor King # @@ -29,25 +29,32 @@ import copy import numpy from ..command import Command, Argument, Failure +from ..command_stack import CommandStack from ..curve import Data -from ..plugin import Builtin -from ..plugin.playlist import current_playlist_callback +from ..engine import CommandMessage from ..util.calculus import derivative from ..util.fft import unitary_avg_power_spectrum from ..util.si import ppSI, join_data_label, split_data_label +from . import Builtin +from .playlist import current_playlist_callback # Define common or complicated arguments -def current_curve_callback(hooke, command, argument, value): +def current_curve_callback(hooke, command, argument, value, load=True): if value != None: return value playlist = current_playlist_callback(hooke, command, argument, value) - curve = playlist.current() + curve = playlist.current(load=load) if curve == None: raise Failure('No curves in %s' % playlist) return curve +def unloaded_current_curve_callback(hooke, command, argument, value): + return current_curve_callback( + hooke=hooke, command=command, argument=argument, value=value, + load=False) + CurveArgument = Argument( name='curve', type='curve', callback=current_curve_callback, help=""" @@ -85,6 +92,15 @@ class CurveCommand (Command): super(CurveCommand, self).__init__(**kwargs) def _curve(self, hooke, params): + """Get the selected curve. + + Notes + ----- + `hooke` is intended to attach the selected curve to the local + playlist; the returned curve should not be effected by the + state of `hooke`. This is important for reliable + :class:`~hooke.command_stack.CommandStack`\s. + """ # HACK? rely on params['curve'] being bound to the local hooke # playlist (i.e. not a copy, as you would get by passing a # curve through the queue). Ugh. Stupid queues. As an @@ -92,6 +108,37 @@ class CurveCommand (Command): # queue... return params['curve'] + def _add_to_command_stack(self, params): + """Store the command name and current `params` values in the + curve's `.command_stack`. + + If this would duplicate the command currently on top of the + stack, no action is taken. Call early on, or watch out for + repeated param processing. + + Recommended practice is to *not* lock in argument values that + are loaded from the plugin's :attr:`.config`. + + Notes + ----- + Perhaps we should subclass :meth:`_run` and use :func:`super`, + or embed this in :meth:`run` to avoid subclasses calling this + method explicitly, with all the tedium and brittality that + implies. On the other hand, the current implemtnation allows + CurveCommands that don't effect the curve itself + (e.g. :class:`GetCommand`) to avoid adding themselves to the + stack entirely. + """ + if params['stack'] == True: + curve = self._curve(hooke=None, params=params) + if (len(curve.command_stack) > 0 + and curve.command_stack[-1].command == self.name + and curve.command_stack[-1].arguments == params): + pass # no need to place duplicate calls on the stack. + else: + curve.command_stack.append(CommandMessage( + self.name, params)) + class BlockCommand (CurveCommand): """A :class:`CurveCommand` operating on a :class:`~hooke.curve.Data` block. @@ -161,7 +208,12 @@ class ColumnAccessCommand (BlockCommand): column_name = self._column_arguments[0].name column_name = params[column_name] block = self._block(hooke, params, block_name) - column_index = block.info['columns'].index(column_name) + columns = block.info['columns'] + try: + column_index = columns.index(column_name) + except ValueError, e: + raise Failure('%s not in %s (%s): %s' + % (column_name, block.info['name'], columns, e)) return block[:,column_index] @@ -213,7 +265,8 @@ class CurvePlugin (Builtin): self._commands = [ GetCommand(self), InfoCommand(self), DeltaCommand(self), ExportCommand(self), DifferenceCommand(self), - DerivativeCommand(self), PowerSpectrumCommand(self)] + DerivativeCommand(self), PowerSpectrumCommand(self), + ClearStackCommand(self)] # Define commands @@ -237,8 +290,8 @@ class InfoCommand (CurveCommand): Argument(name='all', type='bool', default=False, count=1, help='Get all curve information.'), ] - self.fields = ['name', 'path', 'experiment', 'driver', 'filetype', 'note', - 'blocks', 'block sizes'] + self.fields = ['name', 'path', 'experiment', 'driver', 'filetype', + 'note', 'command stack', 'blocks', 'block sizes'] for field in self.fields: args.append(Argument( name=field, type='bool', default=False, count=1, @@ -252,7 +305,7 @@ class InfoCommand (CurveCommand): fields = {} for key in self.fields: fields[key] = params[key] - if reduce(lambda x,y: x and y, fields.values()) == False: + if reduce(lambda x,y: x or y, fields.values()) == False: params['all'] = True # No specific fields set, default to 'all' if params['all'] == True: for key in self.fields: @@ -282,6 +335,9 @@ class InfoCommand (CurveCommand): def _get_note(self, curve): return curve.info.get('note', None) + def _get_command_stack(self, curve): + return curve.command_stack + def _get_blocks(self, curve): return len(curve.data) @@ -394,7 +450,8 @@ Name of the new column for storing the difference (without units, defaults to help=self.__doc__, plugin=plugin) def _run(self, hooke, inqueue, outqueue, params): - params = self.__setup_params(hooke=hooke, params=params) + self._add_to_command_stack(params) + params = self._setup_params(hooke=hooke, params=params) data_A = self._get_column(hooke=hooke, params=params, block_name='block A', column_name='column A') @@ -407,7 +464,7 @@ Name of the new column for storing the difference (without units, defaults to column_name='output column', values=out) - def __setup_params(self, hooke, params): + def _setup_params(self, hooke, params): curve = self._curve(hooke, params) if params['block A'] == None: params['block A'] = curve.data[0].info['name'] @@ -468,7 +525,8 @@ central differencing. help=self.__doc__, plugin=plugin) def _run(self, hooke, inqueue, outqueue, params): - params = self.__setup_params(hooke=hooke, params=params) + self._add_to_command_stack(params) + params = self._setup_params(hooke=hooke, params=params) x_data = self._get_column(hooke=hooke, params=params, column_name='x column') f_data = self._get_column(hooke=hooke, params=params, @@ -479,7 +537,7 @@ central differencing. column_name='output column', values=d) - def __setup_params(self, hooke, params): + def _setup_params(self, hooke, params): curve = self._curve(hooke, params) x_name,x_unit = split_data_label(params['x column']) f_name,f_unit = split_data_label(params['f column']) @@ -532,7 +590,8 @@ Otherwise, the chunks are end-to-end, and not overlapping. help=self.__doc__, plugin=plugin) def _run(self, hooke, inqueue, outqueue, params): - params = self.__setup_params(hooke=hooke, params=params) + self._add_to_command_stack(params) + params = self._setup_params(hooke=hooke, params=params) data = self._get_column(hooke=hooke, params=params) bounds = params['bounds'] if bounds != None: @@ -556,7 +615,7 @@ Otherwise, the chunks are end-to-end, and not overlapping. values=power) outqueue.put(b) - def __setup_params(self, hooke, params): + def _setup_params(self, hooke, params): if params['output block'] in self._block_names(hooke, params): raise Failure('output block %s already exists in %s.' % (params['output block'], @@ -573,6 +632,24 @@ Otherwise, the chunks are end-to-end, and not overlapping. return params +class ClearStackCommand (CurveCommand): + """Empty a curve's command stack. + """ + def __init__(self, plugin): + super(ClearStackCommand, self).__init__( + name='clear curve command stack', + help=self.__doc__, plugin=plugin) + i,arg = [(i,arg) for i,arg in enumerate(self.arguments) + if arg.name == 'curve'][0] + arg = copy.copy(arg) + arg.callback = unloaded_current_curve_callback + self.arguments[i] = arg + + def _run(self, hooke, inqueue, outqueue, params): + curve = self._curve(hooke, params) + curve.command_stack = CommandStack() + + class OldCruft (object): def do_forcebase(self,args):