From: W. Trevor King Date: Thu, 2 Sep 2010 02:06:59 +0000 (-0400) Subject: Added 'block info' to retrieve and export portions of Curve.data[*].info. X-Git-Url: http://git.tremily.us/?p=hooke.git;a=commitdiff_plain;h=74756b77ea19b9b0a76c3de24d0ce6c0ab910656 Added 'block info' to retrieve and export portions of Curve.data[*].info. --- diff --git a/doc/tutorial.txt b/doc/tutorial.txt index e24358f..13e0694 100644 --- a/doc/tutorial.txt +++ b/doc/tutorial.txt @@ -308,69 +308,24 @@ ways.:: hooke> remove_cantilever_from_extension --block retract hooke> flat_peaks_to_polymer_peaks --block retract hooke> polymer_fit_peaks --block retract + hooke> block_info --block retract --output data.yaml name 'polymer peak [0-9]*' This stores the fit parameters in the block's -:attr:`~hooke.curve.Data.info` dictionary (see each command's `Help`_ -for details). To access the parameters, save the playlist,:: - - hooke> save_playlist --output mylist.hkp - -load it with PyYAML_:: +:attr:`~hooke.curve.Data.info` dictionary and also appends them to +:file:`data.yaml` (see each command's `Help`_ for details). To access +the parameters, load :file:`data.yaml` with PyYAML_:: $ python >>> import yaml >>> import hooke.util.yaml - >>> mylist = yaml.load(open('mylist.hkp', 'r')) - -navigate to your curve,:: - - >>> mylist.jump(1234) + >>> data = yaml.load(open('data.yaml', 'r')) -and extract your parameter.:: +and extract your parameter:: - >>> mylist.current().data[1].info['polymer peak 0']['contour length (m)'] + >>> data['20071120a_i27_t33.100']['retract']['polymer peak 0']['contour length (m)'] 2.124...e-08 -You can also get a list of all available parameters:: - - >>> mylist.current().data[1].info['polymer peak 0'].keys() - ['model', 'contour length (m)', 'temperature (K)', 'fit', - 'persistence length (m)'] - -or just pprint_ the whole thing:: - - >>> from pprint import pprint - >>> pprint(mylist.current().data[1].info['polymer peak 0']) - {'contour length (m)': 2.1248220207858103e-08, - 'fit': {'active fitted parameters': 3.7024307200788127, - 'active parameters': 3.7024307200788127, - 'convergence flag': 1, - 'covariance matrix': None, - 'data scale factor': 5.2716380732198972e-10, - 'fitted parameters': -2.5663294148411571, - 'info': {'fjac': None, - 'fvec': None, - 'ipvt': None, - 'nfev': 16, - 'qtf': None}, - 'initial parameters': [-0.69314718055994529], - 'message': 'Both actual and predicted relative reductions in the sum of squares\n are at most 0.000000', - 'rescaled': True, - 'scale': None}, - 'model': u'WLC', - 'persistence length (m)': 4.0000000000000001e-10, - 'temperature (K)': 301.0} - .. _PyYAML: http://pyyaml.org/ -.. _pprint: http://docs.python.org/library/pprint.html - -.. todo:: UI access to block (and curve?) info dicts. Someone should - make a tree-based object browser ;). - -.. todo:: Playlists currently drop all :class:`~hooke.curve.Data` - instances when they are unloaded, so you can't extract the fitted - parameters from unloaded curves. We'll need a way to export chosen - curve attributes to file. Command stacks ~~~~~~~~~~~~~~ @@ -428,7 +383,7 @@ freely jointed chain fitting`_ and `Command stacks`_.:: 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> block_info --block retract --output data.yaml name 'polymer peak [0-9]*' hooke> stop_command_capture hooke> apply_command_stack_to_playlist diff --git a/hooke/plugin/curve.py b/hooke/plugin/curve.py index b287ee4..92e5bd1 100644 --- a/hooke/plugin/curve.py +++ b/hooke/plugin/curve.py @@ -25,8 +25,10 @@ associated :class:`hooke.command.Command`\s for handling """ import copy +import re import numpy +import yaml from ..command import Command, Argument, Failure from ..command_stack import CommandStack @@ -263,8 +265,8 @@ class CurvePlugin (Builtin): def __init__(self): super(CurvePlugin, self).__init__(name='curve') self._commands = [ - GetCommand(self), InfoCommand(self), DeltaCommand(self), - ExportCommand(self), DifferenceCommand(self), + GetCommand(self), InfoCommand(self), BlockInfoCommand(self), + DeltaCommand(self), ExportCommand(self), DifferenceCommand(self), DerivativeCommand(self), PowerSpectrumCommand(self), ClearStackCommand(self)] @@ -345,6 +347,59 @@ class InfoCommand (CurveCommand): return [block.shape for block in curve.data] +class BlockInfoCommand (BlockCommand): + """Get selected information about a :class:`hooke.curve.Curve` data block. + """ + def __init__(self, plugin): + super(BlockInfoCommand, self).__init__( + name='block info', arguments=[ + Argument( + name='key', count=-1, optional=False, + help='Dot-separted (.) key selection regexp.'), + Argument( + name='output', + help=""" +File name for the output (appended). +""".strip()), + ], + help=self.__doc__, plugin=plugin) + + def _run(self, hooke, inqueue, outqueue, params): + block = self._block(hooke, params) + values = {'index': self._block_index(hooke, params)} + for key in params['key']: + keys = [(0, key.split('.'), block.info)] + while len(keys) > 0: + index,key_stack,info = keys.pop(0) + regexp = re.compile(key_stack[index]) + matched = False + for k,v in info.items(): + if regexp.match(k): + matched = True + new_stack = copy.copy(key_stack) + new_stack[index] = k + if index+1 == len(key_stack): + vals = values + for k in new_stack[:-1]: + if k not in vals: + vals[k] = {} + vals = vals[k] + vals[new_stack[-1]] = v + else: + keys.append((index+1, new_stack, v)) + if matched == False: + raise ValueError('no match found for %s in %s' + % (key_stack[index], key)) + if params['output'] != None: + curve = self._curve(hooke, params) + with open(params['output'], 'a') as f: + yaml.dump({curve.name:{ + 'path': curve.path, + block.info['name']: values + }}, f) + outqueue.put(values) + + class DeltaCommand (BlockCommand): """Get distance information between two points. diff --git a/test/block_info.py b/test/block_info.py new file mode 100644 index 0000000..d3da920 --- /dev/null +++ b/test/block_info.py @@ -0,0 +1,52 @@ +# Copyright (C) 2010 W. Trevor King +# +# 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 +# . + +""" +>>> import os +>>> from uuid import uuid4 +>>> from hooke.hooke import Hooke, HookeRunner +>>> h = Hooke() +>>> r = HookeRunner() +>>> h = r.run_lines(h, ['load_playlist test/data/test']) # doctest: +ELLIPSIS + +Success + + +>>> file_name = '%s.block' % uuid4() +>>> block_info_already_exists = os.path.exists(file_name) +>>> block_info_already_exists +False +>>> h = r.run_lines(h, ['block_info --output %s name columns "raw info.file*"' +... % file_name]) # doctest: +ELLIPSIS, +REPORT_UDIFF +{'index': 0, 'name': 'approach', 'columns': ['z piezo (m)', 'deflection (m)'], 'raw info': {'filetype': 'picoforce'}} +Success + +>>> with open(file_name, 'r') as f: +... text = f.read() +>>> if block_info_already_exists == False: +... os.remove(file_name) +>>> print text +picoforce.000: + approach: + columns: [z piezo (m), deflection (m)] + index: 0 + name: approach + raw info: {filetype: picoforce} + path: /tmp/hooke/test/data/picoforce.000 + +"""