function [xout, yout] = ydrag(varargin) % ydrag -- Drag points in y-direction only. % ydrag('demo') demonstrates itself. % ydrag(N) demonstrates itself with N points. % [xout, yout] = ydrag(x, y, ...) enables y-dragging % of (x, y) points. Additional arguments are sent intact % to the embedded "PLOT" command. To terminate and return % the data, press any active key, or delete the window by % clicking on its "goaway" box. If no output arguments % are given, "xout" and "yout" are assigned to the caller's % workspace. Note: this routine invokes "zoomsafe" for % systems that have it. % [xout, yout] = ydrag(y, ...) uses a default value of x, % as in the Matlab "PLOT" command. % ... = ydrag(aHandle) enables the line with the given % handle, such as the "gco". % ... = ydrag (no argument) enables an existing line, with % priority given to one that was previously targetted % by this routine. % xyout = ... returns a two-column array of the (x, y) data. % Copyright (C) 2001 Dr. Charles R. Denham, ZYDECO. % All Rights Reserved. % Disclosure without explicit written consent from the % copyright owner does not constitute publication. % Version of 03-Dec-2001 11:35:44. % Updated 04-Dec-2001 11:12:35. persistent theLine persistent thePointIndex persistent oldFigureName persistent oldNumberTitle persistent oldPointer persistent oldCloseRequestFcn persistent deleteFlag CURSOR = 'circle'; if nargout > 0 xout = []; yout = []; end % Demonstration. if nargin == 1 & isequal(varargin{1}, 'demo') help(mfilename) varargin{1} = 10; end if nargin == 1 & ischar(varargin{1}) & any(varargin{1}(1) == '0123456789') varargin{1} = eval(varargin{1}); end if nargin == 1 & length(varargin{1}) == 1 & ~ischar(varargin{1}) xmax = varargin{1}; set(gcf, 'Name', [mfilename ' ' int2str(xmax)]) xdemo = 0:xmax; ydemo = rand(size(xdemo)); xo = []; yo = []; [xo, yo] = feval(mfilename, xdemo, ydemo); if nargout == 1 xout = [xo(:) yo(:)]; elseif nargout == 2 xout = xo; yout = yo; else assignin('caller', 'xout', xo) assignin('caller', 'yout', yo) disp(' ## See results in "xout" and "yout".') end return end % New or existing line. doInitialize = ~~0; if nargin >= 1 & ~ischar(varargin{1}) & length(varargin{1}) > 1 theShadow = plot(varargin{:}); set(theShadow, 'LineStyle', ':') hold on theLine = plot(varargin{:}); if isequal(get(theLine, 'Marker'), 'none') set(theLine, 'Marker', '*', 'MarkerEdgeColor', 'r') end hold off doInitialize = ~~1; elseif nargin == 1 & ~ischar(varargin{1}) & ishandle(varargin{1}) theLine = varargin{1}; doInitialize = ~~1; elseif nargin < 1 h = findobj(gca, 'Type', 'line', 'Tag', mfilename); if ~any(h) h = findobj(gca, 'Type', 'line'); end if ~any(h), return, end theLine = h(1); doInitialize = ~~1; end % Initialize, then wait for keypress. % We need to figure out how to handle % a premature "CloseRequestFcn" callback. if doInitialize & ishandle(theLine) theFigure = gcf; set(theLine, ... 'ButtonDownFcn', [mfilename ' down'], ... 'Tag', mfilename) try zoomsafe on catch end set(theFigure, 'UserData', []) set(theFigure, 'KeyPressFcn', [mfilename ' keypress']) oldCloseRequestFcn = get(theFigure, 'CloseRequestFcn'); set(theFigure, 'CloseRequestFcn', [mfilename ' closereq']) figure(theFigure) try waitfor(theFigure, 'UserData', 'done') % Suspend. catch % Catch any manual interrupt. set(theFigure, 'CloseRequestFcn', oldCloseRequestFcn) feval(mfilename, 'keypress') end if ishandle(theFigure) set(theFigure, 'UserData', []) set(theFigure, 'KeyPressFcn', '') set(theLine, 'ButtonDownFcn', '') if ishandle(theLine) xo = get(theLine, 'XData'); yo = get(theLine, 'YData'); set(theLine, 'ButtonDownFcn', '') if nargout == 1 xout = [x(:) y(:)]; elseif nargout == 2 xout = xo; yout = yo; else assignin('caller', 'xout', xo) assignin('caller', 'yout', yo) disp(' ## See results in "xout" and "yout".') end end if any(deleteFlag) delete(theFigure) end end end if nargin == 1 & ischar(varargin{1}) theCommand = varargin{1}; switch theCommand case 'closereq' deleteFlag = ~~1; set(gcbf, 'UserData', 'done') set(gcbf, 'CloseRequestFcn', oldCloseRequestFcn) case 'keypress' deleteFlag = ~~0; set(gcbf, 'UserData', 'done') set(gcbf, 'CloseRequestFcn', oldCloseRequestFcn) case 'down' xy = get(gca, 'CurrentPoint'); oldFigureName = get(gcbf, 'Name'); oldNumberTitle = get(gcbf, 'NumberTitle'); oldPointer = get(gcbf, 'Pointer'); set(gcbf, 'Name', num2str(xy(1, 2))) set(gcbf, 'NumberTitle', 'off') set(gcbf, 'Pointer', CURSOR) xdown = xy(1, 1); ydown = xy(1, 2); xlim = get(gca, 'XLim'); ylim = get(gca, 'YLim'); xdata = get(theLine, 'XData'); ydata = get(theLine, 'YData'); oldUnits = get(gca, 'Units'); set(gca, 'Units', 'pixels') pos = get(gca, 'Position'); set(gca, 'Units', oldUnits) width = pos(3); height = pos(4); xdist = width * (xdata - xdown) / diff(xlim); ydist = height * (ydata - ydown) / diff(ylim); dist = abs(xdist + sqrt(-1) * ydist); f = find(dist == min(dist)); thePointIndex = f(1); set(gcbf, 'WindowButtonMotionFcn', [mfilename ' motion']) set(gcbf, 'WindowButtonUpFcn', [mfilename ' up']) case 'motion' xy = get(gca, 'CurrentPoint'); set(gcbf, 'Name', num2str(xy(1, 2))) case 'up' xy = get(gca, 'CurrentPoint'); set(gcbf, 'Name', num2str(xy(1, 2))) xup = xy(1, 1); yup = xy(1, 2); ydata = get(theLine, 'YData'); ydata(thePointIndex) = yup; set(theLine, 'YData', ydata); set(gcbf, 'Name', oldFigureName) set(gcbf, 'NumberTitle', oldNumberTitle) set(gcbf, 'Pointer', oldPointer) set(gcbf, 'WindowButtonMotionFcn', '') set(gcbf, 'WindowButtonUpFcn', '') otherwise end end