selectdata: graphical selection of data points on a plot using the mouse usage: pointslist = vb_data_pick_tool % uses all default options usage: pointslist = vb_data_pick_tool(prop1,val1,prop2,val2,...) vb_data_pick_tool allows the user to select data points on a given plot using the mouse, in a variety of modes. 'Lasso' mode allows the selection by a user directed lasso around the points. 'Brush' mode selects points as you brush over them with the mouse. 'Rect' mode draws a rectangle, selecting any points inside the rectangle. 'Closest' mode looks for a aingle mouse click, finding the closest point to the mouse. Returned is a list of the point indexes selected, additionally you can specify that the points be deleted from the plot. Arguments: (input) The input arguments to vb_data_pick_tool are all property/value pairs. (See PARSE_PV_PAIRS for more details.) http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=9082&objectType=FILE Property names and character values can be shortened as long as the shortening is unambiguous. Capitalization is ignored. Valid Properties: 'Action', 'Axes', 'BrushSize', 'Identify', 'Ignore' , 'Pointer', 'SelectionMode' 'Action' - {'list', 'delete'} 'delete' causes the selected points to be deleted from the figure after their selection is final. DEFAULT VALUE: 'List' 'Axes' - denotes the axes from which to select points DEFAULT VALUE: gca 'BrushShape' - {'rect', 'circle'} DEFAULT VALUE: 'circle' Sets the shape of the brush to be used. Both brush shapes are relative to the figure axes, so a nominally "circular" brush is actually elliptical if the axis units/lengths are unequal. Only used when SelectionMode is 'brush'. 'BrushSize' - Only used when SelectionMode is 'brush'. DEFAULT VALUE: 0.05 The default value will specify a rectangular brush that has dimensions of 5% of the current axes. Note that on a set of square axes, the brush will always look square, even if the axes have very different units. 0 < brushsize <= 0.25 'Identify' - {'on', 'off'} Causes the selected points to be temporarily over-plotted with a new filled red marker ('o') as they are selected. Points selected with a lasso, or rect may be deselected as the tool is modified. Brush selections are cumulative. DEFAULT VALUE: 'on' 'Ignore' - a data handle, or [] A list of data handles to be ignored. This allows you to use selectdata on only some sets of points, while others in the same figure are ignored. This is a useful option when you may have plotted some data points but also a curve fit through your data. You can then cause the plotted curve to be ignored by selectdata. DEFAULT VALUE: [] 'Target' - a data handle A list of data handles of target. 'Label' - {'off', 'on'} Causes text labels with their (x,y) coordinates to appear next to each point selected. Beware that selecting large numbers of points and creating and displaying the label for them can be time consuming. This option is a great one for single point selection, but I have seen system-related problems when rapidly selecting & deselecting large numbers of points with the rect tool. DEFAULT VALUE: 'off' 'Pointer' - {'crosshair' | 'fullcrosshair' | 'arrow' | 'ibeam' | 'watch' | 'topl' | 'topr' | 'botl' | 'botr' | 'left' | 'top' | 'right' | 'bottom' | 'circle' | 'cross' | 'fleur' | 'hand' } Changes the cursor pointer while selection is active. After selection terminates, the figure pointer is restored to its old setting. DEFAULT VALUE: 'crosshair' 'Return' - {'selected' | 'unselected' } Selection of data points, perhaps if used to indicate outliers in data, would normally return that set of points selected. But some users may prefer to see the list of points returned to be those points which were NOT selected. DEFAULT VALUE: 'selected' 'SelectionMode' - {'Lasso', 'Brush', 'Rect', 'Closest'} DEFAULT VALUE: 'Lasso' If 'Brush' is used, then the brush will be a rectangular brush, with a size as defined by the 'BrushSize' property. The brush will be centered at the current mouse coordinates. Brush size will be a fraction of the axis limits for the current axes. Click inside the axes, then drag the "brush" around. Any points the brush crosses over will be selected. If 'Lasso' is chosen, then click inside the axes to define one end of the lasso, then drag with the mouse still down, causing the mouse to define a general curvilinear region. The polygon will close automatically when the mouse button is released. A point is "inside" the lasso if inpolygon identifies it as so. BEWARE of convoluted lassos that intersect themselves. If 'Rect' is chosen, then click inside the axes to define one corner of the rect, dragging to specify the opposite corner, just as rbbox would do. If 'Closest' was chosen, then a single mouse click in the figure window is used, then that point which is closest in in Euclidean distance (in window units) is chosen. You can move the cursor around (don't release the mouse until you are done) and the currently selected point will be highlighted. 'Verify' - { 'off' | 'on' } If set to 'on', this causes a dialog box to pop up after selection. The user can then acccept the selection, redo it, or cancel out, causing no points to be selected. Note, if cancel is chosen from the dialog, and 'return' was specify to return those points 'unselected', then ALL the points will actually be returned. DEFAULT VALUE: 'off' Note: other properties are available for use, but I've chosen to leave them semi-hidden because they don't seem terribly useful to most users. These properties allow you to specify the colors of the selection tool itself, the colors of the selected point markers, the transparency of the selection tool, the marker itself, etc. Default values for these parameters are: FlagMarker = 'o' FlagColor = 'r' Fill = 'on' FillColor = 'y' FillEdgeColor = 'b' FillTrans = 0.5 MaxBrush = 0.25 RemoveTool = 'on' RemoveFlagged = 'on' RemoveLabels = 'on' Further documentation on these parameters can be found by editting selectdata.m itself. Arguments: (output) pointslist - list of points that were selected. If only one dataset was found, then points list is a simple vector. If multiple sets of points were found in the axes, then points list will be a cell array. NOTE: Each set of points is peeled off the stach in the matlab stores it. xselect - array (or cell array) containing the x coordinates of those points identified in the selection yselect - array (or cell array) containing the y coordinates of those points identified in the selection Example: Plot a set of points, then select some with the mouse using a rectangular brush, return the indices of those points selected. (Note: user interaction on the plot will be necessary.) x = 0:.1:1; y = x.^2; h = plot(x,y,'o') waitforbuttonpress; pl = vb_data_pick_tool('selectionmode','brush', 'Target', h); Example: Select a single point with the mouse, then delete that selected point from the plot. pl = vb_data_pick_tool('selectionmode','closest','action','delete'); Example: Select some points using a rect(rbbox) tool, also return the (x,y) coordinates from multiple curves plotted. Use shortened versions of the properties and values. h = plot(rand(5,2),rand(5,2),'o'); waitforbuttonpress; [pl,xs,ys] = vb_data_pick_tool('sel','r', 'Target', h); Example: Plot a curve and some data points on one plot, select some points from the data plotted, but ignore the smooth curve, even if the lasso passes over it. x = 0:.01:1; y = exp(x); ynoisy = y + randn(size(y))/2; h1 = plot(x,y,'-'); hold on h2 = plot(x,ynoisy,'o'); waitforbuttonpress; [pl,xs,ys] = vb_data_pick_tool('sel','lasso','Target',h2); See also: Author: John D'Errico E-mail: woodchips@rochester.rr.com Release: 3.0 Release date: 2/19/07 Copyright (c) 2007, John D'Errico All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [History] 2016-02-01 rhayashi Added some options and not to use waitforbuttonpress [Note] Please specify 'Target' option implicitly.
0001 function [pointslist,xselect,yselect] = vb_data_pick_tool(varargin) 0002 % selectdata: graphical selection of data points on a plot using the mouse 0003 % usage: pointslist = vb_data_pick_tool % uses all default options 0004 % usage: pointslist = vb_data_pick_tool(prop1,val1,prop2,val2,...) 0005 % 0006 % vb_data_pick_tool allows the user to select data points on a given plot 0007 % using the mouse, in a variety of modes. 'Lasso' mode allows the 0008 % selection by a user directed lasso around the points. 'Brush' mode 0009 % selects points as you brush over them with the mouse. 'Rect' mode 0010 % draws a rectangle, selecting any points inside the rectangle. 0011 % 'Closest' mode looks for a aingle mouse click, finding the closest 0012 % point to the mouse. 0013 % 0014 % Returned is a list of the point indexes selected, additionally you 0015 % can specify that the points be deleted from the plot. 0016 % 0017 % Arguments: (input) 0018 % The input arguments to vb_data_pick_tool are all property/value pairs. 0019 % (See PARSE_PV_PAIRS for more details.) 0020 % http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=9082&objectType=FILE 0021 % 0022 % Property names and character values can be shortened as long as 0023 % the shortening is unambiguous. Capitalization is ignored. 0024 % 0025 % Valid Properties: 'Action', 'Axes', 'BrushSize', 'Identify', 0026 % 'Ignore' , 'Pointer', 'SelectionMode' 0027 % 0028 % 'Action' - {'list', 'delete'} 0029 % 'delete' causes the selected points to be deleted from 0030 % the figure after their selection is final. 0031 % 0032 % DEFAULT VALUE: 'List' 0033 % 0034 % 'Axes' - denotes the axes from which to select points 0035 % 0036 % DEFAULT VALUE: gca 0037 % 0038 % 'BrushShape' - {'rect', 'circle'} 0039 % 0040 % DEFAULT VALUE: 'circle' 0041 % 0042 % Sets the shape of the brush to be used. Both brush 0043 % shapes are relative to the figure axes, so a nominally 0044 % "circular" brush is actually elliptical if the axis 0045 % units/lengths are unequal. 0046 % 0047 % Only used when SelectionMode is 'brush'. 0048 % 0049 % 'BrushSize' - Only used when SelectionMode is 'brush'. 0050 % 0051 % DEFAULT VALUE: 0.05 0052 % 0053 % The default value will specify a rectangular brush 0054 % that has dimensions of 5% of the current axes. Note 0055 % that on a set of square axes, the brush will always 0056 % look square, even if the axes have very different 0057 % units. 0058 % 0059 % 0 < brushsize <= 0.25 0060 % 0061 % 'Identify' - {'on', 'off'} 0062 % Causes the selected points to be temporarily over-plotted 0063 % with a new filled red marker ('o') as they are selected. 0064 % 0065 % Points selected with a lasso, or rect may be deselected 0066 % as the tool is modified. Brush selections are cumulative. 0067 % 0068 % DEFAULT VALUE: 'on' 0069 % 0070 % 'Ignore' - a data handle, or [] 0071 % 0072 % A list of data handles to be ignored. This allows you to 0073 % use selectdata on only some sets of points, while others 0074 % in the same figure are ignored. This is a useful option 0075 % when you may have plotted some data points but also a 0076 % curve fit through your data. You can then cause the plotted 0077 % curve to be ignored by selectdata. 0078 % 0079 % DEFAULT VALUE: [] 0080 % 0081 % 'Target' - a data handle 0082 % A list of data handles of target. 0083 % 0084 % 'Label' - {'off', 'on'} 0085 % 0086 % Causes text labels with their (x,y) coordinates to appear 0087 % next to each point selected. 0088 % 0089 % Beware that selecting large numbers of points and creating 0090 % and displaying the label for them can be time consuming. 0091 % This option is a great one for single point selection, 0092 % but I have seen system-related problems when rapidly 0093 % selecting & deselecting large numbers of points with the 0094 % rect tool. 0095 % 0096 % DEFAULT VALUE: 'off' 0097 % 0098 % 'Pointer' - {'crosshair' | 'fullcrosshair' | 'arrow' | 'ibeam' | 0099 % 'watch' | 'topl' | 'topr' | 'botl' | 'botr' | 'left' | 0100 % 'top' | 'right' | 'bottom' | 'circle' | 'cross' | 'fleur' | 0101 % 'hand' } 0102 % 0103 % Changes the cursor pointer while selection is active. 0104 % After selection terminates, the figure pointer is 0105 % restored to its old setting. 0106 % 0107 % DEFAULT VALUE: 'crosshair' 0108 % 0109 % 'Return' - {'selected' | 'unselected' } 0110 % 0111 % Selection of data points, perhaps if used to indicate 0112 % outliers in data, would normally return that set of 0113 % points selected. But some users may prefer to see the 0114 % list of points returned to be those points which were 0115 % NOT selected. 0116 % 0117 % DEFAULT VALUE: 'selected' 0118 % 0119 % 'SelectionMode' - {'Lasso', 'Brush', 'Rect', 'Closest'} 0120 % 0121 % DEFAULT VALUE: 'Lasso' 0122 % 0123 % If 'Brush' is used, then the brush will be a rectangular 0124 % brush, with a size as defined by the 'BrushSize' property. 0125 % The brush will be centered at the current mouse coordinates. 0126 % Brush size will be a fraction of the axis limits for the 0127 % current axes. Click inside the axes, then drag the "brush" 0128 % around. Any points the brush crosses over will be selected. 0129 % 0130 % If 'Lasso' is chosen, then click inside the axes to define 0131 % one end of the lasso, then drag with the mouse still down, 0132 % causing the mouse to define a general curvilinear region. 0133 % The polygon will close automatically when the mouse button 0134 % is released. A point is "inside" the lasso if inpolygon 0135 % identifies it as so. BEWARE of convoluted lassos that 0136 % intersect themselves. 0137 % 0138 % If 'Rect' is chosen, then click inside the axes to define 0139 % one corner of the rect, dragging to specify the opposite 0140 % corner, just as rbbox would do. 0141 % 0142 % If 'Closest' was chosen, then a single mouse click in the 0143 % figure window is used, then that point which is closest in 0144 % in Euclidean distance (in window units) is chosen. You 0145 % can move the cursor around (don't release the mouse until 0146 % you are done) and the currently selected point will be 0147 % highlighted. 0148 % 0149 % 'Verify' - { 'off' | 'on' } 0150 % 0151 % If set to 'on', this causes a dialog box to pop up after 0152 % selection. The user can then acccept the selection, redo 0153 % it, or cancel out, causing no points to be selected. 0154 % 0155 % Note, if cancel is chosen from the dialog, and 'return' 0156 % was specify to return those points 'unselected', then ALL 0157 % the points will actually be returned. 0158 % 0159 % DEFAULT VALUE: 'off' 0160 % 0161 % 0162 % Note: other properties are available for use, but I've chosen to 0163 % leave them semi-hidden because they don't seem terribly useful to 0164 % most users. These properties allow you to specify the colors of the 0165 % selection tool itself, the colors of the selected point markers, 0166 % the transparency of the selection tool, the marker itself, etc. 0167 % Default values for these parameters are: 0168 % 0169 % FlagMarker = 'o' 0170 % FlagColor = 'r' 0171 % Fill = 'on' 0172 % FillColor = 'y' 0173 % FillEdgeColor = 'b' 0174 % FillTrans = 0.5 0175 % MaxBrush = 0.25 0176 % RemoveTool = 'on' 0177 % RemoveFlagged = 'on' 0178 % RemoveLabels = 'on' 0179 % 0180 % Further documentation on these parameters can be found by editting 0181 % selectdata.m itself. 0182 % 0183 % 0184 % Arguments: (output) 0185 % pointslist - list of points that were selected. If only one 0186 % dataset was found, then points list is a simple vector. 0187 % If multiple sets of points were found in the axes, then 0188 % points list will be a cell array. 0189 % 0190 % NOTE: Each set of points is peeled off the stach in the 0191 % matlab stores it. 0192 % 0193 % xselect - array (or cell array) containing the x coordinates of 0194 % those points identified in the selection 0195 % 0196 % yselect - array (or cell array) containing the y coordinates of 0197 % those points identified in the selection 0198 % 0199 % 0200 % Example: 0201 % Plot a set of points, then select some with the mouse 0202 % using a rectangular brush, return the indices of those 0203 % points selected. (Note: user interaction on the plot 0204 % will be necessary.) 0205 % 0206 % x = 0:.1:1; 0207 % y = x.^2; 0208 % h = plot(x,y,'o') 0209 % waitforbuttonpress; 0210 % pl = vb_data_pick_tool('selectionmode','brush', 'Target', h); 0211 % 0212 % Example: 0213 % Select a single point with the mouse, then delete that 0214 % selected point from the plot. 0215 % 0216 % pl = vb_data_pick_tool('selectionmode','closest','action','delete'); 0217 % 0218 % Example: 0219 % Select some points using a rect(rbbox) tool, also return 0220 % the (x,y) coordinates from multiple curves plotted. Use 0221 % shortened versions of the properties and values. 0222 % 0223 % h = plot(rand(5,2),rand(5,2),'o'); 0224 % waitforbuttonpress; 0225 % [pl,xs,ys] = vb_data_pick_tool('sel','r', 'Target', h); 0226 % 0227 % Example: 0228 % Plot a curve and some data points on one plot, select 0229 % some points from the data plotted, but ignore the 0230 % smooth curve, even if the lasso passes over it. 0231 % x = 0:.01:1; 0232 % y = exp(x); 0233 % ynoisy = y + randn(size(y))/2; 0234 % h1 = plot(x,y,'-'); 0235 % hold on 0236 % h2 = plot(x,ynoisy,'o'); 0237 % waitforbuttonpress; 0238 % [pl,xs,ys] = vb_data_pick_tool('sel','lasso','Target',h2); 0239 % 0240 % See also: 0241 % 0242 % 0243 % Author: John D'Errico 0244 % E-mail: woodchips@rochester.rr.com 0245 % Release: 3.0 0246 % Release date: 2/19/07 0247 % 0248 % Copyright (c) 2007, John D'Errico 0249 % All rights reserved. 0250 % 0251 % Redistribution and use in source and binary forms, with or without 0252 % modification, are permitted provided that the following conditions are 0253 % met: 0254 % 0255 % * Redistributions of source code must retain the above copyright 0256 % notice, this list of conditions and the following disclaimer. 0257 % * Redistributions in binary form must reproduce the above copyright 0258 % notice, this list of conditions and the following disclaimer in 0259 % the documentation and/or other materials provided with the distribution 0260 % 0261 % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 0262 % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 0263 % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 0264 % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 0265 % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 0266 % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 0267 % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 0268 % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 0269 % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 0270 % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 0271 % POSSIBILITY OF SUCH DAMAGE. 0272 % 0273 % [History] 0274 % 2016-02-01 rhayashi Added some options and not to use waitforbuttonpress 0275 % 0276 % [Note] 0277 % Please specify 'Target' option implicitly. 0278 0279 0280 pointslist = []; 0281 xselect = []; 0282 yselect = []; 0283 0284 % defaults for the parameters 0285 params.Axes = gca; 0286 params.SelectionMode = 'lasso'; 0287 params.Action = 'list'; 0288 params.BrushShape = 'circle'; 0289 params.BrushSize = .05; 0290 params.Identify = 'on'; 0291 params.Ignore = []; 0292 params.Target = []; 0293 params.Pointer = 'cross'; 0294 params.Return = 'selected'; 0295 params.Verify = 'off'; 0296 params.Label = 'off'; 0297 0298 % Undocumented options, also unchecked for validity. 0299 % These parameters control the marker used to identify 0300 % those points which are currently selected. 0301 % FlagMarker must be a valid plot marker, FlagColor 0302 % must be a valid color spec. The default values are... 0303 params.FlagMarker = 'o'; 0304 params.FlagColor = 'r'; 0305 params.FlagEdgeColor = []; 0306 0307 % More (unchecked) options that are yours to fiddle with 0308 % (or not.) These control the fill color to be applied 0309 % to the interior of the lasso, rect, and brush. Also 0310 % controlled are the degree of transparency to be applied. 0311 params.Fill = 'on'; 0312 params.FillColor = 'y'; 0313 params.FillEdgeColor = 'b'; 0314 params.FillTrans = 0.5; % must be in the interval [0,1] 0315 0316 % The maximum relative brushsize allowed is also 0317 % controlled here, just in case I ever wanted to allow 0318 % the brush to be a bit larger. 0319 params.MaxBrush = 0.25; 0320 0321 % After selection has been accomplished, the flagged points 0322 % and the selection tool itself are normally deleted. But 0323 % in some circumstances it may be useful to not delete 0324 % those objects. 'off' will cause these objects to remain. 0325 params.RemoveTool = 'on'; 0326 params.RemoveFlagged = 'on'; 0327 params.RemoveLabels = 'on'; 0328 0329 % save this to restore later 0330 axissize = axis; 0331 0332 % process any Property/value pairs. 0333 if nargin>0 0334 params = parse_pv_pairs(params,varargin); 0335 end 0336 0337 % check the supplied parameters for validity 0338 params = check_params(params); 0339 0340 % bring the focus to the figure containing the 0341 % designated axes 0342 fighandle = get(params.Axes,'parent'); 0343 wbmf = get(fighandle,'WindowButtonMotionFcn'); 0344 wbup = get(fighandle,'WindowButtonUpFcn'); 0345 set(fighandle,'WindowButtonUpFcn',@selectdone); 0346 figure(fighandle); 0347 0348 % User input thread sometime changes application status to 'Stop' 0349 % before running this program.(e.g. very short mouse click) 0350 % if strcmpi(get_app_status(fighandle), 'Stop') 0351 % set_app_status(fighandle, 'Idle'); 0352 % % emergency stop code 0353 % return; 0354 % end 0355 0356 % get the current figure pointer, so we can 0357 % restore it later on 0358 oldpointer = get(fighandle,'Pointer'); 0359 0360 % extract xdata and ydata from the specified axes 0361 % get the children of the axes 0362 hc = get(params.Axes,'children'); 0363 0364 % are any of the data handles to be ignored? 0365 if ~isempty(params.Ignore) && ~isempty(params.Target) 0366 hc = setdiff(hc,params.Ignore); 0367 else 0368 hc = params.Target; 0369 end 0370 0371 % strip out xdata and ydata 0372 xdata = get(hc,'xdata'); 0373 ydata = get(hc,'ydata'); 0374 0375 % if we must highlight the points as they are 0376 % selected, then for efficiency we need to know 0377 % how many we may expect. 0378 flaghandle = []; 0379 if ~iscell(xdata) 0380 xdata = xdata(:); 0381 ydata = ydata(:); 0382 % total number of data points 0383 npoints = length(xdata); 0384 else 0385 for i = 1:length(xdata) 0386 xdata{i} = xdata{i}(:); 0387 ydata{i} = ydata{i}(:); 0388 end 0389 % total number of data points 0390 npoints = cellfun('length',xdata); 0391 end 0392 0393 % for textlabels if desired 0394 texthandles = []; 0395 0396 % set up a while loop in case we need to verify 0397 % satisfaction 0398 selectionflag = true; 0399 0400 while selectionflag 0401 % and the total number currently selected 0402 nsel = 0; 0403 0404 0405 % what SelectionMode was specified 0406 switch params.SelectionMode 0407 case 'closest' 0408 % Find the single closest point (in Euclidean distance) 0409 % to the mouse click 0410 0411 % set the figure pointer 0412 if ~isempty(params.Pointer) 0413 set(fighandle,'Pointer',params.Pointer) 0414 end 0415 0416 % Button Motion and Button Up 0417 set(fighandle,'WindowButtonMotionFcn',@CPmotion); 0418 0419 % dx, dy to scale the distance 0420 dx = (axissize(2) - axissize(1)); 0421 dy = (axissize(4) - axissize(3)); 0422 0423 % current closest point is 0424 cc = get(gca,'CurrentPoint'); 0425 xy = cc(1,1:2); 0426 0427 % what point was closest? 0428 [pointslist,xselect,yselect] = closestpoint(xy,xdata,ydata,dx,dy); 0429 nsel = 1; 0430 0431 % identify any points? 0432 if strcmp(params.Identify,'on') 0433 flagpoints 0434 end 0435 0436 % label them? 0437 if strcmp(params.Label,'on') 0438 maketextlabels 0439 end 0440 0441 % selecthandle is not needed for this mode op operation 0442 selecthandle = []; 0443 0444 0445 % resume. 0446 0447 % all we need to do here is restore the figure pointer 0448 % if we changed it before 0449 if ~isempty(params.Pointer) 0450 set(fighandle,'Pointer',oldpointer) 0451 end 0452 0453 case 'rect' 0454 % Selection rect as a polygon 0455 0456 % mouse click? 0457 % waitforbuttonpress; 0458 0459 % set the figure pointer 0460 if ~isempty(params.Pointer) 0461 set(fighandle,'Pointer',params.Pointer) 0462 end 0463 0464 % button down detected 0465 cc = get(gca,'CurrentPoint'); 0466 rectxy1 = cc(1,1:2); 0467 rectxy2 = rectxy1 + eps(rectxy1); 0468 0469 % make a polygon of the box, initially of nil area 0470 xv = [rectxy1(1), rectxy2(1), rectxy2(1), rectxy1(1), rectxy1(1)]; 0471 yv = [rectxy1(2), rectxy1(2), rectxy2(2), rectxy2(2), rectxy1(2)]; 0472 0473 % no points should been selected 0474 [pointslist,xselect,yselect,nsel] = testpoly(xv,yv,xdata,ydata); 0475 0476 % and plot it, filled or not 0477 hold on 0478 if strcmp(params.Fill,'on') 0479 % filled 0480 selecthandle = fill(xv,yv,params.FillColor); 0481 set(selecthandle,'facealpha',params.FillTrans, ... 0482 'linestyle','--','edgecolor',params.FillEdgeColor) 0483 else 0484 % unfilled 0485 selecthandle = plot(xv,yv,'r:'); 0486 end 0487 0488 % we can undo the hold now 0489 hold off 0490 0491 % Button Motion and Button Up 0492 set(fighandle,'WindowButtonMotionFcn',@rectmotion); 0493 0494 0495 % .... 0496 0497 % resume. 0498 0499 % The rect already is a polygon, stored in (xv,yv) 0500 0501 case 'lasso' 0502 % Selection lasso as a polygon 0503 0504 % mouse click? 0505 % waitforbuttonpress; 0506 0507 % set the figure pointer 0508 if ~isempty(params.Pointer) 0509 set(fighandle,'Pointer',params.Pointer) 0510 end 0511 0512 % button down detected 0513 cc = get(gca,'CurrentPoint'); 0514 xlasso = cc(1,1); 0515 ylasso = cc(1,2); 0516 0517 % form the polygon 0518 xv = xlasso; 0519 yv = ylasso; 0520 0521 % and plot it, filled or not 0522 hold on 0523 if strcmp(params.Fill,'on') 0524 % filled 0525 selecthandle = fill(xv,yv,params.FillColor); 0526 set(selecthandle,'facealpha',params.FillTrans, ... 0527 'linestyle','--','edgecolor',params.FillEdgeColor) 0528 else 0529 % unfilled 0530 selecthandle = plot(xv,yv,'r:'); 0531 end 0532 0533 % we can undo the hold now 0534 hold off 0535 0536 % Button Motion and Button Up 0537 set(fighandle,'WindowButtonMotionFcn',@lassomotion); 0538 0539 % .... 0540 0541 % resume. 0542 0543 % The lasso already is a polygon, stored in (xv,yv) 0544 0545 case 'brush' 0546 % paint over the data, with a rectangular brush 0547 0548 % mouse click? 0549 % waitforbuttonpress; 0550 0551 % set the figure pointer 0552 if ~isempty(params.Pointer) 0553 set(fighandle,'Pointer',params.Pointer) 0554 end 0555 0556 % button down detected 0557 bc = get(gca,'CurrentPoint'); 0558 brushcenter = bc(1,1:2); 0559 0560 % dx, dy for the brush 0561 bdx = params.BrushSize*(axissize(2) - axissize(1)); 0562 bdy = params.BrushSize*(axissize(4) - axissize(3)); 0563 0564 if strcmpi(params.BrushShape,'rect') 0565 % make the brush polygon as a fixed size rectangle 0566 % that we can slide around 0567 xv = brushcenter(1) + [-1, 1, 1, -1, -1]*bdx/2; 0568 yv = brushcenter(2) + [-1, -1, 1, 1, -1]*bdy/2; 0569 else 0570 % a circle was specified 0571 theta = linspace(0,2*pi,100); 0572 xv = cos(theta)*bdx/2 + brushcenter(1); 0573 yv = sin(theta)*bdy/2 + brushcenter(2); 0574 end 0575 0576 % draw the initial brush polygon, filled or not 0577 hold on 0578 if strcmp(params.Fill,'on') 0579 % filled 0580 selecthandle = fill(xv,yv,params.FillColor); 0581 set(selecthandle,'facealpha',params.FillTrans, ... 0582 'linestyle','-','edgecolor',params.FillEdgeColor) 0583 else 0584 % unfilled 0585 selecthandle = plot(xv,yv,'r:'); 0586 end 0587 hold off 0588 0589 % have any points been selected? 0590 [pointslist,xselect,yselect,nsel] = testpoly(xv,yv,xdata,ydata); 0591 0592 % identify any points? 0593 if strcmp(params.Identify,'on') && (nsel>0) 0594 flagpoints 0595 end 0596 0597 % label them? 0598 if strcmp(params.Label,'on') && (nsel>0) 0599 maketextlabels 0600 end 0601 0602 % Button Motion and Button Up 0603 set(fighandle,'WindowButtonMotionFcn',@brushmotion); 0604 0605 % resume. 0606 0607 end 0608 0609 % wait until the selection is done 0610 InputWait(fighandle); 0611 0612 % Finished selection 0613 selectdone; 0614 0615 % verify? 0616 if strcmpi(params.Verify,'on') 0617 % pop up a dialog 0618 ButtonName = questdlg( ... 0619 'Are you satisfied with the points selected?','???', ... 0620 'Yes','Redo Selection','Cancel Selection','Yes'); 0621 0622 switch ButtonName 0623 case 'Yes' 0624 % we can drop through 0625 selectionflag = false; 0626 0627 case 'Cancel Selection' 0628 % drop out, with nothing selected 0629 if ~iscell(xdata) 0630 pointslist = []; 0631 xselect = []; 0632 yselect = []; 0633 else 0634 for i = 1:numel(xdata); 0635 pointslist{i} = []; 0636 xselect{i} = []; 0637 yselect{i} = []; 0638 end 0639 end 0640 0641 % we can drop through 0642 selectionflag = false; 0643 0644 case 'Redo Selection' 0645 % or try again. The while loop will cycle 0646 % until happy or canceled 0647 0648 end 0649 0650 else 0651 % no verification was requested, so we want to 0652 % terminate the while loop after only one pass through. 0653 selectionflag = false; 0654 end 0655 0656 end 0657 0658 % pointslist and xselect, yselect are already complete. 0659 % Do we delete the selected points? 0660 if strcmpi(params.Action,'delete') 0661 if ~iscell(xdata) 0662 % only one set, so xdata and ydata are not cell arrays 0663 0664 % Which points from the data fall in the selection polygon? 0665 xdata(pointslist) = []; 0666 ydata(pointslist) = []; 0667 0668 % drop those points from the plot 0669 set(hc,'xdata',xdata,'ydata',ydata) 0670 else 0671 % it was a cell array, so there were multiple sets. 0672 for i = 1:numel(xdata); 0673 0674 xdata{i}(pointslist{i}) = []; 0675 ydata{i}(pointslist{i}) = []; 0676 0677 % drop those points from the plot 0678 set(hc(i),'xdata',xdata{i},'ydata',ydata{i}) 0679 end 0680 end 0681 end 0682 0683 % was 'return' set to be the selected list or the unselected one? 0684 % Do nothing if 'selected', we are already done. 0685 if strcmpi(params.Return,'unselected') 0686 if ~iscell(xdata) 0687 % only one set, so xdata and ydata are not cell arrays 0688 pointslist = setdiff((1:npoints)',pointslist); 0689 xselect = xdata(pointslist); 0690 yselect = ydata(pointslist); 0691 else 0692 % it was a cell array, so there were multiple sets. 0693 for i = 1:numel(xdata); 0694 pointslist{i} = setdiff((1:npoints(i))',pointslist{i}); 0695 0696 xselect{i} = xdata{i}(pointslist{i}); 0697 yselect{i} = ydata{i}(pointslist{i}); 0698 end 0699 end 0700 end 0701 set(fighandle,'WindowButtonMotionFcn', wbmf); 0702 set(fighandle,'WindowButtonUpFcn', wbup); 0703 0704 % ===================================================== 0705 % begin nested functions 0706 % ===================================================== 0707 function brushmotion(src,evnt) %#ok 0708 % nested function for motion of the brush 0709 0710 % get the new mouse position 0711 mousenew = get(params.Axes,'CurrentPoint'); 0712 mousenew = mousenew(1,1:2); 0713 0714 % make sure the axes are fixed 0715 axis(axissize) 0716 0717 % how far did it move 0718 brushoffset = mousenew - brushcenter; 0719 brushcenter = mousenew; 0720 0721 xv = xv + brushoffset(1); 0722 yv = yv + brushoffset(2); 0723 0724 % did we brush over any new points 0725 [pl,xselect,yselect,nsel] = testpoly(xv,yv,xdata,ydata); 0726 0727 % for a brush, we need to append any selected points to 0728 % the already selected list 0729 if ~iscell(xdata) 0730 % only one set, so xdata and ydata are not cell arrays 0731 pointslist = union(pointslist,pl); 0732 xselect = xdata(pointslist); 0733 yselect = ydata(pointslist); 0734 nsel = length(pointslist); 0735 else 0736 % it was a cell array, so there were multiple sets. 0737 for j = 1:numel(pointslist); 0738 pointslist{j} = union(pointslist{j},pl{j}); %#ok 0739 pointslist{j} = pointslist{j}(:); %#ok 0740 0741 if ~isempty(pointslist{j}) 0742 xselect{j} = xdata{j}(pointslist{j}); 0743 yselect{j} = ydata{j}(pointslist{j}); 0744 end 0745 end 0746 0747 % total of points selected 0748 nsel = sum(cellfun('length',pointslist)); 0749 end 0750 0751 % identify any points? 0752 if strcmp(params.Identify,'on') 0753 flagpoints 0754 end 0755 0756 % label them? 0757 if strcmp(params.Label,'on') 0758 maketextlabels 0759 end 0760 0761 % replot the brush in its new position 0762 set(selecthandle,'xdata',xv,'ydata',yv) 0763 0764 end 0765 % ===================================================== 0766 0767 % ===================================================== 0768 function CPmotion(src,evnt) %#ok 0769 % nested function to select the closest point 0770 0771 % get the new mouse position 0772 mousenew = get(params.Axes,'CurrentPoint'); 0773 xy = mousenew(1,1:2); 0774 0775 % make sure the axes stay fixed 0776 axis(axissize) 0777 0778 % what point was closest? 0779 [pointslist,xselect,yselect] = closestpoint(xy,xdata,ydata,dx,dy); 0780 nsel = 1; 0781 0782 % identify any points? 0783 if strcmp(params.Identify,'on') 0784 flagpoints 0785 end 0786 0787 % label them? 0788 if strcmp(params.Label,'on') 0789 maketextlabels 0790 end 0791 0792 end 0793 % ===================================================== 0794 0795 % ===================================================== 0796 function rectmotion(src,evnt) %#ok 0797 % nested function for expansion or contraction of the rect 0798 0799 % get the new mouse position 0800 mousenew = get(params.Axes,'CurrentPoint'); 0801 rectxy2 = mousenew(1,1:2); 0802 0803 % make sure the axes are fixed 0804 axis(axissize) 0805 0806 % update the rect polygon of the box, changing the second corner 0807 xv = [rectxy1(1), rectxy2(1), rectxy2(1), rectxy1(1), rectxy1(1)]; 0808 yv = [rectxy1(2), rectxy1(2), rectxy2(2), rectxy2(2), rectxy1(2)]; 0809 0810 % did we brush over any new points 0811 [pointslist,xselect,yselect,nsel] = testpoly(xv,yv,xdata,ydata); 0812 0813 % identify any points? 0814 if strcmp(params.Identify,'on') 0815 flagpoints 0816 end 0817 0818 % label them? 0819 if strcmp(params.Label,'on') 0820 maketextlabels 0821 end 0822 0823 % replot the rect in its new position 0824 set(selecthandle,'xdata',xv,'ydata',yv) 0825 0826 end 0827 % ===================================================== 0828 0829 % ===================================================== 0830 function lassomotion(src,evnt) %#ok 0831 % nested function for expansion of the lasso 0832 0833 % get the new mouse position 0834 mousenew = get(params.Axes,'CurrentPoint'); 0835 mousenew = mousenew(1,1:2); 0836 0837 % append the new point on the end of the last lasso 0838 xlasso = [xlasso,mousenew(1,1)]; 0839 ylasso = [ylasso,mousenew(1,2)]; 0840 0841 % and close it to form the polygon 0842 xv = [xlasso,xlasso(1)]; 0843 yv = [ylasso,ylasso(1)]; 0844 0845 % replot the newly extended lasso 0846 set(selecthandle,'xdata',xv,'ydata',yv) 0847 0848 % did we enclose any new points? 0849 [pointslist,xselect,yselect,nsel] = testpoly(xv,yv,xdata,ydata); 0850 0851 % identify any points? 0852 if strcmp(params.Identify,'on') 0853 flagpoints 0854 end 0855 0856 % label them? 0857 if strcmp(params.Label,'on') 0858 maketextlabels 0859 end 0860 0861 % make sure the axes are maintained in size 0862 axis(axissize) 0863 0864 end 0865 % ===================================================== 0866 0867 % ===================================================== 0868 function selectdone(src,evnt) %#ok 0869 % nested function for mouse up 0870 0871 % do we remove the selection tool? 0872 if strcmpi(params.RemoveTool,'on') 0873 % delete the selection object from the plot 0874 if exist('selecthandle', 'var') && ~isempty(selecthandle) 0875 delete(selecthandle); 0876 selecthandle = []; 0877 end 0878 end 0879 0880 % do we remove the flagged points? 0881 if strcmpi(params.RemoveFlagged,'on') 0882 % also remove the flagged/plotted points 0883 if exist('flaghandle', 'var') && ~isempty(flaghandle) 0884 delete(flaghandle) 0885 flaghandle = []; 0886 end 0887 end 0888 0889 % do we remove the flagged points? 0890 if strcmpi(params.RemoveLabels,'on') 0891 % also remove the labels 0892 if exist('texthandles', 'var') && ~isempty(texthandles) 0893 delete(texthandles); 0894 texthandles = []; 0895 end 0896 end 0897 0898 % % cancel the WindowButtonFcn's that we had set 0899 % set(fighandle,'WindowButtonMotionFcn',[]); 0900 % set(fighandle,'WindowButtonUpFcn',[]); 0901 0902 % restore the figure pointer to its original setting 0903 if ~isempty(params.Pointer) && exist('oldpointer', 'var') 0904 set(fighandle,'Pointer',oldpointer) 0905 end 0906 0907 % and resume execution, back in the mainline 0908 Exit(fighandle); 0909 0910 end 0911 % ===================================================== 0912 0913 % ===================================================== 0914 function flagpoints 0915 % nested function for flagging the selected points 0916 0917 % Are these the first points flagged? If so, 0918 % we need to plot them and set the marker, etc. 0919 if isempty(flaghandle) && (nsel > 0) 0920 % hold the figure, so we can add the flagged points 0921 hold on 0922 if isempty(params.FlagEdgeColor) 0923 params.FlagEdgeColor = params.FlagColor; 0924 end 0925 if ~iscell(xselect) 0926 flaghandle = plot(xselect,yselect,params.FlagMarker); 0927 set(flaghandle,'Color',params.FlagColor,'MarkerFaceColor',params.FlagColor,... 0928 'MarkerEdgeColor', params.FlagEdgeColor); 0929 else 0930 flaghandle = plot(vertcat(xselect{:}),vertcat(yselect{:}),params.FlagMarker); 0931 set(flaghandle,'Color',params.FlagColor,'MarkerFaceColor',params.FlagColor,... 0932 'MarkerEdgeColor', params.FlagEdgeColor); 0933 end 0934 % now release the hold 0935 hold off 0936 elseif ~isempty(flaghandle) 0937 % otherwise, we just need to update xdata and ydata 0938 0939 if nsel == 0 0940 set(flaghandle,'xdata',[],'ydata',[]); 0941 0942 elseif ~iscell(xselect) 0943 set(flaghandle,'xdata',xselect,'ydata',yselect); 0944 else 0945 set(flaghandle,'xdata',vertcat(xselect{:}),'ydata',vertcat(yselect{:})); 0946 end 0947 end 0948 end 0949 % ===================================================== 0950 0951 % ===================================================== 0952 function maketextlabels 0953 % nested function for generation of text labels 0954 % over each point selected 0955 0956 % We need to remove the last set of text labels 0957 delete(texthandles) 0958 0959 % creat a new set of handles 0960 if ~iscell(xselect) 0961 xtext = xselect; 0962 ytext = yselect; 0963 else 0964 xtext = vertcat(xselect{:}); 0965 ytext = vertcat(yselect{:}); 0966 end 0967 0968 % anything selected? 0969 if ~isempty(xtext) 0970 textlabels = cell(1,nsel); 0971 for L = 1:nsel 0972 textlabels{L} = ['(',num2str(xtext(L)),',',num2str(ytext(L)),')']; 0973 end 0974 texthandles = text(xtext,ytext,textlabels); 0975 end 0976 end 0977 % ===================================================== 0978 0979 end % mainline end 0980 0981 % ================================================ 0982 % end main function 0983 % ================================================ 0984 0985 % ================================================ 0986 % subfunctions 0987 % ================================================ 0988 function [pl,xsel,ysel,nsel] = testpoly(xv,yv,xdata,ydata) 0989 % checks which points are inside the given polygon 0990 0991 % was there more than one set of points found in the plot? 0992 if ~iscell(xdata) 0993 % only one set, so xdata and ydata are not cell arrays 0994 0995 % Which points from the data fall in the selection polygon? 0996 pl = find(inpolygon(xdata,ydata,xv,yv)); 0997 nsel = length(pl); 0998 0999 xsel = xdata(pl); 1000 ysel = ydata(pl); 1001 else 1002 % it was a cell array, so there were multiple sets. 1003 pl = cell(size(xdata)); 1004 xsel = pl; 1005 ysel = pl; 1006 nsel = 0; 1007 for i = 1:numel(xdata); 1008 pl{i} = find(inpolygon(xdata{i},ydata{i},xv,yv)); 1009 nsel = nsel + length(pl{i}); 1010 1011 if ~isempty(pl{i}) 1012 xsel{i} = xdata{i}(pl{i}); 1013 ysel{i} = ydata{i}(pl{i}); 1014 end 1015 1016 end 1017 end 1018 1019 end % subfunction end 1020 1021 % ================================================ 1022 % subfunction 1023 % ================================================ 1024 function [pointslist,xselect,yselect] = closestpoint(xy,xdata,ydata,dx,dy) 1025 % find the single closest point to xy, in scaled units 1026 if ~iscell(xdata) 1027 % just one set of points to consider 1028 D = sqrt(((xdata - xy(1))/dx).^2 + ((ydata - xy(2))/dy).^2); 1029 [junk,pointslist] = min(D(:)); %#ok 1030 xselect = xdata(pointslist); 1031 yselect = ydata(pointslist); 1032 else 1033 % there is more than one set of points 1034 Dmin = inf; 1035 pointslist = cell(size(xdata)); 1036 for i = 1:numel(xdata); 1037 D = sqrt(((xdata{i} - xy(1))/dx).^2 + ((ydata{i} - xy(2))/dy).^2); 1038 [mind,ind] = min(D(:)); %#ok 1039 1040 if mind < Dmin 1041 % searching for the closest point 1042 Dmin = mind; 1043 1044 pointslist = cell(size(xdata)); 1045 xselect = cell(size(xdata)); 1046 yselect = cell(size(xdata)); 1047 1048 pointslist{i} = ind; 1049 xselect{i} = xdata{i}(ind); 1050 yselect{i} = ydata{i}(ind); 1051 end 1052 end 1053 end 1054 1055 end % subfunction end 1056 1057 % ================================================ 1058 % subfunction 1059 % ================================================ 1060 1061 % ============================================ 1062 % subfunction - check_params 1063 % ============================================ 1064 function par = check_params(par) 1065 % check the parameters for acceptability 1066 % 1067 % Defaults 1068 % Axes = gca; 1069 % SelectionMode = 'lasso'; 1070 % Action = 'list'; 1071 % BrushSize = .05; 1072 1073 % Axes == gca by default 1074 if isempty(par.Axes) 1075 par.Axes = gca; 1076 else 1077 if ~ishandle(par.Axes) 1078 error 'Axes must be the handle to a valid set of axes.' 1079 end 1080 end 1081 1082 % SelectionMode == 'brush' by default 1083 if isempty(par.SelectionMode) 1084 par.SelectionMode = 'brush'; 1085 else 1086 valid = {'rect', 'brush', 'lasso', 'closest'}; 1087 if ~ischar(par.SelectionMode) 1088 error 'Invalid Style: Must be character' 1089 end 1090 1091 ind = strmatch(lower(par.SelectionMode),valid); %#ok 1092 if isempty(ind) || (length(ind)>1) 1093 error(['Invalid SelectionMode: ',par.SelectionMode]) 1094 end 1095 par.SelectionMode = valid{ind}; 1096 end 1097 1098 % BrushShape == 'circle' by default 1099 if isempty(par.BrushShape) 1100 par.BrushShape = 'circle'; 1101 else 1102 valid = {'rect', 'circle'}; 1103 if ~ischar(par.BrushShape) 1104 error 'Invalid Style: Must be character' 1105 end 1106 1107 ind = strmatch(lower(par.BrushShape),valid); %#ok 1108 if isempty(ind) || (length(ind)>1) 1109 error(['Invalid SelectionMode: ',par.BrushShape]) 1110 end 1111 par.BrushShape = valid{ind}; 1112 end 1113 1114 % Action == 'list' by default 1115 if isempty(par.Action) 1116 par.Action = 'list'; 1117 else 1118 valid = {'list', 'delete'}; 1119 if ~ischar(par.Action) 1120 error 'Invalid Action: Must be character' 1121 end 1122 1123 ind = strmatch(lower(par.Action),valid); %#ok 1124 if isempty(ind) || (length(ind)>1) 1125 error(['Invalid Action: ',par.Action]) 1126 end 1127 par.Action = valid{ind}; 1128 end 1129 1130 % Pointer == 'crosshair' by default, but 1131 % if empty, will not change the pointer. 1132 if ~isempty(par.Pointer) 1133 valid = {'crosshair', 'fullcrosshair', 'arrow', 'ibeam', ... 1134 'watch', 'topl', 'topr', 'botl', 'botr', 'left', 'top', ... 1135 'right', 'bottom', 'circle', 'cross', 'fleur', ... 1136 'custom', 'hand'}; 1137 1138 if ~ischar(par.Pointer) 1139 error 'Invalid Pointer: Must be character' 1140 end 1141 1142 ind = strmatch(lower(par.Pointer),valid,'exact'); 1143 if isempty(ind) 1144 ind = strmatch(lower(par.Pointer),valid); %#ok 1145 if isempty(ind) || (length(ind)>1) 1146 error(['Invalid Pointer: ',par.Pointer]) 1147 end 1148 end 1149 par.Pointer = valid{ind}; 1150 end 1151 1152 % Identify == 'on' by default 1153 if isempty(par.Identify) 1154 par.Identify = 'on'; 1155 else 1156 valid = {'on', 'off'}; 1157 if ~ischar(par.Identify) 1158 error 'Value for Identify is invalid: Must be character' 1159 end 1160 1161 ind = strmatch(lower(par.Identify),valid); %#ok 1162 if isempty(ind) || (length(ind)>1) 1163 error(['Invalid Action: ',par.Identify]) 1164 end 1165 par.Identify = valid{ind}; 1166 end 1167 1168 % Label == 'off' by default 1169 if isempty(par.Label) 1170 par.Label = 'off'; 1171 else 1172 valid = {'on', 'off'}; 1173 if ~ischar(par.Label) 1174 error 'Value for Label is invalid: Must be character' 1175 end 1176 1177 ind = strmatch(lower(par.Label),valid); %#ok 1178 if isempty(ind) || (length(ind)>1) 1179 error(['Invalid Action: ',par.Label]) 1180 end 1181 par.Label = valid{ind}; 1182 end 1183 1184 % Return == 'selected' by default 1185 if isempty(par.Return) 1186 par.Return = 'selected'; 1187 else 1188 valid = {'selected', 'unselected'}; 1189 if ~ischar(par.Return) 1190 error 'Value for Return is invalid: Must be character' 1191 end 1192 1193 ind = strmatch(lower(par.Return),valid); %#ok 1194 if isempty(ind) || (length(ind)>1) 1195 error(['Invalid Action: ',par.Return]) 1196 end 1197 par.Return = valid{ind}; 1198 end 1199 1200 % Verify == 'off' by default 1201 if isempty(par.Verify) 1202 par.Verify = 'off'; 1203 else 1204 valid = {'on', 'off'}; 1205 if ~ischar(par.Verify) 1206 error 'Value for Verify is invalid: Must be character' 1207 end 1208 1209 ind = strmatch(lower(par.Verify),valid); %#ok 1210 if isempty(ind) || (length(ind)>1) 1211 error(['Invalid Action: ',par.Verify]) 1212 end 1213 par.Verify = valid{ind}; 1214 end 1215 1216 % BrushSize == 0.05 by default 1217 if isempty(par.BrushSize) 1218 par.BrushSize = 0.05; 1219 else 1220 if (length(par.BrushSize)>1) || (par.BrushSize<=0) || (par.BrushSize>par.MaxBrush) 1221 error 'Brushsize must be scalar, and 0 < BrushSize <= 0.25' 1222 end 1223 end 1224 1225 % Ignore == [] by default 1226 if ~isempty(par.Ignore) && any(~ishandle(par.Ignore)) 1227 error 'Ignore must be empty, or a data handle' 1228 end 1229 1230 end % check_params 1231 1232 1233 % ============================================ 1234 % Included subfunction - parse_pv_pairs 1235 % ============================================ 1236 function params=parse_pv_pairs(params,pv_pairs) 1237 % parse_pv_pairs: parses sets of property value pairs, allows defaults 1238 % usage: params=parse_pv_pairs(default_params,pv_pairs) 1239 % 1240 % arguments: (input) 1241 % default_params - structure, with one field for every potential 1242 % property/value pair. Each field will contain the default 1243 % value for that property. If no default is supplied for a 1244 % given property, then that field must be empty. 1245 % 1246 % pv_array - cell array of property/value pairs. 1247 % Case is ignored when comparing properties to the list 1248 % of field names. Also, any unambiguous shortening of a 1249 % field/property name is allowed. 1250 % 1251 % arguments: (output) 1252 % params - parameter struct that reflects any updated property/value 1253 % pairs in the pv_array. 1254 % 1255 % Example usage: 1256 % First, set default values for the parameters. Assume we 1257 % have four parameters that we wish to use optionally in 1258 % the function examplefun. 1259 % 1260 % - 'viscosity', which will have a default value of 1 1261 % - 'volume', which will default to 1 1262 % - 'pie' - which will have default value 3.141592653589793 1263 % - 'description' - a text field, left empty by default 1264 % 1265 % The first argument to examplefun is one which will always be 1266 % supplied. 1267 % 1268 % function examplefun(dummyarg1,varargin) 1269 % params.Viscosity = 1; 1270 % params.Volume = 1; 1271 % params.Pie = 3.141592653589793 1272 % 1273 % params.Description = ''; 1274 % params=parse_pv_pairs(params,varargin); 1275 % params 1276 % 1277 % Use examplefun, overriding the defaults for 'pie', 'viscosity' 1278 % and 'description'. The 'volume' parameter is left at its default. 1279 % 1280 % examplefun(rand(10),'vis',10,'pie',3,'Description','Hello world') 1281 % 1282 % params = 1283 % Viscosity: 10 1284 % Volume: 1 1285 % Pie: 3 1286 % Description: 'Hello world' 1287 % 1288 % Note that capitalization was ignored, and the property 'viscosity' 1289 % was truncated as supplied. Also note that the order the pairs were 1290 % supplied was arbitrary. 1291 1292 npv = length(pv_pairs); 1293 n = npv/2; 1294 1295 if n~=floor(n) 1296 error 'Property/value pairs must come in PAIRS.' 1297 end 1298 if n<=0 1299 % just return the defaults 1300 return 1301 end 1302 1303 if ~isstruct(params) 1304 error 'No structure for defaults was supplied' 1305 end 1306 1307 % there was at least one pv pair. process any supplied 1308 propnames = fieldnames(params); 1309 lpropnames = lower(propnames); 1310 for i=1:n 1311 p_i = lower(pv_pairs{2*i-1}); 1312 v_i = pv_pairs{2*i}; 1313 1314 ind = strmatch(p_i,lpropnames,'exact'); 1315 if isempty(ind) 1316 ind = find(strncmp(p_i,lpropnames,length(p_i))); 1317 if isempty(ind) 1318 error(['No matching property found for: ',pv_pairs{2*i-1}]) 1319 elseif length(ind)>1 1320 error(['Ambiguous property name: ',pv_pairs{2*i-1}]) 1321 end 1322 end 1323 p_i = propnames{ind}; 1324 1325 % override the corresponding default in params 1326 params = setfield(params,p_i,v_i); %#ok 1327 1328 end 1329 1330 end % parse_pv_pairs 1331 1332 % 1333 % --- Application status 1334 % 1335 function InputWait(fighandle) 1336 set_app_status(fighandle, 'Selecting'); 1337 while(1) 1338 status = get_app_status(fighandle); 1339 if strcmpi(status, 'Stop'); 1340 set_app_status(fighandle, 'Idle'); 1341 %disp('Exit'); 1342 break; 1343 else 1344 % fprintf('S...'); 1345 pause(0.1); 1346 end 1347 end 1348 end 1349 1350 function Exit(fighandle) 1351 %disp('Exit is called'); 1352 set_app_status(fighandle, 'Stop'); 1353 end 1354 1355 function set_app_status(h, status) 1356 setappdata(h, 'selection_status', status); 1357 end 1358 1359 function status = get_app_status(h) 1360 status = getappdata(h, 'selection_status'); 1361 end 1362