From 058185db028d858a62e498dbeb789a3955c3d7d4 Mon Sep 17 00:00:00 2001 From: illysam Date: Thu, 25 Feb 2010 14:32:43 +0000 Subject: [PATCH] Hooke(GUI) hooke.py - added GetPlotmanipulator() - changed _delta() to return a delta class and not update the plot - added multiplier support to UpdatePlot(), the user can now choose to display the scales in pm/nm for x and pN/nN for y, if necessary, more multipliers can be added easily - added decimals support to UpdatePlot(), the user can now choose how many decimals to display - added legend support to UpdatePlot(), the user can now choose to display a legend hooke.ini - added plot plugin (handles global options for plot: multiplier, decimals, legend) jpk.py - added copyright information prettyformat.py - renamed variables to a more pythonic style - added whitespace stripping option to prettyformat() - added get_multiplier() - added get_exponent() - updated examples autopeak.py - added copyright information fit.py - removed specific import of libhooke.coth - replaced whatset=1 by whatset=lh.RETRACTION flatfilts.py - added copyright information - added apply_plotmanipulators option (all, none, flatten) to do_convfilt() generalvclamp.ini/generalvclamp.py - added options: decimals, multiplier, show_in_legend to [distance] and [force] - added options: decimals, multiplier, show_in_legend to [distance] and [force] - added options: baseline_color, baseline_show, baseline_show_in_legend, baseline_size, decimals, maximum_color, maximum_show, maximum_show_in_legend, maximum_size, maximumrange_color, maximumrange_show, maximumrange_show_in_legend, maximumrange_size and multiplier to [forcebase] - added options: decimals, point_show_in_legend, slope_show_in_legend to [slope] - added copyright information - added prettyformat support to do_distance(), do_force(), do_forcebase(), do_slope() - changed whatset=1 to whatset=lh.RETRACTION in linefit_between() playlist.ini - corrected folder location and default playlist file plot.ini/plot.py - added plot.ini - modified plot.py to simply update the current plot (usually after changes are made to plot.ini) procplots.py - changed whatset=1 to whatset=lh.RETRACTION in do_fft() results.ini - changed [fit_function] to [result_type] - added result type 'multidistance' --- config/hooke.ini | 1 + drivers/jpk.py | 2 +- hooke.py | 99 ++++++++------- lib/prettyformat.py | 149 ++++++++++++---------- plugins/autopeak.py | 10 +- plugins/fit.py | 20 ++- plugins/flatfilts.py | 11 +- plugins/generalvclamp.ini | 153 ++++++++++++++++++++--- plugins/generalvclamp.py | 253 ++++++++++++++++++++++++++++---------- plugins/playlist.ini | 4 +- plugins/plot.ini | 34 ++++- plugins/plot.py | 18 +-- plugins/procplots.py | 2 +- plugins/results.ini | 4 +- 14 files changed, 522 insertions(+), 238 deletions(-) diff --git a/config/hooke.ini b/config/hooke.ini index 6f96553..4c0871c 100644 --- a/config/hooke.ini +++ b/config/hooke.ini @@ -46,6 +46,7 @@ flatfilts = True generalvclamp = True multidistance = True playlist = True +plot = True procplots = True results = True diff --git a/drivers/jpk.py b/drivers/jpk.py index 90aa5c8..e7768e2 100644 --- a/drivers/jpk.py +++ b/drivers/jpk.py @@ -5,7 +5,7 @@ jpk.py Driver for jpk files. -Copyright ??? by Massimo Sandal? +Copyright Copyright 2008 by Massimo Sandal (University of Bologna, Italy) with modifications by Dr. Rolf Schmidt (Concordia University, Canada) This program is released under the GNU General Public License version 2. diff --git a/hooke.py b/hooke.py index 7c7a311..8c2167b 100644 --- a/hooke.py +++ b/hooke.py @@ -3,14 +3,14 @@ ''' HOOKE - A force spectroscopy review & analysis tool -Copyright 2008 by Massimo Sandal (University of Bologna, Italy). -Copyright 2010 by Rolf Schmidt (Concordia University, Canada). +Copyright 2008 by Massimo Sandal (University of Bologna, Italy) +Copyright 2010 by Rolf Schmidt (Concordia University, Canada) This program is released under the GNU General Public License version 2. ''' -import wxversion import lib.libhooke as lh +import wxversion wxversion.select(lh.WX_GOOD) from configobj import ConfigObj @@ -29,6 +29,7 @@ from numpy import __version__ as numpy_version from scipy import __version__ as scipy_version from sys import version as python_version from wx import __version__ as wx_version +from matplotlib.ticker import FuncFormatter try: from agw import cubecolourdialog as CCD @@ -39,8 +40,10 @@ except ImportError: # if it's not there locally, try the wxPython lib. lh.hookeDir = os.path.abspath(os.path.dirname(__file__)) from config.config import config import drivers +import lib.delta import lib.playlist import lib.plotmanipulator +import lib.prettyformat import panels.commands import panels.perspectives import panels.playlist @@ -717,6 +720,15 @@ class HookeFrame(wx.Frame): return config[section][key]['value'] return None + def GetPlotmanipulator(self, name): + ''' + Returns a plot manipulator function from its name + ''' + for plotmanipulator in self.plotmanipulators: + if plotmanipulator.name == name: + return plotmanipulator + return None + def GetPerspectiveMenuItem(self, name): if self._perspectives.has_key(name): perspectives_list = [key for key, value in self._perspectives.iteritems()] @@ -1071,50 +1083,24 @@ class HookeFrame(wx.Frame): point.find_graph_coords(xvector, yvector) return point - def _delta(self, message='Click 2 points', plugin=None): + def _delta(self, message='Click 2 points', whatset=lh.RETRACTION): ''' calculates the difference between two clicked points ''' - if plugin is None: - color = 'black' - show_points = True - size = 20 - whatset = lh.RETRACTION - else: - color = self.GetColorFromConfig(plugin.name, plugin.section, plugin.prefix + 'color') - show_points = self.GetBoolFromConfig(plugin.name, plugin.section, plugin.prefix + 'show_points') - size = self.GetIntFromConfig(plugin.name, plugin.section, plugin.prefix + 'size') - whatset_str = self.GetStringFromConfig(plugin.name, plugin.section, plugin.prefix + 'whatset') - if whatset_str == 'extension': - whatset = lh.EXTENSION - if whatset_str == 'retraction': - whatset = lh.RETRACTION - clicked_points = self._measure_N_points(N=2, message=message, whatset=whatset) - dx = abs(clicked_points[0].graph_coords[0] - clicked_points[1].graph_coords[0]) - dy = abs(clicked_points[0].graph_coords[1] - clicked_points[1].graph_coords[1]) plot = self.GetDisplayedPlotCorrected() - curve = plot.curves[whatset] - unitx = curve.units.x - unity = curve.units.y - - #TODO: move this to clicked_points? - if show_points: - for point in clicked_points: - points = copy.deepcopy(curve) - points.x = point.graph_coords[0] - points.y = point.graph_coords[1] - points.color = color - points.size = size - points.style = 'scatter' - plot.curves.append(points) + delta = lib.delta.Delta() + delta.point1.x = clicked_points[0].graph_coords[0] + delta.point1.y = clicked_points[0].graph_coords[1] + delta.point2.x = clicked_points[1].graph_coords[0] + delta.point2.y = clicked_points[1].graph_coords[1] + delta.units.x = curve.units.x + delta.units.y = curve.units.y - self.UpdatePlot(plot) - - return dx, unitx, dy, unity + return delta def _measure_N_points(self, N, message='', whatset=lh.RETRACTION): ''' @@ -1241,13 +1227,30 @@ class HookeFrame(wx.Frame): if curve.visible and curve.x and curve.y: destination = (curve.destination.column - 1) * number_of_rows + curve.destination.row - 1 axes_list[destination].set_title(curve.title) - axes_list[destination].set_xlabel(curve.units.x) - axes_list[destination].set_ylabel(curve.units.y) + axes_list[destination].set_xlabel(multiplier_x + curve.units.x) + axes_list[destination].set_ylabel(multiplier_y + curve.units.y) if curve.style == 'plot': axes_list[destination].plot(curve.x, curve.y, color=curve.color, label=curve.label, lw=curve.linewidth, zorder=1) if curve.style == 'scatter': axes_list[destination].scatter(curve.x, curve.y, color=curve.color, label=curve.label, s=curve.size, zorder=2) + def get_format_x(x, pos): + 'The two args are the value and tick position' + multiplier = lib.prettyformat.get_exponent(multiplier_x) + decimals_str = '%.' + str(decimals_x) + 'f' + return decimals_str % (x/(10 ** multiplier)) + + def get_format_y(x, pos): + 'The two args are the value and tick position' + multiplier = lib.prettyformat.get_exponent(multiplier_y) + decimals_str = '%.' + str(decimals_y) + 'f' + return decimals_str % (x/(10 ** multiplier)) + + decimals_x = self.GetIntFromConfig('plot', 'x_decimals') + decimals_y = self.GetIntFromConfig('plot', 'y_decimals') + multiplier_x = self.GetStringFromConfig('plot', 'x_multiplier') + multiplier_y = self.GetStringFromConfig('plot', 'y_multiplier') + if plot is None: active_file = self.GetActiveFile() if not active_file.driver: @@ -1276,6 +1279,12 @@ class HookeFrame(wx.Frame): for index in range(number_of_rows * number_of_columns): axes_list.append(figure.add_subplot(number_of_rows, number_of_columns, index + 1)) + for axes in axes_list: + formatter_x = FuncFormatter(get_format_x) + formatter_y = FuncFormatter(get_format_y) + axes.xaxis.set_major_formatter(formatter_x) + axes.yaxis.set_major_formatter(formatter_y) + for curve in self.displayed_plot.curves: add_to_plot(curve) @@ -1292,13 +1301,11 @@ class HookeFrame(wx.Frame): else: self.panelResults.ClearResults() - figure.canvas.draw() - + legend = self.GetBoolFromConfig('plot', 'legend') for axes in axes_list: - #TODO: add legend as global option or per graph option - #axes.legend() - axes.figure.canvas.draw() - + if legend: + axes.legend() + figure.canvas.draw() if __name__ == '__main__': diff --git a/lib/prettyformat.py b/lib/prettyformat.py index 7297e66..bbcbcf0 100644 --- a/lib/prettyformat.py +++ b/lib/prettyformat.py @@ -9,6 +9,11 @@ Version 1.0.1 History 2009 07 16: added negative number support added decimal-formatted output +2010 02 25: renamed variables to a more pythonic style + added whitespace stripping option to prettyformat() + added get_multiplier() + added get_exponent() + updated examples Copyright 2009 by Dr. Rolf Schmidt (Concordia University, Canada) @@ -18,40 +23,74 @@ This program is released under the GNU General Public License version 2. import math from numpy import isnan -def pretty_format(fValue, sUnit='', iDecimals=-1, iMultiplier=1, bLeadingSpaces=False): - if fValue == 0: +def pretty_format(value, unit='', decimals=-1, multiplier=0, leading_spaces=False): + if value == 0: return '0' - if isnan(fValue): + if isnan(value): return 'NaN' - iLeadingSpaces = 0 - if bLeadingSpaces: - iLeadingSpaces = 5 - if iMultiplier == 1: - iMultiplier=get_multiplier(fValue) - sUnitString = '' - if sUnit != '': - sUnitString = ' ' + get_prefix(iMultiplier) + sUnit - if iDecimals >= 0: - formatString = '% ' + repr(iLeadingSpaces + iDecimals) + '.' + repr(iDecimals) + 'f' - return formatString % (fValue / iMultiplier) + sUnitString + output_str = '' + leading_spaces_int = 0 + if leading_spaces: + leading_spaces_int = 5 + if multiplier == 0: + multiplier=get_multiplier(value) + unit_str = '' + if unit != '': + unit_str = ' ' + get_prefix(multiplier) + unit + if decimals >= 0: + format_str = '% ' + repr(leading_spaces_int + decimals) + '.' + repr(decimals) + 'f' + output_str = format_str % (value / multiplier) + unit_str else: - return str(fValue / iMultiplier) + sUnitString - return str(fValue / iMultiplier) + ' ' + get_prefix(fValue / iMultiplier) + sUnit + output_str = str(value / multiplier) + unit_str -def get_multiplier(fValue): - return pow(10, get_power(fValue)) + if decimals < 0: + output_str = str(value / multiplier) + ' ' + get_prefix(value / multiplier) + unit -def get_power(fValue): - if fValue != 0 and not isnan(fValue): - #get the log10 from fValue (make sure the value is not negative) - dHelp = math.floor(math.log10(math.fabs(fValue))) + if leading_spaces_int == 0: + output_str = output_str.lstrip() + + return output_str + +def get_multiplier(value): + return pow(10, get_power(value)) + +def get_power(value): + if value != 0 and not isnan(value): + #get the log10 from value (make sure the value is not negative) + value_temp = math.floor(math.log10(math.fabs(value))) #reduce the log10 to a multiple of 3 and return it - return dHelp-(dHelp % 3) + return value_temp - (value_temp % 3) else: return 0 -def get_prefix(fValue): +def get_exponent(prefix): + #set up a dictionary to find the exponent + exponent = { + 'Y': 24, + 'Z': 21, + 'E': 18, + 'P': 15, + 'T': 12, + 'G': 9, + 'M': 6, + 'k': 3, + '': 0, + 'm': -3, + u'\u00B5': -6, + 'n': -9, + 'p': -12, + 'f': -15, + 'a': -18, + 'z': -21, + 'y': -24, + } + if exponent.has_key(prefix): + return exponent[prefix] + else: + return 1 + +def get_prefix(value): #set up a dictionary to find the prefix prefix = { 24: lambda: 'Y', @@ -72,25 +111,25 @@ def get_prefix(fValue): -21: lambda: 'z', -24: lambda: 'y', } - if fValue != 0 and not isnan(fValue): - #get the log10 from fValue - dHelp = math.floor(math.log10(math.fabs(fValue))) + if value != 0 and not isnan(value): + #get the log10 from value + value_temp = math.floor(math.log10(math.fabs(value))) else: - dHelp = 0 + value_temp = 0 #reduce the log10 to a multiple of 3 and create the return string - return prefix.get(dHelp - (dHelp % 3))() + return prefix.get(value_temp - (value_temp % 3))() ''' -dTestValue=-2.4115665714484597e-008 -print 'Value: '+str(dTestValue)+')' +test_value=-2.4115665714484597e-008 +print 'Value: '+str(test_value)+')' print 'pretty_format example (value, unit)' -print pretty_format(dTestValue, 'N') +print pretty_format(test_value, 'N') print'-----------------------' print 'pretty_format example (value, unit, decimals)' -print pretty_format(dTestValue, 'N', 3) +print pretty_format(test_value, 'N', 3) print'-----------------------' print 'pretty_format example (value, unit, decimals, multiplier)' -print pretty_format(dTestValue, 'N', 5, 0.000001) +print pretty_format(test_value, 'N', 5, 0.000001) print'-----------------------' print 'pretty_format example (value, unit, decimals, multiplier, leading spaces)' print pretty_format(0.0166276297705, 'N', 3, 0.001, True) @@ -98,47 +137,21 @@ print pretty_format(0.00750520813323, 'N', 3, 0.001, True) print pretty_format(0.0136453282825, 'N', 3, 0.001, True) ''' ''' -#example use autoFormatValue -dTestValue=0.00000000567 -print 'autoFormatValue example ('+str(dTestValue)+')' -print autoFormatValue(dTestValue, 'N') -#outputs 5.67 nN -''' -''' -#example use of decimalFormatValue(fValue, iDecimals, sUnit): -dTestValue=-2.4115665714484597e-008 -iDecimals=3 -print 'decimalFormatValue example ('+str(dTestValue)+')' -print decimalFormatValue(dTestValue, iDecimals, 'N') -#outputs -24.116 nN -#change iDecimals to see the effect -''' -''' -#example use formatValue -dTestValue=0.000000000567 -print 'formatValue example ('+str(dTestValue)+')' -#find the (common) multiplier -iMultiplier=get_multiplier(dTestValue) -#use the multiplier and a unit to format the value -print formatValue(dTestValue, iMultiplier, 'N') -#outputs 567.0 pN -''' -''' #to output a scale: #choose any value on the axis and find the multiplier and prefix for it #use those to format the rest of the scale #as values can span several orders of magnitude, you have to decide what units to use #tuple of values: -scaleValues=0.000000000985, 0.000000001000, 0.000000001015 +scale_values=0.000000000985, 0.000000001000, 0.000000001015 #use this element (change to 1 or 2 to see the effect on the scale and label) -iIndex=0 -#get the multiplier from the value at iIndex -iMultiplier=get_multiplier(scaleValues[iIndex]) +index=0 +#get the multiplier from the value at index +multiplier=get_multiplier(scale_values[index]) print '\nScale example' -iDecimals=3 +decimals=3 #print the scale -for aValue in scaleValues: print decimalFormat(aValue/iMultiplier, iDecimals), -#print the scale label using the value at iIndex -print '\n'+get_prefix(scaleValues[iIndex])+'N' +for aValue in scale_values: print decimalFormat(aValue/multiplier, decimals), +#print the scale label using the value at index +print '\n'+get_prefix(scale_values[index])+'N' ''' \ No newline at end of file diff --git a/plugins/autopeak.py b/plugins/autopeak.py index 2951ca4..67a85af 100644 --- a/plugins/autopeak.py +++ b/plugins/autopeak.py @@ -5,7 +5,7 @@ autopeak.py Automatic peak detection and analysis. -Copyright ???? by ? +Copyright 2008 Massimo Sandal, Fabrizio Benedetti, Marco Brucale with modifications by Dr. Rolf Schmidt (Concordia University, Canada) This program is released under the GNU General Public License version 2. @@ -70,10 +70,6 @@ class autopeakCommands: Configuration ------------- - apply_plotmanipulators: - - all (all selected plotmanipulators will be applied) - - flatten (only the flatten plotmanipulator will be applied) - - none (no plotmanipulators will be applied) fit_function: type of function to use for elasticity. If "wlc" worm-like chain is used, if "fjc" freely jointed chain is used @@ -119,7 +115,7 @@ class autopeakCommands: if not usepl: pl_value = None else: - pl_value = persistence_length / 10**9 + pl_value = persistence_length / 10 ** 9 usepoints = self.GetBoolFromConfig('autopeak', 'usepoints') whatset_str = self.GetStringFromConfig('autopeak', 'whatset') if whatset_str == 'extension': @@ -156,7 +152,7 @@ class autopeakCommands: plot = self.GetDisplayedPlotCorrected() filename = self.GetActiveFile().name - TODO: add convfilt option? + #TODO: add convfilt option? #--Using points instead of nm interval if not usepoints: fit_points = None diff --git a/plugins/fit.py b/plugins/fit.py index acba74c..dda328f 100644 --- a/plugins/fit.py +++ b/plugins/fit.py @@ -24,8 +24,6 @@ import numpy as np import scipy.stats import scipy.odr -from lib.libhooke import coth - class fitCommands(object): ''' Do not use any of the following commands directly: @@ -242,7 +240,7 @@ class fitCommands(object): therm=Kb*T #x=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd)) - x=(1/lambd)*(coth(f*(1/pii)/therm) - (therm*pii)/f) + x=(1/lambd)*(lh.coth(f*(1/pii)/therm) - (therm*pii)/f) return x def x_fjc_plfix(params,f,pl_value=pl_value,T=T): @@ -254,7 +252,7 @@ class fitCommands(object): Kb=(1.38065e-23) therm=Kb*T #y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd)) - x=(1/lambd)*(coth(f*(1/pii)/therm) - (therm*pii)/f) + x=(1/lambd)*(lh.coth(f*(1/pii)/therm) - (therm*pii)/f) return x #make the ODR fit @@ -293,7 +291,7 @@ class fitCommands(object): Kb = (1.38065e-23) #Boltzmann constant therm = Kb * T #so we have thermal energy #return ( (therm*pii/4.0) * (((1-(x*lambd))**-2.0) - 1 + (4.0*x*lambd)) ) - return (1 / lambd) * (coth(y * (1 / pii) / therm) - (therm * pii) / y) + return (1 / lambd) * (lh.coth(y * (1 / pii) / therm) - (therm * pii) / y) #STEP 3: plotting the fit @@ -404,7 +402,7 @@ class fitCommands(object): #x=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd)) - x=(1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (coth(f*(1/pii)/therm) - (therm*pii)/f) + x=(1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (lh.coth(f*(1/pii)/therm) - (therm*pii)/f) return x def x_fjcPEG_plfix(params,f,pl_value=pl_value,T=T): @@ -416,7 +414,7 @@ class fitCommands(object): Kb=(1.38065e-23) therm=Kb*T #y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd)) - x=(1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (coth(f*(1/pii)/therm) - (therm*pii)/f) + x=(1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (lh.coth(f*(1/pii)/therm) - (therm*pii)/f) return x #make the ODR fit @@ -455,7 +453,7 @@ class fitCommands(object): Kb = (1.38065e-23) #Boltzmann constant therm = Kb * T #so we have thermal energy #return ( (therm*pii/4.0) * (((1-(x*lambd))**-2.0) - 1 + (4.0*x*lambd)) ) - return (1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (coth(y*(1/pii)/therm) - (therm*pii)/y) + return (1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (lh.coth(y*(1/pii)/therm) - (therm*pii)/y) #STEP 3: plotting the fit @@ -594,7 +592,7 @@ class fitCommands(object): #handle contact point arguments correctly if 'reclick' in args.split(): print 'Click contact point' - contact_point=self._measure_N_points(N=1, whatset=1)[0] + contact_point=self._measure_N_points(N=1, whatset=lh.RETRACTION)[0] contact_point_index=contact_point.index self.wlccontact_point=contact_point self.wlccontact_index=contact_point.index @@ -602,7 +600,7 @@ class fitCommands(object): elif 'noauto' in args.split(): if self.wlccontact_index is None or self.wlccurrent != self.current.path: print 'Click contact point' - contact_point=self._measure_N_points(N=1, whatset=1)[0] + contact_point=self._measure_N_points(N=1, whatset=lh.RETRACTION)[0] contact_point_index=contact_point.index self.wlccontact_point=contact_point self.wlccontact_index=contact_point.index @@ -618,7 +616,7 @@ class fitCommands(object): contact_point.is_marker=True print 'Click edges of chunk' - points=self._measure_N_points(N=2, whatset=1) + points=self._measure_N_points(N=2, whatset=lh.RETRACTION) points=[contact_point]+points try: if self.config['fit_function']=='wlc': diff --git a/plugins/flatfilts.py b/plugins/flatfilts.py index d1814e1..9b540fd 100644 --- a/plugins/flatfilts.py +++ b/plugins/flatfilts.py @@ -8,7 +8,7 @@ Force spectroscopy files filtering of flat files. Plugin dependencies: procplots.py (plot processing plugin) -Copyright ???? by ? +Copyright 2008 Massimo Sandal, Fabrizio Benedetti with modifications by Dr. Rolf Schmidt (Concordia University, Canada) This program is released under the GNU General Public License version 2. @@ -254,7 +254,14 @@ class flatfiltsCommands: file_index += 1 try: current_file.identify(self.drivers) - plot = self.ApplyPlotmanipulators(current_file.plot, current_file) + if apply_plotmanipulators == 'all': + plot = self.ApplyPlotmanipulators(current_file.plot, current_file) + if apply_plotmanipulators == 'flatten': + plotmanipulator = self.GetPlotmanipulator('flatten') + plot = plotmanipulator.method(current_file.plot, current_file) + if apply_plotmanipulators == 'none': + plot = copy.deepcopy(current_file.plot) + peak_location, peak_size = self.has_peaks(plot) number_of_peaks = len(peak_location) if number_of_peaks != 1: diff --git a/plugins/generalvclamp.ini b/plugins/generalvclamp.ini index 5968d03..f019ef5 100644 --- a/plugins/generalvclamp.ini +++ b/plugins/generalvclamp.ini @@ -2,19 +2,37 @@ [[color]] default = black type = color - value = "(128,0,128)" + value = "(0,0,0)" + + [[decimals]] + default = 2 + maximum = 10 + minimum = 0 + type = integer + value = 2 + + [[multiplier]] + default = n + elements = n, p + type = enum + value = n [[show]] default = True type = boolean value = True + [[show_in_legend]] + default = True + type = boolean + value = True + [[size]] default = 20 maximum = 10000 minimum = 1 type = integer - value = 100 + value = 20 [[whatset]] default = retraction @@ -26,19 +44,37 @@ [[color]] default = black type = color - value = "(0,255,0)" + value = "(0,0,0)" + + [[decimals]] + default = 2 + maximum = 10 + minimum = 0 + type = integer + value = 2 + + [[multiplier]] + default = p + elements = n, p + type = enum + value = p [[show]] default = True type = boolean - value = False + value = True + + [[show_in_legend]] + default = True + type = boolean + value = True [[size]] default = 20 maximum = 10000 minimum = 1 type = integer - value = 100 + value = 20 [[whatset]] default = retraction @@ -51,32 +87,94 @@ type = none value = 1 - [[color]] + [[baseline_color]] default = black type = color - value = "(255,0,128)" + value = "(0,0,0)" + + [[baseline_show]] + default = True + type = boolean + value = True + + [[baseline_show_in_legend]] + default = True + type = boolean + value = True + + [[baseline_size]] + default = 20 + maximum = 10000 + minimum = 1 + type = integer + value = 20 + + [[decimals]] + default = 2 + maximum = 10 + minimum = 0 + type = integer + value = 2 [[max]] default = False type = boolean value = False - [[rebase]] - default = False + [[maximum_color]] + default = black + type = color + value = "(0,0,0)" + + [[maximum_show]] + default = True type = boolean - value = False + value = True - [[show]] + [[maximum_show_in_legend]] default = True type = boolean value = True - [[size]] + [[maximum_size]] + default = 20 + maximum = 10000 + minimum = 1 + type = integer + value = 20 + + [[maximumrange_color]] + default = black + type = color + value = "(0,0,0)" + + [[maximumrange_show]] + default = True + type = boolean + value = True + + [[maximumrange_show_in_legend]] + default = True + type = boolean + value = True + + [[maximumrange_size]] default = 20 maximum = 10000 minimum = 1 type = integer - value = 50 + value = 20 + + [[multiplier]] + default = p + elements = n, p + type = enum + value = p + + [[rebase]] + default = False + type = boolean + value = False [[whatset]] default = retraction @@ -102,50 +200,67 @@ maximum = 100 minimum = 0 type = float - value = 2 + value = 1 [slope] + [[decimals]] + default = 5 + maximum = 10 + minimum = 0 + type = integer + value = 5 + [[fitspan]] default = 0 maximum = 10000 minimum = 0 type = integer - value = 60 + value = 0 [[point_color]] default = black type = color - value = "(0,255,0)" + value = "(0,0,0)" [[point_show]] default = False type = boolean value = False + [[point_show_in_legend]] + default = True + type = boolean + value = False + [[point_size]] default = 20 maximum = 10000 minimum = 1 type = integer - value = 10 + value = 20 [[slope_color]] default = black type = color - value = "(255,0,128)" + value = "(0,0,0)" [[slope_linewidth]] default = 1 maximum = 10000 minimum = 1 type = integer - value = 2 + value = 1 [[slope_show]] default = True type = boolean value = True + [[slope_show_in_legend]] + default = True + type = boolean + value = True + [[whatset]] default = retraction elements = extension, retraction diff --git a/plugins/generalvclamp.py b/plugins/generalvclamp.py index 9425880..749b9ef 100644 --- a/plugins/generalvclamp.py +++ b/plugins/generalvclamp.py @@ -5,7 +5,7 @@ generalvclamp.py Plugin regarding general velocity clamp measurements -Copyright ???? by ? +Copyright 2008 by Massimo Sandal (University of Bologna, Italy) with modifications by Dr. Rolf Schmidt (Concordia University, Canada) This program is released under the GNU General Public License version 2. @@ -15,7 +15,6 @@ import lib.libhooke as lh import wxversion wxversion.select(lh.WX_GOOD) -from copy import deepcopy import numpy as np import scipy as sp @@ -23,6 +22,7 @@ import warnings warnings.simplefilter('ignore', np.RankWarning) import lib.curve +import lib.prettyformat class generalvclampCommands: @@ -43,17 +43,50 @@ class generalvclampCommands: ----------------- Syntax: distance ''' + color = self.GetColorFromConfig('generalvclamp', 'distance', 'color') + decimals = self.GetIntFromConfig('generalvclamp', 'distance', 'decimals') + multiplier_str = self.GetStringFromConfig('generalvclamp', 'distance', 'multiplier') + multiplier = lib.prettyformat.get_exponent(multiplier_str) + show = self.GetBoolFromConfig('generalvclamp', 'distance', 'show') + show_in_legend = self.GetBoolFromConfig('generalvclamp', 'distance', 'show_in_legend') + size = self.GetIntFromConfig('generalvclamp', 'distance', 'size') + whatset_str = self.GetStringFromConfig('generalvclamp', 'distance', 'whatset') + whatset = 'retraction' + if whatset_str == 'extension': + whatset = lh.EXTENSION + if whatset_str == 'retraction': + whatset = lh.RETRACTION + active_file = self.GetActiveFile() - plot = self.GetActivePlot() if active_file.driver.experiment == 'clamp': self.AppendToOutput('You wanted to use zpiezo perhaps?') return plugin = lib.plugin.Plugin() plugin.name = 'generalvclamp' plugin.section = 'distance' - dx, unitx, dy, unity = self._delta(message='Click 2 points to measure the distance.', plugin=plugin) - #TODO: pretty format - self.AppendToOutput(str(dx * (10 ** 9)) + ' nm') + delta = self._delta(message='Click 2 points to measure the distance.', whatset=whatset) + + plot = self.GetDisplayedPlotCorrected() + if show: + #add the points to the plot + points = lib.curve.Curve() + points.color = color + if show_in_legend: + points.label = 'distance' + else: + points.label = '_nolegend_' + points.size = size + points.style = 'scatter' + points.units.x = delta.units.x + points.units.y = delta.units.y + points.x = [delta.point1.x, delta.point2.x] + points.y = [delta.point1.y, delta.point2.y] + plot.curves.append(points) + + self.UpdatePlot(plot) + + output_str = lib.prettyformat.pretty_format(abs(delta.get_delta_x()), delta.units.x, decimals, 10 ** multiplier) + self.AppendToOutput(''.join(['Distance: ', output_str])) def do_force(self): ''' @@ -63,17 +96,50 @@ class generalvclampCommands: --------------- Syntax: force ''' + color = self.GetColorFromConfig('generalvclamp', 'force', 'color') + decimals = self.GetIntFromConfig('generalvclamp', 'force', 'decimals') + multiplier_str = self.GetStringFromConfig('generalvclamp', 'force', 'multiplier') + multiplier = lib.prettyformat.get_exponent(multiplier_str) + show = self.GetBoolFromConfig('generalvclamp', 'force', 'show') + show_in_legend = self.GetBoolFromConfig('generalvclamp', 'force', 'show_in_legend') + size = self.GetIntFromConfig('generalvclamp', 'force', 'size') + whatset_str = self.GetStringFromConfig('generalvclamp', 'force', 'whatset') + whatset = 'retraction' + if whatset_str == 'extension': + whatset = lh.EXTENSION + if whatset_str == 'retraction': + whatset = lh.RETRACTION + active_file = self.GetActiveFile() - plot = self.GetActivePlot() if active_file.driver.experiment == 'clamp': self.AppendToOutput('This command makes no sense for a force clamp experiment.') return plugin = lib.plugin.Plugin() plugin.name = 'generalvclamp' plugin.section = 'force' - dx, unitx, dy, unity = self._delta(message='Click 2 points to measure the force.', plugin=plugin) - #TODO: pretty format - self.AppendToOutput(str(dy * (10 ** 12)) + ' pN') + delta = self._delta(message='Click 2 points to measure the force.', whatset=whatset) + + plot = self.GetDisplayedPlotCorrected() + if show: + #add the points to the plot + points = lib.curve.Curve() + points.color = color + if show_in_legend: + points.label = 'force' + else: + points.label = '_nolegend_' + points.size = size + points.style = 'scatter' + points.units.x = delta.units.x + points.units.y = delta.units.y + points.x = [delta.point1.x, delta.point2.x] + points.y = [delta.point1.y, delta.point2.y] + plot.curves.append(points) + + self.UpdatePlot(plot) + + output_str = lib.prettyformat.pretty_format(abs(delta.get_delta_y()), delta.units.y, decimals, 10 ** multiplier) + self.AppendToOutput(''.join(['Force: ', output_str])) def do_forcebase(self): ''' @@ -90,11 +156,23 @@ class generalvclampCommands: max: Instead of asking for a point to measure, asks for two points and use the maximum peak in between ''' - color = self.GetColorFromConfig('generalvclamp', 'forcebase', 'color') + baseline_color = self.GetColorFromConfig('generalvclamp', 'forcebase', 'baseline_color') + baseline_show = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'baseline_show') + baseline_show_in_legend = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'baseline_show_in_legend') + baseline_size = self.GetIntFromConfig('generalvclamp', 'forcebase', 'baseline_size') + decimals = self.GetIntFromConfig('generalvclamp', 'forcebase', 'decimals') + maximum_color = self.GetColorFromConfig('generalvclamp', 'forcebase', 'maximum_color') + maximum_show = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'maximum_show') + maximum_show_in_legend = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'maximum_show_in_legend') + maximum_size = self.GetIntFromConfig('generalvclamp', 'forcebase', 'maximum_size') + maximumrange_color = self.GetColorFromConfig('generalvclamp', 'forcebase', 'maximumrange_color') + maximumrange_show = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'maximumrange_show') + maximumrange_show_in_legend = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'maximumrange_show_in_legend') + maximumrange_size = self.GetIntFromConfig('generalvclamp', 'forcebase', 'maximumrange_size') maxpoint = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'max') + multiplier_str = self.GetStringFromConfig('generalvclamp', 'forcebase', 'multiplier') + multiplier = lib.prettyformat.get_exponent(multiplier_str) rebase = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'rebase') - show_points = self.GetBoolFromConfig('generalvclamp', 'forcebase', 'show_points') - size = self.GetIntFromConfig('generalvclamp', 'forcebase', 'size') whatset_str = self.GetStringFromConfig('generalvclamp', 'forcebase', 'whatset') whatset = 'retraction' if whatset_str == 'extension': @@ -104,34 +182,30 @@ class generalvclampCommands: plot = self.GetDisplayedPlotCorrected() - clicked_points = [] - filename = self.GetActiveFile().name if rebase or (self.basecurrent != filename): self.basepoints = self._measure_N_points(N=2, message='Click on 2 points to select the baseline.', whatset=whatset) self.basecurrent = filename - clicked_points = self.basepoints - #TODO: maxpoint does not seem to be picking up the 'real' minimum (at least not with test.hkp/default.000) + #TODO: maxpoint does not seem to be picking up the 'real' maximum (at least not with test.hkp/default.000) + maximumrange_points = [] + maximum_point = [] if maxpoint: - boundpoints = [] - points = self._measure_N_points(N=2, message='Click 2 points to select the range for maximum detection.', whatset=whatset) - boundpoints = [points[0].index, points[1].index] + maximumrange_points = self._measure_N_points(N=2, message='Click 2 points to select the range for maximum detection.', whatset=whatset) + boundpoints = [maximumrange_points[0].index, maximumrange_points[1].index] boundpoints.sort() - clicked_points += points try: vector_x = plot.curves[whatset].x[boundpoints[0]:boundpoints[1]] vector_y = plot.curves[whatset].y[boundpoints[0]:boundpoints[1]] y = min(vector_y) index = vector_y.index(y) - clicked_points += [self._clickize(vector_x, vector_y, index)] + maximum_point = [self._clickize(vector_x, vector_y, index)] except ValueError: self.AppendToOutput('Chosen interval not valid. Try picking it again. Did you pick the same point as begin and end of the interval?') return else: - points = self._measure_N_points(N=1, message='Click on the point to measure.', whatset=whatset) - y = points[0].graph_coords[1] - clicked_points += [points[0]] + maximum_point = self._measure_N_points(N=1, message='Click on the point to measure.', whatset=whatset) + y = maximum_point[0].graph_coords[1] boundaries = [self.basepoints[0].index, self.basepoints[1].index] boundaries.sort() @@ -140,21 +214,62 @@ class generalvclampCommands: avg = np.mean(to_average) forcebase = abs(y - avg) - if show_points: - curve = plot.curves[whatset] - for point in clicked_points: - points = deepcopy(curve) - points.x = point.graph_coords[0] - points.y = point.graph_coords[1] - - points.color = color - points.size = size - points.style = 'scatter' - plot.curves.append(points) + curve = plot.curves[whatset] + if self.basepoints and baseline_show: + #add the baseline points to the plot + baseline = lib.curve.Curve() + baseline.color = baseline_color + if baseline_show_in_legend: + baseline.label = 'baseline' + else: + baseline.label = '_nolegend_' + baseline.size = baseline_size + baseline.style = 'scatter' + baseline.units.x = curve.units.x + baseline.units.y = curve.units.y + for point in self.basepoints: + baseline.x += [point.graph_coords[0]] + baseline.y += [point.graph_coords[1]] + plot.curves.append(baseline) + + if maximumrange_points and maximumrange_show: + #add the range points to the plot + maximumrange = lib.curve.Curve() + maximumrange.color = maximumrange_color + if maximumrange_show_in_legend: + maximumrange.label = 'maximumrange' + else: + maximumrange.label = '_nolegend_' + maximumrange.size = maximumrange_size + maximumrange.style = 'scatter' + maximumrange.units.x = curve.units.x + maximumrange.units.y = curve.units.y + for point in maximumrange_points: + maximumrange.x += [point.graph_coords[0]] + maximumrange.y += [point.graph_coords[1]] + plot.curves.append(maximumrange) + + if maximum_show: + #add the maximum to the plot + maximum = lib.curve.Curve() + maximum.color = maximum_color + if maximum_show_in_legend: + maximum.label = 'maximum' + else: + maximum.label = '_nolegend_' + maximum.size = maximum_size + maximum.style = 'scatter' + maximum.units.x = curve.units.x + maximum.units.y = curve.units.y + maximum.x = [maximum_point[0].graph_coords[0]] + maximum.y = [maximum_point[0].graph_coords[1]] + plot.curves.append(maximum) self.UpdatePlot(plot) - #TODO: pretty format - self.AppendToOutput(str(forcebase * (10 ** 12)) + ' pN') + + unit_str = plot.curves[whatset].units.y + output_str = lib.prettyformat.pretty_format(forcebase, unit_str, decimals, 10 ** multiplier) + self.AppendToOutput(''.join(['Force: ', output_str])) def plotmanip_multiplier(self, plot, current, customvalue=False): ''' @@ -257,14 +372,17 @@ class generalvclampCommands: Copyright 2008 by Marco Brucale, Massimo Sandal ''' + decimals = self.GetIntFromConfig('generalvclamp', 'slope', 'decimals') fitspan = self.GetIntFromConfig('generalvclamp', 'slope', 'fitspan') point_color = self.GetColorFromConfig('generalvclamp', 'slope', 'point_color') point_show = self.GetBoolFromConfig('generalvclamp', 'slope', 'point_show') + point_show_in_legend = self.GetBoolFromConfig('generalvclamp', 'slope', 'point_show_in_legend') point_size = self.GetIntFromConfig('generalvclamp', 'slope', 'point_size') slope_color = self.GetColorFromConfig('generalvclamp', 'slope', 'slope_color') slope_linewidth = self.GetIntFromConfig('generalvclamp', 'slope', 'slope_linewidth') slope_show = self.GetBoolFromConfig('generalvclamp', 'slope', 'slope_show') - whatset_str = self.GetStringFromConfig('generalvclamp', 'forcebase', 'whatset') + slope_show_in_legend = self.GetBoolFromConfig('generalvclamp', 'slope', 'slope_show_in_legend') + whatset_str = self.GetStringFromConfig('generalvclamp', 'slope', 'whatset') whatset = 'retraction' if whatset_str == 'extension': whatset = lh.EXTENSION @@ -275,30 +393,24 @@ class generalvclampCommands: #TODO: add an option 'mode' with options 'chunk' and 'point' if fitspan == 0: # Gets the Xs of two clicked points as indexes on the curve curve vector - clickedpoints = [] + clicked_points = [] points = self._measure_N_points(N=2, message='Click 2 points to select the chunk.', whatset=whatset) - clickedpoints = [points[0].index, points[1].index] - clickedpoints.sort() + clicked_points = [points[0].index, points[1].index] + clicked_points.sort() else: - clickedpoints = [] + clicked_points = [] points = self._measure_N_points(N=1, message='Click on the leftmost point of the chunk (i.e.usually the peak).', whatset=whatset) - clickedpoints = [points[0].index - fitspan, points[0].index] + clicked_points = [points[0].index - fitspan, points[0].index] # Calls the function linefit_between parameters = [0, 0, [], []] try: - parameters = self.linefit_between(clickedpoints[0], clickedpoints[1], whatset=whatset) + parameters = self.linefit_between(clicked_points[0], clicked_points[1], whatset=whatset) except: self.AppendToOutput('Cannot fit. Did you click the same point twice?') return - # Outputs the relevant slope parameter - #TODO: pretty format with units - self.AppendToOutput(''.join(['Slope: ', str(parameters[0])])) - - #TODO: add option to keep previous slope plot = self.GetDisplayedPlotCorrected() - # Makes a vector with the fitted parameters and sends it to the GUI xtoplot=parameters[2] ytoplot=[] @@ -312,31 +424,44 @@ class generalvclampCommands: clickvector_x.append(item.graph_coords[0]) clickvector_y.append(item.graph_coords[1]) + if point_show: + #add the clicked point to the plot + point = lib.curve.Curve() + point.color = point_color + if point_show_in_legend: + point.label = 'clicked point' + else: + point.label = '_nolegend_' + point.size = point_size + point.style = 'scatter' + point.x = clickvector_x + point.y = clickvector_y + plot.curves.append(point) + if slope_show: #add the slope to the plot slope = lib.curve.Curve() slope.color = slope_color - slope.label = 'slope' + if slope_show_in_legend: + slope.label = 'slope' + else: + slope.label = '_nolegend_' slope.linewidth = slope_linewidth slope.style = 'plot' + slope.units.x = plot.curves[whatset].units.x + slope.units.y = plot.curves[whatset].units.y slope.x = xtoplot slope.y = ytoplot plot.curves.append(slope) - if point_show: - #add the clicked points to the plot - points = lib.curve.Curve() - points.color = point_color - points.label = 'points' - points.size = point_size - points.style = 'scatter' - points.x = clickvector_x - points.y = clickvector_y - plot.curves.append(points) - self.UpdatePlot(plot) - def linefit_between(self, index1, index2, whatset=1): + # Outputs the relevant slope parameter + unit_str = plot.curves[whatset].units.x + '/' + plot.curves[whatset].units.y + output_str = lib.prettyformat.pretty_format(parameters[0], unit_str, decimals, 1) + self.AppendToOutput(''.join(['Slope: ', output_str])) + + def linefit_between(self, index1, index2, whatset=lh.RETRACTION): ''' Creates two vectors (xtofit, ytofit) slicing out from the curve return trace a portion delimited by the two indeces diff --git a/plugins/playlist.ini b/plugins/playlist.ini index 10de454..82deb82 100644 --- a/plugins/playlist.ini +++ b/plugins/playlist.ini @@ -2,7 +2,7 @@ [[folder]] default = "" type = folder - value = R:\Programming\Python\Gui\data\Ecoil good data set 1 week35_surface251_16.5pNnm + value = C:\Hooke [[filemask]] default = *.* @@ -19,4 +19,4 @@ [[filename]] default = untitled.hkp type = filename - value = R:\Programming\Python\Gui\untitled2.hkp + value = C:\Hooke\playlists\test.hkp diff --git a/plugins/plot.ini b/plugins/plot.ini index d3f5a12..f84bba6 100644 --- a/plugins/plot.ini +++ b/plugins/plot.ini @@ -1 +1,33 @@ - +[plot] + [[legend]] + default = False + type = boolean + value = True + + [[x_decimals]] + default = 2 + maximum = 10 + minimum = 0 + type = integer + value = 1 + + [[x_multiplier]] + default = n + elements = n, p + type = enum + value = n + + [[y_decimals]] + default = 2 + maximum = 10 + minimum = 0 + type = integer + value = 1 + + [[y_multiplier]] + default = n + elements = n, p + type = enum + value = n + + diff --git a/plugins/plot.py b/plugins/plot.py index 37a437c..0e8db7a 100644 --- a/plugins/plot.py +++ b/plugins/plot.py @@ -3,24 +3,14 @@ ''' plot.py -Plot commands for Hooke. +Global settings for plots Copyright 2010 by Dr. Rolf Schmidt (Concordia University, Canada) This program is released under the GNU General Public License version 2. ''' -class plotCommands(object): - ''' - Plot commands to replot the original data with fits (if applicable) - but without secondary plots (unless they are part of the original data) - ''' +class plotCommands: - def _plug_init(self): - pass - - def do_replot(self): - ''' - Replots the current force curve from scratch eliminating any secondary plots. - ''' - self.UpdatePlot() + def do_plot(self): + self.UpdatePlot(); diff --git a/plugins/procplots.py b/plugins/procplots.py index 748c96c..222caed 100644 --- a/plugins/procplots.py +++ b/plugins/procplots.py @@ -261,7 +261,7 @@ class procplotsCommands: whatset = [lh.EXTENSION, lh.RETRACTION] if select: - points = self._measure_N_points(N=2, message='Please select a region by clicking on the start and the end point.', whatset=1) + points = self._measure_N_points(N=2, message='Please select a region by clicking on the start and the end point.', whatset=lh.RETRACTION) boundaries = [points[0].index, points[1].index] boundaries.sort() else: diff --git a/plugins/results.ini b/plugins/results.ini index ef4cea2..5352136 100644 --- a/plugins/results.ini +++ b/plugins/results.ini @@ -1,6 +1,6 @@ [show_results] - [[fit_function]] + [[result_type]] default = wlc - elements = wlc, fjc, fjcPEG + elements = wlc, fjc, fjcPEG, multidistance type = enum value = wlc -- 2.26.2