function [varargout] = choose_profile_limits(varargin)
%
% choose_profile_limits.m--A GUI to enable a user to choose the start and
% end of a depth profile (from a CTD cast, VMP cast, etc.).
%
% choose_profile_limits.m can be called specifying just the depth vector
% (z) as an input argument or both depth and time (x) vectors.
%
% Other options are specified as parameter/value pairs:
% 'closeAfter': if 1, then figure window will close after limits chosen
% (default is 1);
% 'initStartIndex': an initial value of the index (default is 1);
% 'initEndIndex': an initial value of the index (default is length(z));
% 'boxWidthPct': width of smaller axes as percent of range(x) (default 5);
% 'marker': 'on' or 'off' (the default);
% 'titleStr': default is no title;
% 'xlabelStr': default is no xlabel;
% 'ylabelStr': default is 'pressure/depth';
% 'buttonStrs': default is {'Accept' 'Reject' 'Skip' 'Marker' 'Quit'}
% 'showButtons': default is [1 1 1 1 1]
%
% By default, choose_profile_limits produces a GUI with five buttons:
% "Accept" returns the current crop limits;
% "Reject" returns crop limits of [+Inf -Inf];
% "Skip" returns crop limits of [NaN NaN];
% "Marker" turns the line markers on and off;
% "Quit" returns crop limits of [[][]] and closes figure.
%
% If you anticipate no need to distinguish between a user skipping and
% rejecting a particular cast, you can eliminate the "Skip" button by
% setting the 'showButtons' parameter to [1 1 0 1 1]. The 'buttonStrs'
% parameter may then be changed to {'Crop' 'Cancel' 'dummy' 'Marker'
% 'Quit'} (or whatever you want) to make the button labels more intuitive.
% Similarly, remove the ability to turn line markers on and off by
% eliminating the "Marker" button.
%
% H = CHOOSE_PROFILE_LIMITS(PARAMETER,VALUE,...) creates an empty
% choose_profile_limits figure window with handle H. The parameter/value
% pairs are optional.
%
% ...CHOOSE_PROFILE_LIMITS(H,...), where H is the handle of an existing
% choose_profile_limits figure window, results in the existing figure being
% reused for the next profile. This is useful when choose_profile_limits.m
% is being called in a loop.
%
% Syntax: choose_profile_limits(<h>,<<x>,z>,<parameter1,value1,...>)
%
% e.g., [x,z] = choose_profile_limits('demo'); % (gets demo data)
%
% e.g., [startIndex,endIndex] = choose_profile_limits(z)
%
% e.g., [startIndex,endIndex] = choose_profile_limits(x,z)
%
% e.g., h = choose_profile_limits('buttonShow',[1 1 0 0 1],'closeAfter',0);
% [startIndex,endIndex] = choose_profile_limits(h,x,z)
%
% e.g., [startIndex,endIndex] = choose_profile_limits(x,z,...
% 'initStartIndex',32,'initEndIndex',108,...
% 'boxWidthPct',25,'marker','on',...
% 'titleStr','This is a title',...
% 'xlabelStr','Samples',...
% 'ylabelStr','Depth', ...
% 'buttonStrs',{'Crop' 'Cancel' 'dummy' 'dummy' 'dummy'}, ...
% 'buttonShow',[1 1 0 0 0])
% Developed in Matlab 7.0.1.24704 (R14) Service Pack 1 on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2006-03-17 16:23
%-------------------------------------------------------------------------
% Define constants.
CROPLINESTYLE = '--';
CROPLINEWIDTH = 3;
markerStyle = 'o';
GuiScale = 1;
DeltaFontSize = 0;
FigurePosition = NaN;
axLimsBufferPct = 5; % percentage of minimum required for data.
% Handle input arguments.
% ...Return demo data if requested.
if nargin == 1
if isstr(varargin{1})
if strcmp(lower(varargin{1}),'demo')
z = [0 0 0 10 20 30 40 50 50 40 30 20 10 0];
z = interp1([1:length(z)],z,linspace(1,length(z),200));
%x = linspace(now,now+.1,length(z));
x = linspace(1000,1100,length(z));
varargout{1} = x;
varargout{2} = z;
return;
else
error([mfilename '.m--Unrecognised input string ''' varargin{1} '''']);
end % if
end % if
end % if
% If no arguments passed to function or if first argument is a parameter
% name, initialise a "hollow" version of the GUI for later calls.
if nargin == 0
isHollow = true;
elseif isstr(varargin{1})
isHollow = true;
else
isHollow = false;
end % if
% Remove first argument from the list if it is the handle of an existing
% choose_profile_limits figure window.
args = varargin;
cplFig = [];
% ...By default, not reusing an existing figure.
doReuse = false;
if length(args) > 0
if ishandle(args{1})
if strcmp(get(args{1},'Tag'),'cpl_fig')
cplFig = args{1};
doReuse = true;
if length(args)>1
args = args(2:end);
else
args = {};
end % if
end % if
end % if
end % if
% Arguments are [z] (odd number) or [x,z] (even number) or
% [z,parameter/value pairs] (odd number) or [x,z,parameter/value pairs]
% (even number). The first argument, then, is z if the number of arguments
% is odd; otherwise, the first two arguments are x and z.
isOdd = rem(length(args),2) == 1;
if isHollow
% Making "hollow" GUI with no data.
x = [];
z = [];
elseif isOdd
x = [];
z = args{1};
if length(args) > 1
args = args(2:end);
else
args = {};
end % if
else
x = args{1};
z = args{2};
if length(args) > 2
args = args(3:end);
else
args = {};
end % if
end % if
% ...If x is not supplied by user, then create it, making x a simple index
% to the elements of z.
if isempty(x)
x = 1:length(z);
end % if
if length(x) ~= length(z)
error([mfilename '.m--Vectors ''x'' and ''z'' must be same length.']);
end % if
% ...Handle parameter/value pairs.
if doReuse == true
% If reusing existing figure, most defaults are extracted from the
% figure.
cpl_properties = getappdata(cplFig,'cpl_properties');
defaultVals.initStartIndex = 1;
defaultVals.initEndIndex = length(z);
defaultVals.boxWidthPct = cpl_properties.boxWidthPct;
defaultVals.titleStr = cpl_properties.titleStr;
defaultVals.xlabelStr = cpl_properties.xlabelStr;
defaultVals.ylabelStr = cpl_properties.ylabelStr;
defaultVals.marker = cpl_properties.marker;
defaultVals.buttonStrs = cpl_properties.buttonStrs;
defaultVals.buttonShow = cpl_properties.buttonShow;
defaultVals.closeAfter = cpl_properties.closeAfter;
else
defaultVals.initStartIndex = 1;
defaultVals.initEndIndex = length(z);
defaultVals.boxWidthPct = 5; % percent of total data width
defaultVals.titleStr = '';
defaultVals.xlabelStr = '';
defaultVals.ylabelStr = 'pressure/depth';
defaultVals.marker = 'off';
defaultVals.buttonStrs = {'Accept' 'Reject' 'Skip' 'Marker' 'Quit'};
defaultVals.buttonShow = [1 1 1 1 1];
defaultVals.closeAfter = 1;
end % if
allowNewFields = 0;
isCaseSensitive = 0;
parValStruct = parse_args(defaultVals,args{:},allowNewFields,isCaseSensitive);
initStartIndex = parValStruct.initStartIndex;
initEndIndex = parValStruct.initEndIndex;
boxWidthPct = parValStruct.boxWidthPct;
titleStr = parValStruct.titleStr;
xlabelStr = parValStruct.xlabelStr;
ylabelStr = parValStruct.ylabelStr;
markerVal = parValStruct.marker;
buttonStrs = parValStruct.buttonStrs;
buttonShow = parValStruct.buttonShow;
closeAfter = parValStruct.closeAfter ;
marker = parValStruct.marker;
% ......Test parameter/value pairs; over-ride if necessary.
if isempty(z)
initStartIndex = [];
initEndIndex = [];
else
if initStartIndex < 0
initStartIndex = 1;
end % if
if initStartIndex>length(z)
initStartIndex = 1;
end % if
if initEndIndex <= initStartIndex
initEndIndex = length(z);
end % if
if initEndIndex>length(z)
initEndIndex = length(z);
end % if
end % if
if boxWidthPct <= 0 | boxWidthPct >= 100
boxWidthPct = defaultVals.boxWidthPct;
end % if
if ~isstr(titleStr)
titleStr = '';
end % if
if ~isstr(xlabelStr)
xlabelStr = '';
end % if
if ~isstr(ylabelStr)
ylabelStr = '';
end % if
% Create GUI objects if they don't already exist.
if isempty(cplFig)
doCreateGUI = true;
else
doCreateGUI = false;
end % if
if doCreateGUI
cplObjs = cpl_makeguiobjects(GuiScale,DeltaFontSize,FigurePosition);
cplFig = findobj(cplObjs,'Type','figure');
set(findobj(cplFig,'Tag','accept_control'),'Callback','accept_control_callback');
set(findobj(cplFig,'Tag','reject_control'),'Callback','reject_control_callback');
set(findobj(cplFig,'Tag','skip_control'),'Callback','skip_control_callback');
set(findobj(cplFig,'Tag','marker_control'),'Callback','marker_control_callback');
set(findobj(cplFig,'Tag','quit_control'),'Callback','quit_control_callback');
set(findobj(cplFig,'Tag','full_ax'),'ButtonDownFcn','full_ax_mouse_callback')
helpMenu = uimenu('Label','Help');
set(helpMenu,'Callback','cpl_help');
cpl_make_lines(cplFig);
% Customise button labels.
accept_control = findobj(cplFig,'Tag','accept_control');
reject_control = findobj(cplFig,'Tag','reject_control');
skip_control = findobj(cplFig,'Tag','skip_control');
marker_control = findobj(cplFig,'Tag','marker_control');
quit_control = findobj(cplFig,'Tag','quit_control');
set(accept_control,'String',buttonStrs{1});
set(reject_control,'String',buttonStrs{2});
set(skip_control,'String',buttonStrs{3});
set(marker_control,'String',buttonStrs{4});
set(quit_control,'String',buttonStrs{5});
% Make some buttons invisible, if requested.
buttonShowStrs = cell(length(buttonShow),1);
[buttonShowStrs{:}] = deal('on');
[buttonShowStrs{buttonShow==0}] = deal('off');
set(accept_control,'visible',buttonShowStrs{1});
set(reject_control','visible',buttonShowStrs{2});
set(skip_control,'visible',buttonShowStrs{3});
set(marker_control,'visible',buttonShowStrs{4});
set(quit_control,'visible',buttonShowStrs{5});
% Adjust the location of the buttons if any have been made invisible.
if any(buttonShow==0)
buttonPos = [];
buttonPos(end+1,:) = get(accept_control,'position');
buttonPos(end+1,:) = get(reject_control,'position');
buttonPos(end+1,:) = get(skip_control,'position');
buttonPos(end+1,:) = get(marker_control,'position');
buttonPos(end+1,:) = get(quit_control,'position');
buttonWidth = buttonPos(1,3);
leftMost = buttonPos(1,1);
rightMost = buttonPos(end,1)+buttonWidth;
%buttonPanelCentre = mean([leftMost rightMost]);
buttonPanelWidth = rightMost - leftMost;
numButtons = length(find(buttonShow==1));
buttonCentres = leftMost + ((1:numButtons)./(numButtons+1)) .* buttonPanelWidth;
leftLocations = buttonCentres - buttonWidth/2;
newButtonPos = buttonPos;
newButtonPos(buttonShow==1,1) = leftLocations;
set(accept_control,'position',newButtonPos(1,:));
set(reject_control,'position',newButtonPos(2,:));
set(skip_control,'position',newButtonPos(3,:));
set(marker_control,'position',newButtonPos(4,:));
set(quit_control,'position',newButtonPos(5,:));
end % if
set(findobj(cplFig,'Tag','full_ax'),'box','on','ydir','reverse');
set(findobj(cplFig,'Tag','start_ax'),'box','on','ydir','reverse');
set(findobj(cplFig,'Tag','end_ax'),'box','on','ydir','reverse');
end % if
% Initialise appdata to initial limits.
setappdata(cplFig,'profileLimits',[initStartIndex initEndIndex]);
set(get(findobj(cplFig,'Tag','full_ax'),'title'),'string',titleStr);
set(get(findobj(cplFig,'Tag','full_ax'),'xlabel'),'string',xlabelStr);
set(get(findobj(cplFig,'Tag','full_ax'),'ylabel'),'string',ylabelStr);
% ...Data lines:
if strcmp(markerVal,'on')
markerStr = markerStyle;
else
markerStr = 'none';
end % if
full_ax_preStartDepthLine = findobj(cplFig,'Tag','full_ax_preStartDepthLine');
full_ax_postEndDepthLine = findobj(cplFig,'Tag','full_ax_postEndDepthLine');
full_ax_selectDepthLine = findobj(cplFig,'Tag','full_ax_selectDepthLine');
start_ax_preStartDepthLine = findobj(cplFig,'Tag','start_ax_preStartDepthLine');
start_ax_postEndDepthLine = findobj(cplFig,'Tag','start_ax_postEndDepthLine');
start_ax_selectDepthLine = findobj(cplFig,'Tag','start_ax_selectDepthLine');
end_ax_preStartDepthLine = findobj(cplFig,'Tag','end_ax_preStartDepthLine');
end_ax_postEndDepthLine = findobj(cplFig,'Tag','end_ax_postEndDepthLine');
end_ax_selectDepthLine = findobj(cplFig,'Tag','end_ax_selectDepthLine');
set(full_ax_preStartDepthLine,'marker',markerStr);
set(full_ax_postEndDepthLine,'marker',markerStr);
set(full_ax_selectDepthLine, ...
'marker',markerStr,...
'xdata',x,...
'ydata',z);
set(start_ax_preStartDepthLine,'marker',markerStr);
set(start_ax_postEndDepthLine,'marker',markerStr);
set(start_ax_selectDepthLine,...
'marker',markerStr,...
'xdata',x,...
'ydata',z);
set(end_ax_preStartDepthLine,'marker',markerStr);
set(end_ax_postEndDepthLine,'marker',markerStr);
set(end_ax_selectDepthLine,...
'marker',markerStr,...
'xdata',x,...
'ydata',z);
%set(findobj(cplFig,'Tag','full_ax_preStartDepthLine'),'UserData',markerVal);
lineProps = {markerStyle markerVal};
set(findobj(cplFig,'Tag','full_ax_preStartDepthLine'),'UserData',lineProps);
startBoxL = findobj(cplFig,'Tag','startBoxL');
startBoxR = findobj(cplFig,'Tag','startBoxR');
startBoxT = findobj(cplFig,'Tag','startBoxT');
startBoxB = findobj(cplFig,'Tag','startBoxB');
endBoxL = findobj(cplFig,'Tag','endBoxL');
endBoxR = findobj(cplFig,'Tag','endBoxR');
endBoxT = findobj(cplFig,'Tag','endBoxT');
endBoxB = findobj(cplFig,'Tag','endBoxB');
full_ax_StartLine = findobj(cplFig,'Tag','full_ax_StartLine');
if isempty(z)
initStartX = [];
initEndX = [];
initZ = [];
else
initStartX = [x(initStartIndex) x(initStartIndex)];
initEndX = [x(initEndIndex) x(initEndIndex)];
initZ = [NaN NaN];
end % if
set(full_ax_StartLine,'xdata',initStartX,'ydata',initZ);
full_ax_EndLine = findobj(cplFig,'Tag','full_ax_EndLine');
set(full_ax_EndLine,'xdata',initEndX,'ydata',initZ);
start_ax_StartLine = findobj(cplFig,'Tag','start_ax_StartLine');
set(start_ax_StartLine,'xdata',initStartX,'ydata',initZ);
start_ax_EndLine = findobj(cplFig,'Tag','start_ax_EndLine');
set(start_ax_EndLine,'xdata',initEndX,'ydata',initZ);
% ...Start/end lines for end axis:
end_ax_StartLine = findobj(cplFig,'Tag','end_ax_StartLine');
set(end_ax_StartLine,'xdata',initStartX,'ydata',initZ);
end_ax_EndLine = findobj(cplFig,'Tag','end_ax_EndLine');
set(end_ax_EndLine,'xdata',initEndX,'ydata',initZ);
cropLines = [full_ax_StartLine full_ax_EndLine ...
start_ax_StartLine start_ax_EndLine ...
end_ax_StartLine end_ax_EndLine];
set(cropLines,'linewidth',CROPLINEWIDTH,'linestyle',CROPLINESTYLE);
% ......Ignore crop lines in determining y-limits of plot.
set(cropLines,'yliminclude','off');
% Add callbacks to lines and buttons, etc.
%set(cropLines,'ButtonDownFcn','cpl_drag_crop_lines');
draglines(cropLines,'cpl_finish_crop_drag');
set([startBoxL startBoxR endBoxL endBoxR],'ButtonDownFcn','cpl_drag_box_lines');
% Store certain values in the figure for later use by other functions.
cpl_properties.boxWidthPct = boxWidthPct;
cpl_properties.axLimsBufferPct = axLimsBufferPct;
cpl_properties.x = x;
cpl_properties.z = z;
cpl_properties.startIndex = initStartIndex;
cpl_properties.endIndex = initEndIndex;
cpl_properties.titleStr = titleStr;
cpl_properties.xlabelStr = xlabelStr;
cpl_properties.ylabelStr = ylabelStr;
cpl_properties.marker = marker;
cpl_properties.buttonStrs = buttonStrs;
cpl_properties.buttonShow = buttonShow;
cpl_properties.closeAfter = closeAfter;
setappdata(cplFig,'cpl_properties',cpl_properties);
accept_control = findobj(cplFig,'Tag','accept_control');
reject_control = findobj(cplFig,'Tag','reject_control');
skip_control = findobj(cplFig,'Tag','skip_control');
marker_control = findobj(cplFig,'Tag','marker_control');
quit_control = findobj(cplFig,'Tag','quit_control');
if isHollow
% Disable all but the Quit button.
set([accept_control reject_control skip_control marker_control],...
'enable','off');
% Return the figure handle.
if nargout > 0
varargout{1} = cplFig;
end % if
return;
else
% Otherwise, enable all controls.
set([accept_control reject_control skip_control marker_control quit_control],...
'enable','on');
end % if
cpl_update(cplFig);
% Wait for figure window to be closed or a GUI button to be pressed.
uiwait;
if ishandle(cplFig)
xlims = getappdata(cplFig,'profileLimits');
else
% If figure has been closed, then xlims will be empty (xlims will also
% be empty if Quit button was pressed).
xlims = [];
end % if
if closeAfter == 1
if ishandle(cplFig)
close(cplFig);
end % if
end % if
if nargout > 1
if length(xlims)>1
varargout{1} = xlims(1);
varargout{2} = xlims(2);
else
varargout{1} = [];
varargout{2} = [];
end
end % if
%-------------------------------------------------------------------------
function [] = cpl_make_lines(cplFig)
%
% cpl_make_lines.m--Makes line objects for cpl GUI (cpl_makeguiobjects.m
% makes only axes, uicontrols, etc.).
% Syntax: cpl_make_lines(cplFig)
% Developed in Matlab 7.0.1.24704 (R14) Service Pack 1 on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2006-03-17 16:23
%-------------------------------------------------------------------------
LEFTCOLOUR = [1 0 0];
RIGHTCOLOUR = [0 1 0];
BOXCOLOUR = .1 * [1 1 1];
PRESTARTCOLOUR = .7 * [1 1 1];
POSTENDCOLOUR = .7 * [1 1 1];
SELECTLINEWIDTH = 3;
SELECTCOLOUR = [0 0 1];
axes(findobj(cplFig,'Tag','full_ax'));
full_ax_preStartDepthLine = line(NaN,NaN,...
'Tag','full_ax_preStartDepthLine',...
'color',PRESTARTCOLOUR);
full_ax_postEndDepthLine = line(NaN,NaN,...
'Tag','full_ax_postEndDepthLine',...
'color',POSTENDCOLOUR);
full_ax_selectDepthLine = line(NaN,NaN,...
'Tag','full_ax_selectDepthLine',...
'color',SELECTCOLOUR,...
'lineWidth',SELECTLINEWIDTH);
axes(findobj(cplFig,'Tag','start_ax'));
start_ax_preStartDepthLine = line(NaN,NaN,...
'Tag','start_ax_preStartDepthLine',...
'color',PRESTARTCOLOUR);
start_ax_postEndDepthLine = line(NaN,NaN,...
'Tag','start_ax_postEndDepthLine',...
'color',POSTENDCOLOUR);
start_ax_selectDepthLine = line(NaN,NaN,...
'color',SELECTCOLOUR,...
'lineWidth',SELECTLINEWIDTH,...
'Tag','start_ax_selectDepthLine');
axes(findobj(cplFig,'Tag','end_ax'));
end_ax_preStartDepthLine = line(NaN,NaN,...
'Tag','end_ax_preStartDepthLine',...
'color',PRESTARTCOLOUR);
end_ax_postEndDepthLine = line(NaN,NaN,...
'Tag','end_ax_postEndDepthLine',...
'color',POSTENDCOLOUR);
end_ax_selectDepthLine = line(NaN,NaN,...
'Tag','end_ax_selectDepthLine',...
'color',SELECTCOLOUR,...
'lineWidth',SELECTLINEWIDTH);
% ...Make "boxes" in full-profile axes, indicating region covered by start
% and end axes.
% ......Start box.
axes(findobj(cplFig,'Tag','full_ax'));
startBoxL = line([NaN NaN],[NaN NaN],'Tag','startBoxL');
startBoxR = line([NaN NaN],[NaN NaN],'Tag','startBoxR');
startBoxT = line([NaN NaN],[NaN NaN],'Tag','startBoxT');
startBoxB = line([NaN NaN],[NaN NaN],'Tag','startBoxB');
% ......End box.
axes(findobj(cplFig,'Tag','full_ax'));
endBoxL = line([NaN NaN],[NaN NaN],'Tag','endBoxL');
endBoxR = line([NaN NaN],[NaN NaN],'Tag','endBoxR');
endBoxT = line([NaN NaN],[NaN NaN],'Tag','endBoxT');
endBoxB = line([NaN NaN],[NaN NaN],'Tag','endBoxB');
boxLines = [startBoxL startBoxR startBoxT startBoxB ...
endBoxL endBoxR endBoxT endBoxB];
set(boxLines,'color',BOXCOLOUR,'linestyle','--');
% ...Start/end lines for full-profile axis:
axes(findobj(cplFig,'Tag','full_ax'));
full_ax_StartLine = line([NaN NaN],[NaN NaN],'color',LEFTCOLOUR,'Tag','full_ax_StartLine');
full_ax_EndLine = line([NaN NaN],[NaN NaN],'color',RIGHTCOLOUR,'Tag','full_ax_EndLine');
% ...Start/end lines for start axis:
axes(findobj(cplFig,'Tag','start_ax'));
start_ax_StartLine = line([NaN NaN],[NaN NaN],'color',LEFTCOLOUR,'Tag','start_ax_StartLine');
start_ax_EndLine = line([NaN NaN],[NaN NaN],'color',RIGHTCOLOUR,'Tag','start_ax_EndLine');
% ...Start/end lines for end axis:
axes(findobj(cplFig,'Tag','end_ax'));
end_ax_StartLine = line([NaN NaN],[NaN NaN],'color',LEFTCOLOUR,'Tag','end_ax_StartLine');
end_ax_EndLine = line([NaN NaN],[NaN NaN],'color',RIGHTCOLOUR,'Tag','end_ax_EndLine');