From: W. Trevor King Date: Mon, 17 May 2010 14:29:41 +0000 (-0400) Subject: Moving hooke.plugin.procplots to .curve in preparation for merge X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=bff2e146f66541f8935c634b93aa4bf4d74b04ca;p=hooke.git Moving hooke.plugin.procplots to .curve in preparation for merge --- diff --git a/hooke/plugin/curve.py b/hooke/plugin/curve.py index 1e0ad06..3868a83 100644 --- a/hooke/plugin/curve.py +++ b/hooke/plugin/curve.py @@ -1,5 +1,6 @@ -# Copyright (C) 2010 Fibrin's Benedetti -# W. Trevor King +# Copyright (C) 2008-2010 Alberto Gomez-Casado +# Massimo Sandal +# W. Trevor King # # This file is part of Hooke. # @@ -17,133 +18,285 @@ # License along with Hooke. If not, see # . -"""The ``curve`` module provides :class:`CurvePlugin` and several -associated :class:`hooke.command.Command`\s for handling -:mod:`hooke.curve` classes. +"""Processed plots plugin for force curves. """ -from ..command import Command, Argument, Failure -from ..plugin import Builtin -from ..plugin.playlist import current_playlist_callback - - -class CurvePlugin (Builtin): - def __init__(self): - super(CurvePlugin, self).__init__(name='curve') - - def commands(self): - return [InfoCommand(), ] - - -# Define common or complicated arguments - -def current_curve_callback(hooke, command, argument, value): - if value != None: - return value - playlist = current_playlist_callback(hooke, command, argument, value) - curve = playlist.current() - if curve == None: - raise Failure('No curves in %s' % playlist) - return curve - -CurveArgument = Argument( - name='curve', type='curve', callback=current_curve_callback, - help=""" -:class:`hooke.curve.Curve` to act on. Defaults to the current curve -of the current playlist. -""".strip()) - - -# Define commands - -class InfoCommand (Command): - """Print selected information about a :class:`hooke.curve.Curve`. - """ - def __init__(self): - args = [ - CurveArgument, - Argument(name='all', type='bool', default=False, count=1, - help='Print all curve information.'), - ] - self.fields = ['name', 'path', 'experiment', 'driver', 'filetype', 'note', - 'blocks', 'block sizes'] - for field in self.fields: - args.append(Argument( - name=field, type='bool', default=False, count=1, - help='Print curve %s' % field)) - super(InfoCommand, self).__init__( - name='curve info', arguments=args, help=self.__doc__) - - def _run(self, hooke, inqueue, outqueue, params): - fields = {} - for key in self.fields: - fields[key] = params[key] - if reduce(lambda x,y: x and y, fields.values()) == False: - params['all'] = True # No specific fields set, default to 'all' - if params['all'] == True: - for key in self.fields: - fields[key] = True - lines = [] - for key in self.fields: - if fields[key] == True: - get = getattr(self, '_get_%s' % key.replace(' ', '_')) - lines.append('%s: %s' % (key, get(params['curve']))) - outqueue.put('\n'.join(lines)) - - def _get_name(self, curve): - return curve.name - - def _get_path(self, curve): - return curve.path - - def _get_experiment(self, curve): - return curve.info.get('experiment', None) - - def _get_driver(self, curve): - return curve.driver - - def _get_filetype(self, curve): - return curve.info.get('filetype', None) - - def _get_note(self, curve): - return curve.info.get('note', None) - - def _get_blocks(self, curve): - return len(curve.data) - - def _get_block_sizes(self, curve): - return [block.shape for block in curve.data] - - -class ExportCommand (Command): - """Export a :class:`hooke.curve.Curve` data block as TAB-delimeted - ASCII text. - """ - def __init__(self): - self.fields = ['name', 'path', 'experiment', 'driver', 'filetype', 'note', - 'blocks', 'block sizes'] - for field in self.fields: - args.append(Argument( - name=field, type='bool', default=False, count=1, - help='Print curve %s' % field)) - super(InfoCommand, self).__init__( - name='curve info', - arguments=[ - CurveArgument, - Argument(name='block', aliases=['set'], type='int', default=0, - help=""" -Data block to save. For an approach/retract force curve, `0` selects -the approacing curve and `1` selects the retracting curve. -""".strip()), - Argument(name='output', type='file', default='curve.dat', - help=""" -File name for the output data. Defaults to 'curve.dat' -""".strip()), - ], - help=self.__doc__) - - def _run(self, hooke, inqueue, outqueue, params): - data = params['curve'].data[params['index']] - f = open(params['output'], 'w') - data.tofile(f, sep='\t') - f.close() +from ..libhooke import WX_GOOD +import wxversion +wxversion.select(WX_GOOD) + +import wx +import numpy as np +import scipy as sp +import scipy.signal +import copy + +from .. import curve as lhc + + +class procplotsCommands(object): + + def _plug_init(self): + pass + + def do_derivplot(self,args): + ''' + DERIVPLOT + (procplots.py plugin) + Plots the derivate (actually, the discrete differentiation) of the current force curve + --------- + Syntax: derivplot + ''' + dplot=self.derivplot_curves() + plot_graph=self.list_of_events['plot_graph'] + wx.PostEvent(self.frame,plot_graph(plots=[dplot])) + + def derivplot_curves(self): + ''' + do_derivplot helper function + + create derivate plot curves for force curves. + ''' + dplot=lhc.PlotObject() + dplot.vectors=[] + + for vector in self.plots[0].vectors: + dplot.vectors.append([]) + dplot.vectors[-1].append(vector[0][:-1]) + dplot.vectors[-1].append(np.diff(vector[1])) + + dplot.destination=1 + dplot.units=self.plots[0].units + + return dplot + + def do_subtplot(self, args): + ''' + SUBTPLOT + (procplots.py plugin) + Plots the difference between ret and ext current curve + ------- + Syntax: subtplot + ''' + #FIXME: sub_filter and sub_order must be args + + if len(self.plots[0].vectors) != 2: + print 'This command only works on a curve with two different plots.' + pass + + outplot=self.subtract_curves(sub_order=1) + + plot_graph=self.list_of_events['plot_graph'] + wx.PostEvent(self.frame,plot_graph(plots=[outplot])) + + def subtract_curves(self, sub_order): + ''' + subtracts the extension from the retraction + ''' + xext=self.plots[0].vectors[0][0] + yext=self.plots[0].vectors[0][1] + xret=self.plots[0].vectors[1][0] + yret=self.plots[0].vectors[1][1] + + #we want the same number of points + maxpoints_tot=min(len(xext),len(xret)) + xext=xext[0:maxpoints_tot] + yext=yext[0:maxpoints_tot] + xret=xret[0:maxpoints_tot] + yret=yret[0:maxpoints_tot] + + if sub_order: + ydiff=[yretval-yextval for yretval,yextval in zip(yret,yext)] + else: #reverse subtraction (not sure it's useful, but...) + ydiff=[yextval-yretval for yextval,yretval in zip(yext,yret)] + + outplot=copy.deepcopy(self.plots[0]) + outplot.vectors[0][0], outplot.vectors[1][0] = xext,xret #FIXME: if I use xret, it is not correct! + outplot.vectors[1][1]=ydiff + outplot.vectors[0][1]=[0 for item in outplot.vectors[1][0]] + + return outplot + + +#-----PLOT MANIPULATORS + def plotmanip_median(self, plot, current, customvalue=None): + ''' + does the median of the y values of a plot + ''' + if customvalue: + median_filter=customvalue + else: + median_filter=self.config['medfilt'] + + if median_filter==0: + return plot + + if float(median_filter)/2 == int(median_filter)/2: + median_filter+=1 + + nplots=len(plot.vectors) + c=0 + while cstartvalue: + cutindex=index + else: + break + + plot.vectors[0][0]=plot.vectors[0][0][:cutindex] + plot.vectors[0][1]=plot.vectors[0][1][:cutindex] + + return plot + ''' + + + +#FFT--------------------------- + def fft_plot(self, vector): + ''' + calculates the fast Fourier transform for the selected vector in the plot + ''' + fftplot=lhc.PlotObject() + fftplot.vectors=[[]] + + fftlen=len(vector)/2 #need just 1/2 of length + fftplot.vectors[-1].append(np.arange(1,fftlen).tolist()) + + try: + fftplot.vectors[-1].append(abs(np.fft(vector)[1:fftlen]).tolist()) + except TypeError: #we take care of newer NumPy (1.0.x) + fftplot.vectors[-1].append(abs(np.fft.fft(vector)[1:fftlen]).tolist()) + + + fftplot.destination=1 + + + return fftplot + + + def do_fft(self,args): + ''' + FFT + (procplots.py plugin) + Plots the fast Fourier transform of the selected plot + --- + Syntax: fft [top,bottom] [select] [0,1...] + + By default, fft performs the Fourier transform on all the 0-th data set on the + top plot. + + [top,bottom]: which plot is the data set to fft (default: top) + [select]: you pick up two points on the plot and fft only the segment between + [0,1,...]: which data set on the selected plot you want to fft (default: 0) + ''' + + #args parsing + #whatplot = plot to fft + #whatset = set to fft in the plot + select=('select' in args) + if 'top' in args: + whatplot=0 + elif 'bottom' in args: + whatplot=1 + else: + whatplot=0 + whatset=0 + for arg in args: + try: + whatset=int(arg) + except ValueError: + pass + + if select: + points=self._measure_N_points(N=2, whatset=whatset) + boundaries=[points[0].index, points[1].index] + boundaries.sort() + y_to_fft=self.plots[whatplot].vectors[whatset][1][boundaries[0]:boundaries[1]] #y + else: + y_to_fft=self.plots[whatplot].vectors[whatset][1] #y + + fftplot=self.fft_plot(y_to_fft) + fftplot.units=['frequency', 'power'] + plot_graph=self.list_of_events['plot_graph'] + wx.PostEvent(self.frame,plot_graph(plots=[fftplot])) diff --git a/hooke/plugin/procplots.py b/hooke/plugin/procplots.py deleted file mode 100644 index 3868a83..0000000 --- a/hooke/plugin/procplots.py +++ /dev/null @@ -1,302 +0,0 @@ -# Copyright (C) 2008-2010 Alberto Gomez-Casado -# Massimo Sandal -# 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 -# . - -"""Processed plots plugin for force curves. -""" - -from ..libhooke import WX_GOOD -import wxversion -wxversion.select(WX_GOOD) - -import wx -import numpy as np -import scipy as sp -import scipy.signal -import copy - -from .. import curve as lhc - - -class procplotsCommands(object): - - def _plug_init(self): - pass - - def do_derivplot(self,args): - ''' - DERIVPLOT - (procplots.py plugin) - Plots the derivate (actually, the discrete differentiation) of the current force curve - --------- - Syntax: derivplot - ''' - dplot=self.derivplot_curves() - plot_graph=self.list_of_events['plot_graph'] - wx.PostEvent(self.frame,plot_graph(plots=[dplot])) - - def derivplot_curves(self): - ''' - do_derivplot helper function - - create derivate plot curves for force curves. - ''' - dplot=lhc.PlotObject() - dplot.vectors=[] - - for vector in self.plots[0].vectors: - dplot.vectors.append([]) - dplot.vectors[-1].append(vector[0][:-1]) - dplot.vectors[-1].append(np.diff(vector[1])) - - dplot.destination=1 - dplot.units=self.plots[0].units - - return dplot - - def do_subtplot(self, args): - ''' - SUBTPLOT - (procplots.py plugin) - Plots the difference between ret and ext current curve - ------- - Syntax: subtplot - ''' - #FIXME: sub_filter and sub_order must be args - - if len(self.plots[0].vectors) != 2: - print 'This command only works on a curve with two different plots.' - pass - - outplot=self.subtract_curves(sub_order=1) - - plot_graph=self.list_of_events['plot_graph'] - wx.PostEvent(self.frame,plot_graph(plots=[outplot])) - - def subtract_curves(self, sub_order): - ''' - subtracts the extension from the retraction - ''' - xext=self.plots[0].vectors[0][0] - yext=self.plots[0].vectors[0][1] - xret=self.plots[0].vectors[1][0] - yret=self.plots[0].vectors[1][1] - - #we want the same number of points - maxpoints_tot=min(len(xext),len(xret)) - xext=xext[0:maxpoints_tot] - yext=yext[0:maxpoints_tot] - xret=xret[0:maxpoints_tot] - yret=yret[0:maxpoints_tot] - - if sub_order: - ydiff=[yretval-yextval for yretval,yextval in zip(yret,yext)] - else: #reverse subtraction (not sure it's useful, but...) - ydiff=[yextval-yretval for yextval,yretval in zip(yext,yret)] - - outplot=copy.deepcopy(self.plots[0]) - outplot.vectors[0][0], outplot.vectors[1][0] = xext,xret #FIXME: if I use xret, it is not correct! - outplot.vectors[1][1]=ydiff - outplot.vectors[0][1]=[0 for item in outplot.vectors[1][0]] - - return outplot - - -#-----PLOT MANIPULATORS - def plotmanip_median(self, plot, current, customvalue=None): - ''' - does the median of the y values of a plot - ''' - if customvalue: - median_filter=customvalue - else: - median_filter=self.config['medfilt'] - - if median_filter==0: - return plot - - if float(median_filter)/2 == int(median_filter)/2: - median_filter+=1 - - nplots=len(plot.vectors) - c=0 - while cstartvalue: - cutindex=index - else: - break - - plot.vectors[0][0]=plot.vectors[0][0][:cutindex] - plot.vectors[0][1]=plot.vectors[0][1][:cutindex] - - return plot - ''' - - - -#FFT--------------------------- - def fft_plot(self, vector): - ''' - calculates the fast Fourier transform for the selected vector in the plot - ''' - fftplot=lhc.PlotObject() - fftplot.vectors=[[]] - - fftlen=len(vector)/2 #need just 1/2 of length - fftplot.vectors[-1].append(np.arange(1,fftlen).tolist()) - - try: - fftplot.vectors[-1].append(abs(np.fft(vector)[1:fftlen]).tolist()) - except TypeError: #we take care of newer NumPy (1.0.x) - fftplot.vectors[-1].append(abs(np.fft.fft(vector)[1:fftlen]).tolist()) - - - fftplot.destination=1 - - - return fftplot - - - def do_fft(self,args): - ''' - FFT - (procplots.py plugin) - Plots the fast Fourier transform of the selected plot - --- - Syntax: fft [top,bottom] [select] [0,1...] - - By default, fft performs the Fourier transform on all the 0-th data set on the - top plot. - - [top,bottom]: which plot is the data set to fft (default: top) - [select]: you pick up two points on the plot and fft only the segment between - [0,1,...]: which data set on the selected plot you want to fft (default: 0) - ''' - - #args parsing - #whatplot = plot to fft - #whatset = set to fft in the plot - select=('select' in args) - if 'top' in args: - whatplot=0 - elif 'bottom' in args: - whatplot=1 - else: - whatplot=0 - whatset=0 - for arg in args: - try: - whatset=int(arg) - except ValueError: - pass - - if select: - points=self._measure_N_points(N=2, whatset=whatset) - boundaries=[points[0].index, points[1].index] - boundaries.sort() - y_to_fft=self.plots[whatplot].vectors[whatset][1][boundaries[0]:boundaries[1]] #y - else: - y_to_fft=self.plots[whatplot].vectors[whatset][1] #y - - fftplot=self.fft_plot(y_to_fft) - fftplot.units=['frequency', 'power'] - plot_graph=self.list_of_events['plot_graph'] - wx.PostEvent(self.frame,plot_graph(plots=[fftplot]))