diff --git a/@MyPeakFinderGui/MyPeakFinderGui.m b/@MyPeakFinderGui/MyPeakFinderGui.m index 5f0ded8..e7ee944 100644 --- a/@MyPeakFinderGui/MyPeakFinderGui.m +++ b/@MyPeakFinderGui/MyPeakFinderGui.m @@ -1,226 +1,244 @@ classdef MyPeakFinderGui < handle properties PeakFinder Gui; axis_handle; end properties (Access=private) peak_color='r'; data_color='b'; peak_handle; end properties (Dependent=true) trace_handle; filename; session_name; base_dir; save_dir; end methods function this=MyPeakFinderGui() this.PeakFinder=MyPeakFinder(); createGui(this); end function delete(this) %Avoids loops set(this.Gui.Window,'CloseRequestFcn',''); %Deletes the figure delete(this.Gui.Window); %Removes the figure handle to prevent memory leaks this.Gui=[]; end function closeFigure(this, ~, ~) delete(this); end function analyzeCallback(this, src, ~) src.BackgroundColor=[1,0,0]; src.String='Analyzing..'; searchPeaks(this.PeakFinder,... 'MinPeakProminence',str2double(this.Gui.PromEdit.String),... 'MinPeakDistance',str2double(this.Gui.SepEdit.String),... 'FindMinima',this.Gui.MinimaCheck.Value); plotPeaks(this); src.BackgroundColor=[0.94,0.94,0.94]; src.String='Analyze'; end function plotPeaks(this) delete(this.peak_handle); this.peak_handle=plot(this.axis_handle,... [this.PeakFinder.Peaks.Location],... [this.PeakFinder.Peaks.Value],... 'Marker','o',... 'LineStyle','none',... 'Color',this.peak_color); end function fitPeakCallback(this,~,~) + %Clean up fit names + fit_names=cellfun(@(x) erase(x,' '), this.Gui.SelFitList.String,... + 'UniformOutput',false); fitAllPeaks(this.PeakFinder,... + 'FitNames',fit_names,... 'base_dir',this.base_dir,... 'session_name',this.session_name,... 'filename',this.filename); end function clickCallback(this,~,~) switch this.Gui.Window.SelectionType case 'normal' %Left click addPeak(this); case 'alt' %Right click axis(this.axis_handle,'tight') case 'extend' %Shift click coords=this.axis_handle.CurrentPoint; removePeak(this, coords(1)); otherwise end end function windowScrollCallback(this, ~, event) coords=this.axis_handle.CurrentPoint; if event.VerticalScrollCount>0 %Zoom out zoomAxis(this,coords(1),0.1) else %Zoom in zoomAxis(this,coords(1),10); end end function removePeak(this, coord) [~,ind]=min(abs([this.PeakFinder.Peaks.Location]-coord)); this.PeakFinder.Peaks(ind)=[]; plotPeaks(this); end function addPeak(this) x_lim=[this.axis_handle.XLim(1),... this.axis_handle.XLim(2)]; if checkPeakExist(this.PeakFinder,x_lim(1),x_lim(2)) opts=struct('WindowStyle','modal','Interpreter','tex'); errordlg(['A peak already exists in the window. ',... 'To add a new peak, zoom such that there is ',... 'no peak in the window'],'Error',opts); return end searchPeaks(this.PeakFinder,... 'ClearPeaks',false,... 'Limits',x_lim,... 'MinPeakProminence',str2double(this.Gui.PromEdit.String),... 'FindMinima',this.Gui.MinimaCheck.Value,... 'NPeaks',1,... 'SortStr','descend'); plotPeaks(this); end function zoomAxis(this,coords,zoom_factor) curr_width=this.axis_handle.XLim(2)-this.axis_handle.XLim(1); new_width=curr_width/zoom_factor; this.axis_handle.XLim=... [coords(1)-new_width/2,coords(1)+new_width/2]; end function clearCallback(this, ~, ~) delete(getLineHandle(this.PeakFinder.Trace,this.axis_handle)); clearData(this.PeakFinder.Trace); cla(this.axis_handle); end function loadTraceCallback(this, src, ~) %Window can find all files [fname,path]=uigetfile('*.*'); if fname==0 warning('No file was selected'); return end src.BackgroundColor=[1,0,0]; src.String='Loading..'; loadTrace(this.PeakFinder,[path,fname]); plotTrace(this.PeakFinder.Trace,this.axis_handle); this.trace_handle.ButtonDownFcn=... @(src, event) clickCallback(this, src, event); exitLoad(this); end function exitLoad(this) this.Gui.LoadTraceButton.BackgroundColor=[0.94,0.94,0.94]; this.Gui.LoadTraceButton.String='Load trace'; end function savePeaksCallback(this,~,~) save(this.PeakFinder,... 'save_dir',this.save_dir,... 'filename',this.filename); end function loadPeaksCallback(this,~,~) [fname,path]=uigetfile('*.*'); if fname==0 warning('No file was selected'); return end loadPeaks(this.PeakFinder,[path,fname]); plotPeaks(this); end function clearPeaksCallback(this,~,~) clearPeaks(this.PeakFinder); delete(this.peak_handle); end + + %Add a fit to the selected list + function addFitCallback(this,~,~) + val=this.Gui.FitList.Value; + this.Gui.SelFitList.String{end+1}=this.Gui.FitList.String{val}; + this.Gui.FitList.String(val)=[]; + end + + %Remove fits from selected fits + function removeFitCallback(this,~,~) + val=this.Gui.SelFitList.Value; + this.Gui.FitList.String{end+1}=this.Gui.SelFitList.String{val}; + this.Gui.SelFitList.String(val)=[]; + end end methods function trace_handle=get.trace_handle(this) trace_handle=getLineHandle(this.PeakFinder.Trace,this.axis_handle); end function base_dir=get.base_dir(this) try base_dir=this.Gui.BaseEdit.String; catch base_dir=pwd; end end function set.base_dir(this,base_dir) this.Gui.BaseEdit.String=base_dir; end function session_name=get.session_name(this) try session_name=this.Gui.SessionEdit.String; catch session_name=''; end end function set.session_name(this,session_name) this.Gui.SessionEdit.String=session_name; end function filename=get.filename(this) try filename=this.Gui.FileNameEdit.String; catch filename='placeholder'; end end function set.filename(this,filename) this.Gui.FileNameEdit.String=filename; end %Get function from save directory function save_dir=get.save_dir(this) save_dir=createSessionPath(this.base_dir,this.session_name); end end end \ No newline at end of file diff --git a/@MyPeakFinderGui/createGui.m b/@MyPeakFinderGui/createGui.m index 6ae0e93..ca2e7e2 100644 --- a/@MyPeakFinderGui/createGui.m +++ b/@MyPeakFinderGui/createGui.m @@ -1,174 +1,208 @@ function createGui(this) +fit_list={'Lorentzian','Double Lorentzian', 'Gorodetsky2000'}; fig_width=1000; -fig_h=1000; +fig_h=800; +row_height=50; col_width=120; x_first_col=50; button_size=[100,30]; edit_size=[100,30]; file_edit_size=[200,30]; -h_first_row=950; -h_second_row=900; -h_third_row=850; +h_first_row=fig_h-row_height; +h_second_row=fig_h-2*row_height; +h_third_row=fig_h-3*row_height; %Name sets the title of the window, NumberTitle turns off the FigureN text %that would otherwise be before the title, MenuBar is the menu normally on %the figure, toolbar is the toolbar normally on the figure. %HandleVisibility refers to whether gcf, gca etc will grab this figure. this.Gui.Window = figure('Name', 'PeakFinder',... 'NumberTitle', 'off', ... 'MenuBar','none',... 'Toolbar','figure',... 'HandleVisibility', 'off',... 'Units','Pixels',... - 'Position',[100,100,fig_width,fig_h],... + 'Position',[200,400,fig_width,fig_h],... 'WindowScrollWheelFcn',@(src, event) windowScrollCallback(this, src, event)); %Sets the close function (runs when x is pressed) to be class function set(this.Gui.Window, 'CloseRequestFcn',... @(src,event) closeFigure(this, src, event)); %Creates axis this.axis_handle=axes(this.Gui.Window,... 'Box','on',... 'Units','Pixels',... - 'Position',[50,50,900,750]); + 'Position',[50,50,fig_width-100,fig_h-6*row_height]); hold(this.axis_handle,'on'); this.axis_handle.ButtonDownFcn=@(src, event) clickCallback(this, src, event); %Button for doing the analysis this.Gui.AnalyzeButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col,h_first_row,button_size],... 'String','Analyze',... 'Callback',@(src, event) analyzeCallback(this, src, event)); %Checkbox for finding minima this.Gui.MinimaCheck=uicontrol(this.Gui.Window,... 'Style','checkbox',... 'Units','Pixels',... 'Position',[x_first_col+90,h_second_row,button_size],... 'Value',0); this.Gui.MinimaLabel=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','pixels',... 'Position',[x_first_col,h_second_row,[80,30]],... 'String','Find minima',... 'Enable','off'); %Button for clearing the data this.Gui.FitButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col,h_third_row,button_size],... 'String','Fit peaks',... 'Callback',@(src, event) fitPeakCallback(this, src, event)); %Button for clearing the data this.Gui.ClearButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col+col_width,h_first_row,button_size],... 'String','Clear',... 'Callback',@(src, event) clearCallback(this, src, event)); %Button for loading the trace this.Gui.LoadTraceButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col+4*col_width,h_first_row,button_size],... 'String','Load trace',... 'Callback',@(src, event) loadTraceCallback(this, src, event)); this.Gui.PromLabel=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','pixels',... 'Position',[x_first_col+2*col_width,h_first_row,edit_size],... 'String','Prominence',... 'Enable','off'); %Button for changing the peak threshold this.Gui.PromEdit=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','Pixels',... 'Position',[x_first_col+3*col_width,h_first_row,edit_size],... 'String','0.5'); this.Gui.SepLabel=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','pixels',... 'Position',[x_first_col+2*col_width,h_second_row,edit_size],... 'String','Res. Separation',... 'Enable','off'); %Button for changing the resonance separation this.Gui.SepEdit=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','Pixels',... 'Position',[x_first_col+3*col_width,h_second_row,edit_size],... 'String','1'); %Button for saving the peaks this.Gui.SavePeaksButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col+4*col_width,h_second_row,button_size],... 'String','Save Peaks',... 'Callback',@(src, event) savePeaksCallback(this, src, event)); %Button for loading peaks this.Gui.LoadPeaksButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col+4*col_width,h_third_row,button_size],... 'String','Load Peaks',... 'Callback',@(src, event) loadPeaksCallback(this, src, event)); %Button for clearing the peaks this.Gui.ClearPeaksButton=uicontrol(this.Gui.Window,... 'Style','pushbutton',... 'Units','Pixels',... 'Position',[x_first_col+col_width,h_second_row,button_size],... 'String','Clear peaks',... 'Callback',@(src, event) clearPeaksCallback(this, src, event)); this.Gui.BaseLabel=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','pixels',... 'Position',[x_first_col+5*col_width,h_first_row,edit_size],... 'String','Base directory',... 'Enable','off'); %Button for changing the peak threshold this.Gui.BaseEdit=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','Pixels',... 'Position',[x_first_col+6*col_width,h_first_row,file_edit_size],... 'String','M:\Measurement Campaigns'); this.Gui.SessionLabel=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','pixels',... 'Position',[x_first_col+5*col_width,h_second_row,edit_size],... 'String','Session name',... 'Enable','off'); %Editbox for changing the session name this.Gui.SessionEdit=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','Pixels',... 'Position',[x_first_col+6*col_width,h_second_row,file_edit_size],... 'String','placeholder'); this.Gui.FileNameLabel=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','pixels',... 'Position',[x_first_col+5*col_width,h_third_row,edit_size],... 'String','File name',... 'Enable','off'); %Editbox for changing the filename this.Gui.FileNameEdit=uicontrol(this.Gui.Window,... 'Style','edit',... 'Units','Pixels',... 'Position',[x_first_col+6*col_width,h_third_row,file_edit_size],... 'String','placeholder'); +%For selecting fits +this.Gui.FitList=uicontrol(this.Gui.Window,... + 'Style','listbox',... + 'Units','Pixels',... + 'String',fit_list,... + 'Position',[x_first_col+col_width,h_third_row-1.5*row_height,... + col_width,2*row_height]); + +%For selecting fits +this.Gui.SelFitList=uicontrol(this.Gui.Window,... + 'Style','listbox',... + 'Units','Pixels',... + 'Position',[x_first_col+2.5*col_width,h_third_row-1.5*row_height,... + col_width,2*row_height]); + +%Add fit +this.Gui.RemoveFitButton=uicontrol(this.Gui.Window,... + 'Style','pushbutton',... + 'Units','Pixels',... + 'Position',[x_first_col+2.05*col_width,h_third_row-0.9*row_height,50,20],... + 'String','<<',... + 'Callback',@(src, event) removeFitCallback(this, src, event)); + +%Remove fit +this.Gui.RemoveFitButton=uicontrol(this.Gui.Window,... + 'Style','pushbutton',... + 'Units','Pixels',... + 'Position',[x_first_col+2.05*col_width,h_third_row-0.4*row_height,50,20],... + 'String','>>',... + 'Callback',@(src, event) addFitCallback(this, src, event)); + + end \ No newline at end of file diff --git a/@MyTrace/MyTrace.m b/@MyTrace/MyTrace.m index d9fd4e9..5491ad6 100644 --- a/@MyTrace/MyTrace.m +++ b/@MyTrace/MyTrace.m @@ -1,444 +1,447 @@ % Class for XY data representation with labelling, plotting and % saving/loading functionality classdef MyTrace < handle & matlab.mixin.Copyable properties (Access=public) x=[]; y=[]; name_x='x'; name_y='y'; unit_x=''; unit_y=''; + %Information about how the trace was taken + MeasHeaders=MyMetadata(); load_path=''; %Cell that contains handles the trace is plotted in hlines={}; + uid=''; end properties (Access=private) Parser; end properties (Dependent=true) label_x; label_y; end methods (Access=private) %Creates the input parser for the class. Includes default values %for all optional parameters. function createParser(this) p=inputParser; addParameter(p,'x',[]); addParameter(p,'y',[]); addParameter(p,'unit_x','x',@ischar); addParameter(p,'unit_y','y',@ischar); addParameter(p,'name_x','x',@ischar); addParameter(p,'name_y','y',@ischar); addParameter(p,'load_path','',@ischar); addParameter(p,'uid','',@ischar); this.Parser=p; end %Sets the class variables to the inputs from the inputParser. Can %be used to reset class to default values if default_flag=true. function parseInputs(this, inputs, default_flag) parse(this.Parser,inputs{:}); for i=1:length(this.Parser.Parameters) %Sets the value if there was an input or if the default %flag is on. The default flag is used to reset the class to %its default values. if default_flag || ~any(ismember(this.Parser.Parameters{i},... this.Parser.UsingDefaults)) this.(this.Parser.Parameters{i})=... this.Parser.Results.(this.Parser.Parameters{i}); end end end end methods (Access=public) function this=MyTrace(varargin) createParser(this); parseInputs(this,varargin,true); if ~ismember('load_path',this.Parser.UsingDefaults) loadTrace(this,this.load_path); end end %Defines the save function for the class. Note that this is only %used when we want to write only the data with its associated %trace, rather than just the trace. To write just the trace with %fewer input checks, use the writeTrace function. function save(this,varargin) %Parse inputs for saving p=inputParser; addParameter(p,'filename','placeholder',@ischar); addParameter(p,'save_dir',pwd,@ischar); addParameter(p,'save_prec',15); addParameter(p,'overwrite_flag',false); parse(p,varargin{:}); %Assign shorter names filename=p.Results.filename; save_dir=p.Results.save_dir; save_prec=p.Results.save_prec; overwrite_flag=p.Results.overwrite_flag; %Puts together the full file name fullfilename=fullfile([save_dir,filename,'.txt']); %Creates the file in the given folder write_flag=createFile(save_dir,fullfilename,overwrite_flag); %Returns if the file is not created for some reason if ~write_flag; error('File not created, returned write_flag %i',write_flag); end %We now write the data to the file writeData(this, fullfilename,'save_prec',save_prec); end %Writes the data to a file. This is separated so that other %programs can write to the file from the outside. We circumvent the %checks for the existence of the file here, assuming it is done %outside. function writeData(this,fullfilename, varargin) p=inputParser; addRequired(p,'fullfilename',@ischar); addParameter(p,'save_prec',15); parse(p,fullfilename,varargin{:}); fullfilename=p.Results.fullfilename; save_prec=p.Results.save_prec; fileID=fopen(fullfilename,'a'); %Creates the Metadata structure. Metadata=MyMetadata('uid',this.uid); addField(Metadata,'Info'); addParam(Metadata,'Info','uid',this.uid,'%s'); addParam(Metadata,'Info','Name1',this.name_x,'%s'); addParam(Metadata,'Info','Name2',this.name_y,'%s'); addParam(Metadata,'Info','Unit1',this.unit_x,'%s'); addParam(Metadata,'Info','Unit2',this.unit_y,'%s'); %Writes the metadata header writeHeader(Metadata,fullfilename,'Info',... 'title','Trace information'); %Puts in header title for the data fprintf(fileID,[Metadata.hdr_spec,'Data',Metadata.hdr_spec,'\r\n']); %Finds appropriate column width cw=max([length(this.label_y),length(this.label_x),... save_prec+7]); %Pads the vectors if they are not equal length diff=length(this.x)-length(this.y); if diff<0 this.x=[this.x;zeros(-diff,1)]; warning(['Zero padded x vector as the saved vectors are',... ' not of the same length']); elseif diff>0 this.y=[this.y;zeros(diff,1)]; warning(['Zero padded y vector as the saved vectors are',... ' not of the same length']); end %Saves in scientific notation with correct column width defined %above. Again if cw=20, we get %14.10e\t%14.10e\r\n data_format_str=sprintf('%%%i.%ie\t%%%i.%ie\r\n',... cw,save_prec,cw,save_prec); fprintf(fileID,data_format_str,[this.x, this.y]'); fclose(fileID); end function clearData(this) this.x=[]; this.y=[]; end function loadTrace(this, file_path, varargin) p=inputParser; addParameter(p,'hdr_spec','==',@ischar); addParameter(p,'end_header','Data',@ischar); parse(p,varargin{:}); hdr_spec=p.Results.hdr_spec; end_header=p.Results.end_header; if ~exist(file_path,'file') error('File does not exist, please choose a different load path') end %Instantiate a header object from the file you are loading. We %get the line number we want to read from as an output. [MeasHeaders,end_line_no]=MyMetadata(... 'load_path',file_path,... 'hdr_spec',hdr_spec,... 'end_header',end_header); %Tries to assign units and names try this.unit_x=MeasHeaders.TraceInformation.Unit1.value; this.unit_y=MeasHeaders.TraceInformation.Unit2.value; this.name_x=MeasHeaders.TraceInformation.Name1.value; this.name_y=MeasHeaders.TraceInformation.Name2.value; catch warning(['No metadata found. No units or labels assigned',... ' when loading trace from %s'],file_path) this.name_x='x'; this.name_y='y'; this.unit_x='x'; this.unit_y='y'; end %Reads x and y data data_array=dlmread(file_path,'\t',end_line_no,0); this.x=data_array(:,1); this.y=data_array(:,2); this.load_path=file_path; end %Allows setting of multiple properties in one command. function setTrace(this, varargin) parseInputs(this, varargin, false); end %Plots the trace on the given axes, using the class variables to %define colors, markers, lines and labels. Takes all optional %parameters of the class as inputs. function plotTrace(this,plot_axes,varargin) %Checks that there are axes to plot assert(exist('plot_axes','var') && ... (isa(plot_axes,'matlab.graphics.axis.Axes')||... isa(plot_axes,'matlab.ui.control.UIAxes')),... 'Please input axes to plot in.') %Checks that x and y are the same size assert(validatePlot(this),... 'The length of x and y must be identical to make a plot') %Parses inputs p=inputParser(); validateColor=@(x) assert(iscolor(x),... 'Input must be a valid color. See iscolor function'); addParameter(p,'Color','b',validateColor); validateMarker=@(x) assert(ismarker(x),... 'Input must be a valid marker. See ismarker function'); addParameter(p,'Marker','none',validateMarker); validateLine=@(x) assert(isline(x),... 'Input must be a valid linestyle. See isline function'); addParameter(p,'LineStyle','-',validateLine); addParameter(p,'MarkerSize',6,... @(x) validateattributes(x,{'numeric'},{'positive'})); addParameter(p,'make_labels',false,@islogical); interpreters={'none','tex','latex'}; validateInterpreter=@(x) assert(contains(x,interpreters),... 'Interpreter must be none, tex or latex'); addParameter(p,'Interpreter','latex',validateInterpreter); parse(p,varargin{:}); ind=findLineInd(this, plot_axes); if ~isempty(ind) && any(ind) set(this.hlines{ind},'XData',this.x,'YData',this.y); else this.hlines{end+1}=plot(plot_axes,this.x,this.y); ind=length(this.hlines); end %Sets the correct color and label options set(this.hlines{ind},'Color',p.Results.Color,'LineStyle',... p.Results.LineStyle,'Marker',p.Results.Marker,... 'MarkerSize',p.Results.MarkerSize); if p.Results.make_labels interpreter=p.Results.Interpreter; xlabel(plot_axes,this.label_x,'Interpreter',interpreter); ylabel(plot_axes,this.label_y,'Interpreter',interpreter); set(plot_axes,'TickLabelInterpreter',interpreter); end end %If there is a line object from the trace in the figure, this sets %it to the appropriate visible setting. function setVisible(this, plot_axes, bool) if bool vis='on'; else vis='off'; end ind=findLineInd(this, plot_axes); if ~isempty(ind) && any(ind) set(this.hlines{ind},'Visible',vis) end end %Defines addition of two MyTrace objects function sum=plus(a,b) checkArithmetic(a,b); sum=MyTrace('x',a.x,'y',a.y+b.y,'unit_x',a.unit_x,... 'unit_y',a.unit_y,'name_x',a.name_x,'name_y',a.name_y); end %Defines subtraction of two MyTrace objects function sum=minus(a,b) checkArithmetic(a,b); sum=MyTrace('x',a.x,'y',a.y-b.y,'unit_x',a.unit_x,... 'unit_y',a.unit_y,'name_x',a.name_x,'name_y',a.name_y); end function [max_val,max_x]=max(this) assert(validatePlot(this),['MyTrace object must contain',... ' nonempty data vectors of equal length to find the max']) [max_val,max_ind]=max(this.y); max_x=this.x(max_ind); end function fwhm=calcFwhm(this) assert(validatePlot(this),['MyTrace object must contain',... ' nonempty data vectors of equal length to find the fwhm']) [max_val,~]=max(this); ind1=find(this.y>max_val/2,1,'first'); ind2=find(this.y>max_val/2,1,'last'); fwhm=this.x(ind2)-this.x(ind1); end %Integrates the trace numerically function area=integrate(this,varargin) assert(validatePlot(this),['MyTrace object must contain',... ' nonempty data vectors of equal length to integrate']) %Input parser for optional inputs p=inputParser; %Default is to use all the data in the trace addOptional(p,'ind',true(1,length(this.x))); parse(p,varargin{:}); ind=p.Results.ind; %Integrates the data contained in the indexed part. area=trapz(this.x(ind),this.y(ind)); end %Checks if the object is empty function bool=isempty(this) bool=isempty(this.x) && isempty(this.y); end %Checks if the data can be plotted function bool=validatePlot(this) bool=~isempty(this.x) && ~isempty(this.y)... && length(this.x)==length(this.y); end function hline=getLineHandle(this,ax) ind=findLineInd(this,ax); if ~isempty(ind) hline=this.hlines{ind}; else hline=[]; end end end methods (Access=private) %Checks if arithmetic can be done with MyTrace objects. function checkArithmetic(a,b) assert(isa(a,'MyTrace') && isa(b,'MyTrace'),... ['Both objects must be of type MyTrace to add,',... 'here they are type %s and %s'],class(a),class(b)); assert(strcmp(a.unit_x, b.unit_x) && strcmp(a.unit_y,b.unit_y),... 'The MyTrace classes must have the same units for arithmetic'); assert(length(a.x)==length(a.y) && length(a.x)==length(a.y),... 'The length of x and y must be equal for arithmetic'); assert(all(a.x==b.x),... 'The MyTrace objects must have identical x-axis for arithmetic') end %Finds the hline handle that is plotted in the specified axes function ind=findLineInd(this, plot_axes) if ~isempty(this.hlines) ind=cellfun(@(x) ismember(x,findall(plot_axes,... 'Type','Line')),this.hlines); else ind=[]; end end end %Set and get methods methods %Set function for x, checks if it is a vector of doubles. function set.x(this, x) assert(isnumeric(x),... 'Data must be of class double'); this.x=x(:); end %Set function for y, checks if it is a vector of doubles and %generates a new UID for the trace function set.y(this, y) assert(isnumeric(y),... 'Data must be of class double'); this.y=y(:); this.uid=genUid(); %#ok end %Set function for unit_x, checks if input is a string. function set.unit_x(this, unit_x) assert(ischar(unit_x),'Unit must be a char, not a %s',... class(unit_x)); this.unit_x=unit_x; end %Set function for unit_y, checks if input is a string function set.unit_y(this, unit_y) assert(ischar(unit_y),'Unit must be a char, not a %s',... class(unit_y)); this.unit_y=unit_y; end %Set function for name_x, checks if input is a string function set.name_x(this, name_x) assert(ischar(name_x),'Name must be a char, not a %s',... class(name_x)); this.name_x=name_x; end %Set function for name_y, checks if input is a string function set.name_y(this, name_y) assert(ischar(name_y),'Name must be a char, not a %s',... class(name_y)); this.name_y=name_y; end function set.load_path(this, load_path) assert(ischar(load_path),'File path must be a char, not a %s',... class(load_path)); this.load_path=load_path; end function set.uid(this, uid) assert(ischar(uid),'UID must be a char, not a %s',... class(uid)); this.uid=uid; end %Get function for label_x, creates label from name_x and unit_x. function label_x=get.label_x(this) label_x=sprintf('%s (%s)', this.name_x, this.unit_x); end %Get function for label_y, creates label from name_y and unit_y. function label_y=get.label_y(this) label_y=sprintf('%s (%s)', this.name_y, this.unit_y); end end end diff --git a/Utility functions/testfit.m b/Utility functions/testfit.m index 6276d22..9ab6307 100644 --- a/Utility functions/testfit.m +++ b/Utility functions/testfit.m @@ -1,25 +1,26 @@ %Testing tool for MyFit clear -x_vec=linspace(-100,100,1000); +x_vec=linspace(0,200,1000); -testFit=MyFit('fit_name','gaussian','enable_gui',0); +testFit=MyFit('fit_name','lorentzian','enable_gui',1); params=cell(1,testFit.n_params); for i=1:testFit.n_params params{i}=5*rand; end -params{3}=10*rand; +params{3}=200*rand; params -y_vec=testFit.FitStruct.(testFit.fit_name).anon_fit_fun(x_vec,params{:}).*normrnd(1,0.05,size(x_vec)); +y_vec=testFit.FitStruct.(testFit.fit_name).anon_fit_fun(x_vec,params{:}).*normrnd(1,0.04,size(x_vec)); figure(1) ax=gca; plot(x_vec,y_vec,'x'); +axis([min(x_vec),max(x_vec),0.5*min(y_vec),1.5*max(y_vec)]); hold on testFit.plot_handle=ax; testFit.enable_plot=1; testFit.Data.x=x_vec; testFit.Data.y=y_vec; -testFit.genInitParams; -testFit.init_params -testFit.fitTrace; -testFit.init_params \ No newline at end of file +% testFit.genInitParams; +% testFit.init_params +% testFit.fitTrace; +% testFit.init_params \ No newline at end of file