continuing), you can continue adding to the same stack with
``restart_command_capture.``
+To execute a command stack, run::
+
+ hooke> execute_command_stack
+
+To execute a command stack on every curve in a playlist, run::
+
+ hooke> apply_command_stack_to_playlist
+
+If you decide that there are commands in a curve's stack that you
+don't want, you can clear the stack with::
+
+ hooke> clear_curve_command_stack
+
You can also save command stacks to disk (and reload them later,
-potentially in a different Hooke session).
+potentially in a different Hooke session).::
hooke> save_command_stack --output my_stack
hooke> load_command_stack --input my_stack
-Multiple curve fitting and measuring
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. todo:: Update multiple curve fitting tutorial section.
-
-You can cycle through all your current playlist obtaining WLC fit, FJC
-fit, rupture force and slope (loading rate) information from each
-curve using the ``multifit`` command. The collected data can be saved
-in a text file for further analysis in your favourite spreadsheet or
-statistical program. If you want to check your parameters on the
-current curve before fitting all the files in your playlist, use
-``multifit justone``. See the ``multifit`` help for more options.
+Multiple curve analysis
+~~~~~~~~~~~~~~~~~~~~~~~
+
+You can analyze multiple curves by combining `Worm like chain and
+freely jointed chain fitting`_ and `Command stacks`_.::
+
+ hooke> start_command_capture
+ hooke> zero_surface_contact_point --block retract
+ hooke> flat_filter_peaks --block retract --min_points 1
+ hooke> zero_surface_contact_point --block retract
+ ... --ignore_after_last_peak_info_name 'flat filter peaks'
+ hooke> convert_distance_to_force --block retract
+ ... --deflection_column 'surface deflection (m)'
+ hooke> remove_cantilever_from_extension --block retract
+ hooke> flat_peaks_to_polymer_peaks --block retract
+ hooke> polymer_fit_peaks --block retract
+ hooke> export_block --block retract --output myblock.dat
+ hooke> stop_command_capture
+ hooke> apply_command_stack_to_playlist
Fast curve reviewing and saving
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
self.arguments = [
Argument(name='help', type='bool', default=False, count=1,
help='Print a help message.'),
+ Argument(name='stack', type='bool', default=True, count=1,
+ help='Add this command to appropriate command stacks.'),
] + arguments
self._help = help
self.plugin = plugin
>>> print [repr(cm) for cm in c]
[]
"""
- def execute(self, hooke):
+ def execute(self, hooke, stack=False):
"""Execute a stack of commands.
See Also
for command_message in self:
if self.filter(hooke, command_message) == True:
self.execute_command(
- hooke=hooke, command_message=command_message)
+ hooke=hooke, command_message=command_message, stack=stack)
def filter(self, hooke, command_message):
"""Return `True` to execute `command_message`, `False` otherwise.
"""
return True
- def execute_command(self, hooke, command_message):
+ def execute_command(self, hooke, command_message, stack=False):
+ arguments = dict(command_message.arguments)
+ arguments['stack'] = stack
hooke.run_command(command=command_message.command,
- arguments=command_message.arguments)
+ arguments=arguments)
def clear(self):
while len(self) > 0:
class CommandStackCommand (Command):
"""Subclass to avoid pushing control commands to the stack.
"""
+ def __init__(self, *args, **kwargs):
+ super(CommandStackCommand, self).__init__(*args, **kwargs)
+ stack = [a for a in self.arguments if a.name == 'stack'][0]
+ stack.default = False
+
def _set_state(self, state):
try:
self.plugin.set_state(state)
StartCaptureCommand(self), StopCaptureCommand(self),
ReStartCaptureCommand(self),
PopCommand(self), GetCommand(self), GetStateCommand(self),
- SaveCommand(self), LoadCommand(self),
+ SaveCommand(self), LoadCommand(self), ExecuteCommand(self),
]
self._settings = [
Setting(section=self.setting_section, help=self.__doc__),
params['input'] = os.path.join(
self.plugin.config['path'], params['input'])
return params
+
+
+class ExecuteCommand (Command):
+ """Execute a :class:`~hooke.command_stack.CommandStack`.
+ """
+ def __init__(self, plugin):
+ super(ExecuteCommand, self).__init__(
+ name='execute command stack',
+ arguments=[
+ Argument(name='commands', type='command stack',
+ help="""
+Command stack to apply to each curve. Defaults to the plugin's
+current stack.
+""".strip()),
+ ],
+ help=self.__doc__, plugin=plugin)
+ stack = [a for a in self.arguments if a.name == 'stack'][0]
+ stack.default = False
+
+ def _run(self, hooke, inqueue, outqueue, params):
+ params = self.__setup_params(hooke=hooke, params=params)
+ if len(params['commands']) == 0:
+ return
+ params['commands'].execute(hooke=hooke, stack=params['stack'])
+
+ def __setup_params(self, hooke, params):
+ if params['commands'] == None:
+ params['commands'] = self.plugin.command_stack
+ return params
import numpy
from ..command import Command, Argument, Failure
+from ..command_stack import CommandStack
from ..curve import Data
from ..engine import CommandMessage
from ..util.calculus import derivative
(e.g. :class:`GetCommand`) to avoid adding themselves to the
stack entirely.
"""
- 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))
+ 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):
self._commands = [
GetCommand(self), InfoCommand(self), DeltaCommand(self),
ExportCommand(self), DifferenceCommand(self),
- DerivativeCommand(self), PowerSpectrumCommand(self)]
+ DerivativeCommand(self), PowerSpectrumCommand(self),
+ ClearStackCommand(self)]
# Define commands
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)
+
+ def _run(self, hooke, inqueue, outqueue, params):
+ curve = self._curve(hooke, params)
+ curve.command_stack = CommandStack()
+
+
class OldCruft (object):
def do_forcebase(self,args):
help=self.__doc__, plugin=plugin)
def _run(self, hooke, inqueue, outqueue, params):
- outqueue.put(params['target'].info['note'])
+ outqueue.put(params['target'].info.get('note', None))
class NoteFilterCommand (FilterCommand):
import os.path
from ..command import Command, Argument, Failure
-from ..playlist import FilePlaylist
from ..curve import NotRecognized
+from ..playlist import FilePlaylist
+from ..util.itertools import reverse_enumerate
from . import Builtin
GetCommand(self), IndexCommand(self), CurveListCommand(self),
SaveCommand(self), LoadCommand(self),
AddCommand(self), AddGlobCommand(self),
- RemoveCommand(self), ApplyCommandStack(self),
+ RemoveCommand(self), ApplyCommand(self),
FilterCommand(self),
]
self._playlist(hooke, params).jump(params.index())
-class ApplyCommandStack (PlaylistCommand):
+class ApplyCommand (PlaylistCommand):
"""Apply a :class:`~hooke.command_stack.CommandStack` to each
curve in a playlist.
TODO: discuss `evaluate`.
"""
def __init__(self, plugin):
- super(ApplyCommandStack, self).__init__(
- name='apply command stack',
+ super(ApplyCommand, self).__init__(
+ name='apply command stack to playlist',
arguments=[
- Argument(name='commands', type='command stack', optional=False,
+ Argument(name='commands', type='command stack',
help="""
-Command stack to apply to each curve.
+Command stack to apply to each curve. Defaults to the `command_stack`
+plugin's current stack.
""".strip()),
Argument(name='evaluate', type='bool', default=False,
help="""
help=self.__doc__, plugin=plugin)
def _run(self, hooke, inqueue, outqueue, params):
- if len(params['commands']) == 0:
- return
+ params = self.__setup_params(hooke=hooke, params=params)
p = self._playlist(hooke, params)
if params['evaluate'] == True:
+ exec_cmd = hooke.command_by_name['execute command stack']
for curve in p.items():
- for command in params['commands']:
- curve.command_stack.execute_command(hooke, command)
- curve.command_stack.append(command)
+ hooke.run_command(exec_cmd.name,
+ {'commands':params['commands'],
+ 'stack':True})
else:
for curve in p:
- curve.command_stack.extend(params['commands'])
- curve.unload() # force command stack execution on next access.
+ for command in params['commands']:
+ curve.command_stack.append(command)
+ curve.set_hooke(hooke)
+ curve.unload()
+
+ def __setup_params(self, hooke, params):
+ if params['commands'] == None:
+ cstack_plugin = [p for p in hooke.plugins
+ if p.name == 'command_stack'][0]
+ params['commands'] = cstack_plugin.command_stack
+ return params
class FilterCommand (PlaylistAddingCommand, PlaylistCommand):
... CommandMessage('zero surface contact point'),
... ])
-Test `apply command stack`.
+Test `apply command stack to playlist`.
->>> h.run_command('apply command stack',
+>>> h.run_command('apply command stack to playlist',
... {'commands': stack, 'evaluate': True}) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE, +REPORT_UDIFF
-engine running internal <CommandMessage apply command stack
+engine running internal <CommandMessage apply command stack to playlist
{commands: [<CommandMessage get curve>,
<CommandMessage zero surface contact point>],
evaluate: True}>
loading curve 20071120a_i27_t33.100 with driver ...
-engine running internal <CommandMessage get curve>
+engine running internal <CommandMessage execute command stack {...}>
+engine running internal <CommandMessage get curve {stack: True}>
engine message from get curve (<class 'hooke.curve.Curve'>): <Curve 20071120a_i27_t33.100>
engine message from get curve (<class 'hooke.command.Success'>):
-engine running internal <CommandMessage zero surface contact point>
+engine running internal <CommandMessage zero surface contact point {...}>
engine message from zero surface contact point (<type 'dict'>): {...}
engine message from zero surface contact point (<class 'hooke.command.Success'>):
+engine message from execute command stack (<class 'hooke.command.Success'>):
loading curve 20071120a_i27_t33.101 with driver ...
-engine running internal <CommandMessage get curve>
+engine running internal <CommandMessage execute command stack {...}>
+engine running internal <CommandMessage get curve {stack: True}>
engine message from get curve (<class 'hooke.curve.Curve'>): <Curve 20071120a_i27_t33.101>
engine message from get curve (<class 'hooke.command.Success'>):
-engine running internal <CommandMessage zero surface contact point>
+engine running internal <CommandMessage zero surface contact point {...}>
engine message from zero surface contact point (<type 'dict'>): {...}
engine message from zero surface contact point (<class 'hooke.command.Success'>):
+engine message from execute command stack (<class 'hooke.command.Success'>):
loading curve 20071120a_i27_t33.102 with driver ...
+
...
loading curve 20071120a_i27_t33.199 with driver ...
-engine running internal <CommandMessage get curve>
+engine running internal <CommandMessage execute command stack {...}>
+engine running internal <CommandMessage get curve {stack: True}>
engine message from get curve (<class 'hooke.curve.Curve'>): <Curve 20071120a_i27_t33.199>
engine message from get curve (<class 'hooke.command.Success'>):
-engine running internal <CommandMessage zero surface contact point>
+engine running internal <CommandMessage zero surface contact point {...}>
engine message from zero surface contact point (<type 'dict'>): {...}
engine message from zero surface contact point (<class 'hooke.command.Success'>):
+engine message from execute command stack (<class 'hooke.command.Success'>):
loading curve 0x06130001 with driver ...
unloading curve 20071120a_i27_t33.100
-engine running internal <CommandMessage get curve>
+engine running internal <CommandMessage execute command stack
+ {commands: [<CommandMessage get curve>,
+ <CommandMessage zero surface contact point>],
+ curve: ...}>
+engine running internal <CommandMessage get curve {stack: True}>
+...
+engine message from apply command stack to playlist (<class 'hooke.command.Success'>):
+>>> curve = h.playlists.current().current(
+... ) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+loading curve 20071120a_i27_t33.100 with driver ...
+engine running internal <CommandMessage zero surface contact point
+ {block: None, curve: <Curve 20071120a_i27_t33.100>, ...}>
+engine message from zero surface contact point (<type 'dict'>): {...}
+engine message from zero surface contact point (<class 'hooke.command.Success'>):
+unloading curve 20071120a_i27_t33.102
+>>> curve
+<Curve 20071120a_i27_t33.100>
+>>> curve.command_stack # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+[<CommandMessage zero surface contact point
+ {block: None, curve: <Curve 20071120a_i27_t33.100>, ...}>]
+
+Test `apply command stack to playlist` without evaluating.
+
+>>> stack = CommandStack([
+... CommandMessage('flat_filter_peaks --block retract --min_points 1'),
+... ])
+>>> h.run_command('apply command stack to playlist',
+... {'commands': stack, 'evaluate': False}
+... ) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE, +REPORT_UDIFF
+engine running internal
+ <CommandMessage apply command stack to playlist {...}>
+unloading curve 20071120a_i27_t33.100
+unloading curve 20071120a_i27_t33.101
+unloading curve 20071120a_i27_t33.102
...
-engine message from apply command stack (<class 'hooke.command.Success'>):
+unloading curve 20071120a_i27_t33.199
+unloading curve 0x06130001
+unloading curve 0x07200000
+engine message from apply command stack to playlist
+ (<class 'hooke.command.Success'>):
+>>> for c in curve.command_stack:
+... print c # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE, +REPORT_UDIFF
+<CommandMessage zero surface contact point
+ {..., curve: <Curve 20071120a_i27_t33.100>...}>
+<CommandMessage flat_filter_peaks --block retract --min_points 1>
+
+Test `clear curve command stack`.
+
+>>> h.run_command('clear curve command stack', arguments={})
+engine running internal <CommandMessage clear curve command stack>
+engine message from clear curve command stack (<class 'hooke.command.Success'>):
+>>> curve.command_stack
+[]
"""
# <http://www.gnu.org/licenses/>.
"""
+>>> import logging
+>>> import sys
>>> from hooke.hooke import Hooke, HookeRunner
>>> h = Hooke()
>>> r = HookeRunner()
[]
Success
<BLANKLINE>
+
+Building command stacks is fun, but its useless if you can't execute
+them. First, lets repopulate the in-memory stack.
+
+>>> h = r.run_lines(h, ['start_command_capture',
+... 'debug --attribute config',
+... 'version',
+... 'stop_command_capture']
+... ) # doctest: +REPORT_UDIFF
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+
+Setup logging so we can check command output in the doctest.
+
+>>> log = logging.getLogger('hooke')
+>>> stdout_handler = logging.StreamHandler(sys.stdout)
+>>> log.addHandler(stdout_handler)
+
+Execute the stack. We use `h.run_command` because `sys.stdout` is
+replaced by a `doctest._SpoofOut`, and doctest has no way to collect
+those results from `run_lines`'s engine subprocess.
+
+>>> h.run_command('execute command stack', arguments={}
+... ) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE, +REPORT_UDIFF
+engine running internal <CommandMessage execute command stack>
+engine running internal <CommandMessage debug {attribute: config, ...}>
+engine message from debug (<type 'instance'>):
+ <hooke.config.HookeConfigParser instance at 0x...>
+engine message from debug (<class 'hooke.command.Success'>):
+engine running internal <CommandMessage version {stack: False}>
+engine message from version (<type 'str'>): Hooke 1.0.0.alpha (Ninken)
+----
+...
+engine message from version (<class 'hooke.command.Success'>):
+engine message from execute command stack (<class 'hooke.command.Success'>):
"""
--- /dev/null
+# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+#
+# This file is part of Hooke.
+#
+# Hooke is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# Hooke is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+# Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Hooke. If not, see
+# <http://www.gnu.org/licenses/>.
+
+"""
+>>> from hooke.hooke import Hooke, HookeRunner
+>>> h = Hooke()
+>>> r = HookeRunner()
+
+Setup a playlist to act on.
+
+>>> h = r.run_lines(h, ['load_playlist test/data/vclamp_picoforce/playlist'])
+<FilePlaylist playlist.hkp>
+Success
+<BLANKLINE>
+
+Build the command stack.
+
+>>> h = r.run_lines(h, [
+... 'start_command_capture',
+... 'zero_surface_contact_point --block retract',
+... 'flat_filter_peaks --block retract --min_points 1',
+... 'zero_surface_contact_point --block retract --ignore_after_last_peak_info_name "flat filter peaks"',
+... 'convert_distance_to_force --block retract --deflection_column "surface deflection (m)"',
+... 'remove_cantilever_from_extension --block retract',
+... 'flat_peaks_to_polymer_peaks --block retract',
+... 'polymer_fit_peaks --block retract',
+... 'stop_command_capture',
+... ]) # doctest: +REPORT_UDIFF
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+Success
+<BLANKLINE>
+
+Apply the command stack.
+
+>>> h = r.run_lines(h, ['apply_command_stack_to_playlist'])
+Success
+<BLANKLINE>
+
+Verify successful application.
+
+>>> curve = h.playlists.current().current()
+>>> curve
+<Curve 20071120a_i27_t33.100>
+>>> for c in curve.command_stack:
+... print c # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE, +REPORT_UDIFF
+<CommandMessage zero surface contact point {block: retract}>
+<CommandMessage flat filter peaks {block: retract, min points: 1}>
+<CommandMessage zero surface contact point {block: retract, ignore after last peak info name: flat filter peaks}>
+<CommandMessage convert distance to force {block: retract, deflection column: surface deflection (m)}>
+<CommandMessage remove cantilever from extension {block: retract}>
+<CommandMessage flat peaks to polymer peaks {block: retract}>
+<CommandMessage polymer fit peaks {block: retract}>
+>>> for c in curve.data[-1].info['columns']:
+... print c # doctest: +REPORT_UDIFF
+z piezo (m)
+deflection (m)
+surface distance (m)
+surface deflection (m)
+flat filter peaks (m)
+deflection (N)
+cantilever adjusted extension (m)
+polymer peak 0 (N)
+>>> h.playlists.current().next()
+>>> curve = h.playlists.current().current()
+>>> curve
+<Curve 20071120a_i27_t33.101>
+>>> for c in curve.command_stack:
+... print c # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE, +REPORT_UDIFF
+<CommandMessage zero surface contact point {block: retract}>
+<CommandMessage flat filter peaks {block: retract, min points: 1}>
+<CommandMessage zero surface contact point {block: retract, ignore after last peak info name: flat filter peaks}>
+<CommandMessage convert distance to force {block: retract, deflection column: surface deflection (m)}>
+<CommandMessage remove cantilever from extension {block: retract}>
+<CommandMessage flat peaks to polymer peaks {block: retract}>
+<CommandMessage polymer fit peaks {block: retract}>
+>>> for c in curve.data[-1].info['columns']:
+... print c # doctest: +REPORT_UDIFF
+z piezo (m)
+deflection (m)
+surface distance (m)
+surface deflection (m)
+flat filter peaks (m)
+deflection (N)
+cantilever adjusted extension (m)
+polymer peak 0 (N)
+"""
Arguments:
<BLANKLINE>
help BOOL (bool) Print a help message.
+stack BOOL (bool) Add this command to appropriate command stacks.
output_playlist STRING (string) Name of the new playlist (defaults to
an auto-generated name).
input FILE (file) File name for the input playlist.
Success
<BLANKLINE>
>>> h = r.run_lines(h, ['new_playlist --output_playlist mylist'])
+<FilePlaylist mylist>
Success
<BLANKLINE>
>>> h = r.run_lines(h, ['jump_to_playlist -- -1'])
*Command stacks*
-See :file:`command_stack.py`and :file:`command_stack_save_load.py`.
+See :file:`command_stack.py`,
+:file:`apply_command_stack_to_playlist.py`, and
+:file:`command_stack_save_load.py`.
+
+*Multiple curve analysis*
-*Multiple curve fitting and measuring*
+See :file:`multiple_curve_analysis`.
*Fast curve reviewing and saving*