% 2D % https://www.mathworks.com/matlabcentral/answers/444743-multiple-bar-plots-and-error-bars clc; close all % Fig. 12b x=0:5:20; meanA = [120.06 202.19 296.29 379.03 498.37]; meanB = [125.35 234.58 317.41 411.57 530.39]; meanC = [190.47 320.13 450.15 534.29 648.12]; meanD = [210.32 345.28 481.74 551.15 682.04]; meanAB = [meanA; meanB]'; meanCD = [meanC; meanD]'; figure(12); plot(x,meanCD,'b--*') xlabel('PMSC content (wt. %)'); yyaxis right ylabel('CO (ppm hr kg-1)'); legend('850 oC','900 oC','850 oC','900 oC'); hold on; plot(x,meanAB,'r--o') xlabel('PMSC content (wt. %)'); yyaxis left ylabel('CO2 (ppm hr kg-1)'); legend('850 oC','900 oC','850 oC','900 oC'); dragzoom function dragzoom(varargin) %DRAGZOOM Drag and zoom tool % https://www.mathworks.com/matlabcentral/fileexchange/29276-dragzoom-drag-and-zoom-tool % % Description: % DRAGZOOM allows you to interactively manage the axes in figure. % This simple function for usable draging and zooming of axes, using the % mouse and the keyboard shortcuts. % % - Supported 2D-Plots, 3D-plots, semilogx-plots, semilogy-plots, loglog-plots and Images; % - Supported subplots (mixed axes). % % ------------------------------------------------------------------------- % Version : 0.9.7 % Author : Evgeny Pr aka iroln % Created : 10.07.10 % Updated : 05.06.11 % % Copyright : Evgeny Pr (c) 2010-2011 % ------------------------------------------------------------------------- % % ****************************** % 2D and Image modes: % ****************************** % - Mouse actions in 2D mode: % -- Normal mode: % "single-click and holding LB" - Activation Drag mode % "single-click and holding RB" - Activation Rubber Band for region zooming % "single-click MB" - Activation 'Extend' Zoom mode % "scroll wheel MB" - Activation Zoom mode % "double-click LB, RB, MB" - Reset to Original View % % -- Magnifier mode: % "single-click LB" - Not Used % "single-click RB" - Not Used % "single-click MB" - Reset Magnifier to Original View % "scroll wheel MB" - Change Magnifier Zoom % "double-click LB" - Increase Magnifier Size % "double-click RB" - Decrease Magnifier Size % % - Hotkeys in 2D mode: % '+' - Zoom plus % '-' - Zoom minus % '0' - Set default axes (reset to original view) % 'uparrow' - Up or down (inrerse) drag % 'downarrow' - Down or up (inverse) drag % 'leftarrow' - Left or right (inverse) drag % 'rightarrow' - Right or left (inverse) drag % 'c' - On/Off Pointer Symbol 'fullcrosshair' % 'g' - On/Off axes grid (only plots) % 's' - On/Off smoothing plots % 'x' - If pressed and holding, zoom and drag works only for X axis % 'y' - If pressed and holding, zoom and drag works only for Y axis % 'm' - If pressed and holding, Magnifier mode on % 'l' - On XY / Off X,Y,XY linking 2-D axes (Synchronize manage) % 'control+l' - On X linking 2-D axes % 'alt+l' - On Y linking 2-D axes hFig = []; hAx = []; hAxes = []; % variables mOrigFigName = []; mOrigCallbacks = []; mAxesInfo = []; mDragStartX = []; mDragStartY = []; mDragKeysX = []; mDragKeysY = []; mDragShiftStep = []; mDragSaveShiftStep = []; mDragShiftStepInc = []; mDragSave3DShiftStep = []; mDrag3DShiftStep = []; mZoomScroll = []; mZoomMinPow = []; mZoomMaxPow = []; mZoomNum = []; mZoomExtendNum = []; mZoomKeysNum = []; mZoom3DExtendNum = []; mZoom3DKeysNum = []; mZoom3DIndex = []; mDefaultZoomGrid = []; mDefaultZoomSteps = []; mZoomGrid = []; mZoomSteps = []; mZoomIndexX = []; mZoomIndexY = []; mZoom3DStartX = []; mZoom3DStartY = []; mZoom3DBindX = []; mZoom3DBindY = []; mDefaultXLim = []; mDefaultYLim = []; mDefaultAxPos = []; mRotStartAZ = []; mRotStartEL = []; mRotStartX = []; mRotStartY = []; mRot3DKeysInc = []; mPointerCross = []; mRubberBand = []; mRbEdgeColor = []; mRbFaceColor = []; mRbFaceAlpha = []; mMagnifier = []; mMgSize = []; mMgMinSize = []; mMgMaxSize = []; mMgZoom = []; mMgMinZoom = []; mMgMaxZoom = []; mMgLinesWidth = []; mMgShadow = []; mMgSizeStep = []; mMgZoomStep = []; mMgDirection = []; mLinkOpt = 'xy'; % flags fIsEnabled = false; fIsSelectedCurrentAxes = true; fIsDragAllowed = false; fIsZoomExtendAllowed = false; fIsZoomExtend3DAllowed = false; fIsRotate3DAllowed = false; fIsRubberBandOn = false; fIsPointerCross = false; fIsAxesGrid = false; fIsSmoothing = false; fIsEnableDragX = true; fIsEnableDragY = true; fIsEnableZoomX = true; fIsEnableZoomY = true; fIsAxes2D = false; fIsImage = false; fIsMagnifierOn = false; fIsLinkAxesOn = false; fIsEnableControl = false; fIsMouseOnLegend = false; % Initialize and Setup Initialize(varargin{:}) %-------------------------------------------------------------------------- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %========================================================================== function Setup() %Setup setup options % Drag Options mDragKeysX = 'normal'; % 'normal', 'reverse' mDragKeysY = 'normal'; % 'normal', 'reverse' mDragShiftStep = 3; % step dragging on keys mDragShiftStepInc = 1; % increase speed dragging on keys mDrag3DShiftStep = 10; % step dragging 3D on keys % Zoom Options mZoomScroll = 'normal'; % 'normal', 'reverse' mZoomMinPow = 0; % min zoom percent 10 ^ mZoomMinPow mZoomMaxPow = 5; % max zoom perzent 10 ^ mZoomMaxPow mZoomNum = 51; % count steps of log zoom grid mZoomExtendNum = 301; % count steps of log grid zoom extend for 2D mZoomKeysNum = 181; % count steps of log grid zoom for keys for 2D mZoom3DExtendNum = 201; % count steps of log grid zoom extend for 3D mZoom3DKeysNum = 181; % count steps of log grid zoom for keys for 3D % Rubber Band Options mRbEdgeColor = 'k'; % rubber band edge color mRbFaceColor = 'none'; % rubber band face color mRbFaceAlpha = 1; % rubber band face alpha (transparency) % Magnifier Options mMgSize = 100; % default size of magnifier (pixels) mMgMinSize = 50; % min size of magnifier mMgMaxSize = 200; % max size of magnifier mMgZoom = 2; % default zoom on magnifier mMgMinZoom = 1; % min zoom on magnifier mMgMaxZoom = 100; % max zoom on magnifier mMgLinesWidth = 1; % lines width on magnifier mMgShadow = 0.95; % shadow area without magnifier mMgSizeStep = 15; % step change in the magnifier size mMgZoomStep = 1.2; % step change in the magnifier zoom % Rotate Options mRot3DKeysInc = 3; % rotate increase for keys end %-------------------------------------------------------------------------- %========================================================================== function Initialize(varargin) %Initialize initialize tool % Parse Input Arguments isWithStatus = ParseInputs(varargin{:}); if isempty(hAxes), return; end hAx = hAxes(1); set(hFig, 'CurrentAxes', hAx); % setup tool Setup(); % initialize tool UserData = get(hFig, 'UserData'); if (isfield(UserData, 'axesinfo') && isWithStatus) mAxesInfo = UserData.axesinfo; mOrigCallbacks = UserData.origcallbacks; mOrigFigName = UserData.origfigname; else % first call dragzoom or call without enable status if ~isfield(UserData, 'origfigname') mOrigFigName = get(hFig, 'Name'); end if isfield(UserData, 'origcallbacks') mOrigCallbacks = UserData.origcallbacks; SetOriginalCallbacks(); end % save original callbacks SaveOriginalCallbacks(); % get info about all axes and create axes info struct mAxesInfo = GetAxesInfo(); % save initialize view for all axes for i = 1:numel(mAxesInfo) resetplotview(mAxesInfo(i).handle, 'InitializeCurrentView'); end UserData.axesinfo = mAxesInfo; UserData.origcallbacks = mOrigCallbacks; UserData.origfigname = mOrigFigName; if ~isfield(UserData, 'tools') UserData.tools.pointercross = mPointerCross; UserData.tools.islinkaxeson = fIsLinkAxesOn; end set(hFig, 'UserData', UserData); end DeleteOldTools(); axi = GetCurrentAxesIndex(); SetCurrentAxes(axi); SetDefaultZoomGrid(); SetFigureName(); mDragSaveShiftStep = mDragShiftStep; mDragSave3DShiftStep = mDrag3DShiftStep; % In case the figure will be saved set(hFig, 'CreateFcn', {@CreateFigureCallback}); if fIsEnabled SetCallbacks(); else SetOriginalCallbacks(); end end %-------------------------------------------------------------------------- %========================================================================== function SaveOriginalCallbacks() %SaveOriginalCallbacks mOrigCallbacks.window_button_down_fcn = get(hFig, 'WindowButtonDownFcn'); mOrigCallbacks.window_button_up_fcn = get(hFig, 'WindowButtonUpFcn'); mOrigCallbacks.window_button_motion_fcn = get(hFig, 'WindowButtonMotionFcn'); mOrigCallbacks.window_scroll_whell_fcn = get(hFig, 'WindowScrollWheelFcn'); mOrigCallbacks.window_key_press_fcn = get(hFig, 'WindowKeyPressFcn'); mOrigCallbacks.window_key_release_fcn = get(hFig, 'WindowKeyReleaseFcn'); mOrigCallbacks.create_fcn = get(hFig, 'CreateFcn'); end %-------------------------------------------------------------------------- %========================================================================== function SetOriginalCallbacks() %SetOriginalCallbacks set(hFig, ... 'WindowButtonDownFcn', mOrigCallbacks.window_button_down_fcn, ... 'WindowButtonUpFcn', mOrigCallbacks.window_button_up_fcn, ... 'WindowButtonMotionFcn', mOrigCallbacks.window_button_motion_fcn, ... 'WindowScrollWheelFcn', mOrigCallbacks.window_scroll_whell_fcn, ... 'WindowKeyPressFcn', mOrigCallbacks.window_key_press_fcn, ... 'WindowKeyReleaseFcn', mOrigCallbacks.window_key_release_fcn, ... 'CreateFcn', mOrigCallbacks.create_fcn); end %-------------------------------------------------------------------------- %========================================================================== function SetCallbacks() %SetCallbacks if fIsAxes2D % 2D mode SetFigureCallbacks2D(); else % 3D mode SetFigureCallbacks3D(); end end %-------------------------------------------------------------------------- %========================================================================== function SetFigureCallbacks2D() %SetFigureCallbacks2D set callback-functions for processing figure events in mode 2D set(hFig, ... 'WindowButtonDownFcn', {@WindowButtonDownCallback2D}, ... 'WindowButtonUpFcn', {@WindowButtonUpCallback2D}, ... 'WindowButtonMotionFcn', {@WindowButtonMotionCallback2D}, ... 'WindowScrollWheelFcn', {@WindowScrollWheelFcn2D}, ... 'WindowKeyPressFcn', {@WindowKeyPressCallback2D}, ... 'WindowKeyReleaseFcn', {@WindowKeyReleaseCallback2D}); end %-------------------------------------------------------------------------- %========================================================================== function SetFigureCallbacks3D() %SetFigureCallbacks3D set callback-functions for processing figure events in mode 3D set(hFig, ... 'WindowButtonDownFcn', {@WindowButtonDownCallback3D}, ... 'WindowButtonUpFcn', {@WindowButtonUpCallback3D}, ... 'WindowButtonMotionFcn', {@WindowButtonMotionCallback3D}, ... 'WindowScrollWheelFcn', {@WindowScrollWheelFcn3D}, ... 'WindowKeyPressFcn', {@WindowKeyPressCallback3D}, ... 'WindowKeyReleaseFcn', {@WindowKeyReleaseCallback3D}); end %-------------------------------------------------------------------------- %========================================================================== function WindowButtonDownCallback2D(src, evnt) %#ok %WindowButtonDownCallback2D if fIsMouseOnLegend, return; end clickType = get(src, 'SelectionType'); switch clickType case 'normal' DragMouseBegin(); mMgDirection = 'plus'; case 'open' if fIsMagnifierOn MagnifierSizeChange(mMgDirection); else ResetAxesToOrigView(); end case 'alt' RubberBandBegin(); mMgDirection = 'minus'; case 'extend' if fIsMagnifierOn MagnifierReset(); else ZoomMouseExtendBegin(); end end end %-------------------------------------------------------------------------- %========================================================================== function WindowButtonUpCallback2D(src, evnt) %#ok %WindowButtonUpCallback2D DragMouseEnd(); ZoomMouseExtendEnd(); RubberBandEnd(); end %-------------------------------------------------------------------------- %========================================================================== function WindowButtonMotionCallback2D(src, evnt) %#ok %WindowButtonMotionCallback2D if ~(fIsMagnifierOn || fIsDragAllowed || fIsRubberBandOn) % set current axes under cursor SelectAxesUnderCursor(); end if fIsEnableControl DragMouse(); RubberBandUpdate(); MagnifierUpdate(); end ZoomMouseExtend(); PointerCrossUpdate(); end %-------------------------------------------------------------------------- %========================================================================== function WindowScrollWheelFcn2D(src, evnt) %#ok %WindowScrollWheelFcn2D if fIsMouseOnLegend, return; end % Update Zoom Info % because it can be changed function 'zoom' UpdateCurrentZoomAxes(); switch mZoomScroll case 'normal' directions = {'minus', 'plus'}; case 'reverse' directions = {'plus', 'minus'}; end verScrollCount = evnt.VerticalScrollCount; if (verScrollCount > 0) direction = directions{1}; elseif (verScrollCount < 0) direction = directions{2}; else return; end % if fIsEnableControl ZoomMouse(direction); PointerCrossUpdate(); % end MagnifierZoomChange(direction); end %-------------------------------------------------------------------------- %========================================================================== function WindowKeyPressCallback2D(src, evnt) %#ok %WindowKeyPressCallback2D modifier = evnt.Modifier; switch evnt.Key case '0' ResetAxesToOrigView(); case {'equal', 'add'} ZoomKeys('plus'); case {'hyphen', 'subtract'} ZoomKeys('minus'); case 'leftarrow' DragKeys('left'); case 'rightarrow' DragKeys('right'); case 'uparrow' DragKeys('up'); case 'downarrow' DragKeys('down'); case 'c' SetPointerCrossKeys(); case 'g' SetAxesGridKeys(); case 'x' DragEnable('y', 'off'); ZoomEnable('y', 'off'); case 'y' DragEnable('x', 'off'); ZoomEnable('x', 'off'); case 'm' if fIsEnableControl MagnifierOn(); end case 'l' SetLinkAxesKeys(modifier); case 's' % smooth plot SetSmoothKeys(); end end %-------------------------------------------------------------------------- %========================================================================== function WindowKeyReleaseCallback2D(src, evnt) %#ok %WindowKeyReleaseCallback2D switch evnt.Key case {'leftarrow', 'rightarrow', 'uparrow', 'downarrow'} mDragShiftStep = mDragSaveShiftStep; case 'x' DragEnable('y', 'on'); ZoomEnable('y', 'on'); case 'y' DragEnable('x', 'on'); ZoomEnable('x', 'on'); case 'm' MagnifierOff(); end end %-------------------------------------------------------------------------- %========================================================================== function WindowButtonDownCallback3D(src, evnt) %#ok %WindowButtonDownCallback3D if fIsMouseOnLegend, return; end clickType = get(src, 'SelectionType'); switch clickType case 'normal' DragMouseBegin3D(); case 'open' ResetAxesToOrigView3D(); case 'alt' RotateMouseBegin3D(); case 'extend' ZoomMouseExtendBegin3D(); end end %-------------------------------------------------------------------------- %========================================================================== function WindowButtonUpCallback3D(src, evnt) %#ok %WindowButtonUpCallback3D DragMouseEnd3D(); ZoomMouseExtendEnd3D(); RotateMouseEnd3D(); end %-------------------------------------------------------------------------- %========================================================================== function WindowButtonMotionCallback3D(src, evnt) %#ok %WindowButtonMotionCallback3D if ~(fIsDragAllowed || fIsZoomExtend3DAllowed || fIsRotate3DAllowed) SelectAxesUnderCursor(); end if fIsEnableControl DragMouse3D(); RotateMouse3D(); end ZoomMouseExtend3D(); end %-------------------------------------------------------------------------- %========================================================================== function WindowScrollWheelFcn3D(src, evnt) %#ok %WindowScrollWheelFcn3D if fIsMouseOnLegend, return; end UpdateCurrentZoomAxes3D(); switch mZoomScroll case 'normal' directions = {'minus', 'plus'}; case 'reverse' directions = {'plus', 'minus'}; end verScrollCount = evnt.VerticalScrollCount; if (verScrollCount > 0) direction = directions{1}; elseif (verScrollCount < 0) direction = directions{2}; else return; end % if fIsEnableControl ZoomMouse3D(direction); % end end %-------------------------------------------------------------------------- %========================================================================== function WindowKeyPressCallback3D(src, evnt) %#ok %WindowKeyPressCallback3D isModifier = ~isempty(intersect(evnt.Modifier, {'control', 'command'})); switch evnt.Key case {'equal', 'add'} ZoomKeys3D('plus'); case {'hyphen', 'subtract'} ZoomKeys3D('minus'); case 'leftarrow' if isModifier DragKeys3D('left'); else RotateKeys3D('az-'); end case 'rightarrow' if isModifier DragKeys3D('right'); else RotateKeys3D('az+'); end case 'uparrow' if isModifier DragKeys3D('up'); else RotateKeys3D('el-'); end case 'downarrow' if isModifier DragKeys3D('down'); else RotateKeys3D('el+'); end case '0' ResetAxesToOrigView3D(); case '1' RotateKeys3D('xy'); case '2' RotateKeys3D('xz'); case '3' RotateKeys3D('yz'); case 'v' VisibleAxesKeys3D(); case 'f' SwitchAspectRatioKeys3D() case 'g' SetAxesGridKeys(); end end %-------------------------------------------------------------------------- %========================================================================== function WindowKeyReleaseCallback3D(src, evnt) %#ok %WindowKeyReleaseCallback3D switch evnt.Key case {'equal', 'add', 'hyphen', 'subtract'} SetDefaultZoomGrid3D(); case {'leftarrow', 'rightarrow', 'uparrow', 'downarrow'} mDrag3DShiftStep = mDragSave3DShiftStep; end end %-------------------------------------------------------------------------- %========================================================================== function CreateFigureCallback(src, evnt) %#ok %CreateFigureCallback hFig = src; UserData = get(hFig, 'UserData'); mAxesInfo = UserData.axesinfo; mOrigCallbacks = UserData.origcallbacks; mOrigFigName = UserData.origfigname; hAxes = arrayfun(@(x) x.handle, mAxesInfo); axi = GetCurrentAxesIndex(); SetCurrentAxes(axi) DeleteOldTools(); end %-------------------------------------------------------------------------- %========================================================================== function SetFigureName() %SetFigureName Set Name of Figure enableStatus = 'off'; if fIsEnabled enableStatus = 'on'; end syncMode = 'Normal'; if fIsLinkAxesOn syncMode = sprintf('Synchronized %s', upper(mLinkOpt)); end sep = ''; if ~isempty(mOrigFigName) sep = ':'; end newName = sprintf('[DRAGZOOM : "%s" (%s)]%s %s', ... enableStatus, syncMode, sep, mOrigFigName); set(hFig, 'Name', newName) end %-------------------------------------------------------------------------- %========================================================================== function DragMouseBegin() %DragMouseBegin begin draging if (~fIsDragAllowed && ~fIsMagnifierOn) [cx, cy] = GetCursorCoordOnWindow(); mDragStartX = cx; mDragStartY = cy; fIsDragAllowed = true; end end %-------------------------------------------------------------------------- %========================================================================== function DragMouseEnd() %DragMouseEnd end draging if fIsDragAllowed fIsDragAllowed = false; end end %-------------------------------------------------------------------------- %========================================================================== function DragMouse() %DragMouse if fIsDragAllowed [cx, cy] = GetCursorCoordOnWindow(); pdx = mDragStartX - cx; pdy = mDragStartY - cy; mDragStartX = cx; mDragStartY = cy; DragAxes(pdx, pdy); end end %-------------------------------------------------------------------------- %========================================================================== function DragKeys(direction) %DragKeys dx = mDragShiftStep; dy = mDragShiftStep; % Increment of speed when you hold the button mDragShiftStep = mDragShiftStep + mDragShiftStepInc; directionsX = {'right', 'left'}; directionsY = {'down', 'up'}; switch mDragKeysX case 'normal' case 'reverse' directionsX = fliplr(directionsX); end switch mDragKeysY case 'normal' case 'reverse' directionsY = fliplr(directionsY); end switch direction case directionsX{1} DragAxes(-dx, 0); case directionsX{2} DragAxes(dx, 0); case directionsY{1} DragAxes(0, dy); case directionsY{2} DragAxes(0, -dy); end PointerCrossUpdate(); end %-------------------------------------------------------------------------- %========================================================================== function DragAxes(pdx, pdy) %DragAxes [xLim, yLim] = GetAxesLimits(); pos = GetObjPos(hAx, 'Pixels'); pbar = get(hAx, 'PlotBoxAspectRatio'); %NOTE: MATLAB Bug? % Fixed problem with AspectRatio and Position of Axes % MATLAB Function PAN is not correct works with rectangular images! % Here it is correctly. imAspectRatioX = pbar(2) / pbar(1); if (imAspectRatioX ~= 1) posAspectRatioX = pos(3) / pos(4); arFactorX = imAspectRatioX * posAspectRatioX; if (arFactorX < 1) arFactorX = 1; end else arFactorX = 1; end imAspectRatioY = pbar(1) / pbar(2); if (imAspectRatioY ~= 1) posAspectRatioY = pos(4) / pos(3); arFactorY = imAspectRatioY * posAspectRatioY; if (arFactorY < 1) arFactorY = 1; end else arFactorY = 1; end if fIsEnableDragX % For log plots, transform to linear scale if strcmp(get(hAx, 'xscale'), 'log') xLim = log10(xLim); xLim = FixInfLogLimits('x', xLim); isXLog = true; else isXLog = false; end dx = pdx * range(xLim) / (pos(3) / arFactorX); xLim = xLim + dx; % For log plots, untransform limits if isXLog xLim = 10.^(xLim); end end if fIsEnableDragY if strcmp(get(hAx, 'yscale'), 'log') yLim = log10(yLim); yLim = FixInfLogLimits('y', yLim); isYLog = true; else isYLog = false; end dy = pdy * range(yLim) / (pos(4) / arFactorY); if fIsImage yLim = yLim - dy; else yLim = yLim + dy; end if isYLog yLim = 10.^(yLim); end end SetAxesLimits(xLim, yLim); end %-------------------------------------------------------------------------- %========================================================================== function DragMouseBegin3D() %DragMouseBegin3D if ~fIsDragAllowed [wcx, wcy] = GetCursorCoordOnWindow('pixels'); mDragStartX = wcx; mDragStartY = wcy; fIsDragAllowed = true; end end %-------------------------------------------------------------------------- %========================================================================== function DragMouseEnd3D() %DragMouseEnd3D if fIsDragAllowed fIsDragAllowed = false; end end %-------------------------------------------------------------------------- %========================================================================== function DragMouse3D() %DragMouse3D if fIsDragAllowed [wcx, wcy] = GetCursorCoordOnWindow('pixels'); dx = mDragStartX - wcx; dy = mDragStartY - wcy; DragAxes3D(dx, dy); mDragStartX = wcx; mDragStartY = wcy; end end %-------------------------------------------------------------------------- %========================================================================== function DragKeys3D(direction) %DragKeys3D dx = mDrag3DShiftStep; dy = mDrag3DShiftStep; mDrag3DShiftStep = mDrag3DShiftStep + mDragShiftStepInc; directionsX = {'right', 'left'}; directionsY = {'down', 'up'}; switch mDragKeysX case 'normal' case 'reverse' directionsX = fliplr(directionsX); end switch mDragKeysY case 'normal' case 'reverse' directionsY = fliplr(directionsY); end switch direction case directionsX{1} DragAxes3D(-dx, 0); case directionsX{2} DragAxes3D(dx, 0); case directionsY{1} DragAxes3D(0, dy); case directionsY{2} DragAxes3D(0, -dy); end end %-------------------------------------------------------------------------- %========================================================================== function DragAxes3D(dx, dy) %DragAxes3D axPos = GetObjPos(hAx, 'pixels'); axPos(1) = axPos(1) - dx; axPos(2) = axPos(2) - dy; SetObjPos(hAx, axPos, 'pixels'); end %-------------------------------------------------------------------------- %========================================================================== function DragEnable(ax, action) %DragEnable switch lower(action) case 'on' tf = true; case 'off' tf = false; end switch lower(ax) case 'x' fIsEnableDragX = tf; case 'y' fIsEnableDragY = tf; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomEnable(ax, action) %ZoomEnable switch lower(action) case 'on' tf = true; case 'off' tf = false; end switch lower(ax) case 'x' fIsEnableZoomX = tf; case 'y' fIsEnableZoomY = tf; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouse(direction) %ZoomMouse zooming axes with mouse if (IsZoomMouseAllowed && ~fIsMagnifierOn) [acx, acy] = GetCursorCoordOnAxes(); ZoomAxes(direction, acx, acy) end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouseExtendBegin() %ZoomMouseExtendBegin if ~fIsZoomExtendAllowed UpdateCurrentZoomAxes(); % set new zoom grid for extend zoom [mZoomGrid, mZoomSteps] = ZoomLogGrid(mZoomMinPow, mZoomMaxPow, mZoomExtendNum); UpdateCurrentZoomAxes(); [wcx, wcy] = GetCursorCoordOnWindow('pixels'); [acx, acy] = GetCursorCoordOnAxes(); mZoom3DStartX = wcx; mZoom3DStartY = wcy; mZoom3DBindX = acx; mZoom3DBindY = acy; fIsZoomExtendAllowed = true; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouseExtendEnd() %ZoomMouseExtendEnd if fIsZoomExtendAllowed % set default zoom grid SetDefaultZoomGrid(); fIsZoomExtendAllowed = false; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouseExtend() %ZoomMouseExtend if fIsZoomExtendAllowed directions = {'minus', 'plus'}; switch mZoomScroll case 'normal' case 'reverse' directions = fliplr(directions); end % Heuristic for pixel change to camera zoom factor % (taken from function ZOOM) [wcx, wcy] = GetCursorCoordOnWindow('pixels'); xy(1) = wcx - mZoom3DStartX; xy(2) = wcy - mZoom3DStartY; q = max(-0.9, min(0.9, sum(xy)/70)) + 1; if (q < 1) direction = directions{1}; elseif (q > 1) direction = directions{2}; else return; end ZoomAxes(direction, mZoom3DBindX, mZoom3DBindY) mZoom3DStartX = wcx; mZoom3DStartY = wcy; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomKeys(direction) %ZoomKeys zooming axes with keyboard UpdateCurrentZoomAxes(); [mZoomGrid, mZoomSteps] = ZoomLogGrid(mZoomMinPow, mZoomMaxPow, mZoomKeysNum); UpdateCurrentZoomAxes(); [acx, acy] = GetCursorCoordOnAxes(); ZoomAxes(direction, acx, acy) PointerCrossUpdate(); SetDefaultZoomGrid(); end %-------------------------------------------------------------------------- %========================================================================== function ZoomAxes(direction, cx, cy) %ZoomAxes Zoom axes in 2D and image modes [xLim, yLim] = GetAxesLimits(); if fIsImage mZoomIndexX = ChangeZoomIndex(direction, mZoomIndexX); mZoomIndexY = mZoomIndexX; zoomPct = GetZoomPercent(mZoomIndexX); xLim = RecalcZoomAxesLimits('x', xLim, mDefaultXLim, cx, zoomPct); yLim = RecalcZoomAxesLimits('y', yLim, mDefaultYLim, cy, zoomPct); else if fIsEnableZoomX mZoomIndexX = ChangeZoomIndex(direction, mZoomIndexX); zoomPct = GetZoomPercent(mZoomIndexX); xLim = RecalcZoomAxesLimits('x', xLim, mDefaultXLim, cx, zoomPct); end if fIsEnableZoomY mZoomIndexY = ChangeZoomIndex(direction, mZoomIndexY); zoomPct = GetZoomPercent(mZoomIndexY); yLim = RecalcZoomAxesLimits('y', yLim, mDefaultYLim, cy, zoomPct); end end SetAxesLimits(xLim, yLim); end %-------------------------------------------------------------------------- %========================================================================== function zoomPct = GetZoomPercent(zoomIndex, zoomGrid) %GetZoomPercent get zoom percent if (nargin < 2) zoomGrid = mZoomGrid; end zoomPct = zoomGrid(zoomIndex); end %-------------------------------------------------------------------------- %========================================================================== function zoomIndex = ChangeZoomIndex(direction, zoomIndex, zoomSteps) %ChangeZoomIndex if (nargin < 3) zoomSteps = mZoomSteps; end switch direction case 'plus' if (zoomIndex < zoomSteps) zoomIndex = zoomIndex + 1; end case 'minus' if (zoomIndex > 1) zoomIndex = zoomIndex - 1; end end end %-------------------------------------------------------------------------- %========================================================================== function axLim = RecalcZoomAxesLimits(ax, axLim, axLimDflt, zcCrd, zoomPct) %RecalcZoomAxesLimits recalc axes limits if strcmp(get(hAx, [ax, 'scale']), 'log') axLim = log10(axLim); axLim = FixInfLogLimits(ax, axLim); axLimDflt = log10(axLimDflt); zcCrd = log10(zcCrd); isLog = true; else isLog = false; end if (zcCrd < axLim(1)), zcCrd = axLim(1); end if (zcCrd > axLim(2)), zcCrd = axLim(2); end rf = range(axLim); ra = range([axLim(1), zcCrd]); rb = range([zcCrd, axLim(2)]); cfa = ra / rf; cfb = rb / rf; newRange = range(axLimDflt) * 100 / zoomPct; dRange = newRange - rf; axLim(1) = axLim(1) - dRange * cfa; axLim(2) = axLim(2) + dRange * cfb; if isLog axLim = 10.^axLim; end end %-------------------------------------------------------------------------- %========================================================================== function UpdateCurrentZoomAxes() %UpdateCurrentZoomAxes [xLim, yLim] = GetAxesLimits(); [curentZoomX, curentZoomY] = GetCurrentZoomAxesPercent(xLim, yLim); if (curentZoomX ~= GetZoomPercent(mZoomIndexX)) [nu, mZoomIndexX] = min(abs(mZoomGrid - curentZoomX)); %#ok ([~, ...]) end if (curentZoomY ~= GetZoomPercent(mZoomIndexY)) [nu, mZoomIndexY] = min(abs(mZoomGrid - curentZoomY)); %#ok ([~, ...]) end end %-------------------------------------------------------------------------- %========================================================================== function [curentZoomX, curentZoomY] = GetCurrentZoomAxesPercent(xLim, yLim) %GetCurrentZoomAxesPercent if strcmp(get(hAx, 'xscale'), 'log') xLim = log10(xLim); defaultXLim = log10(mDefaultXLim); else defaultXLim = mDefaultXLim; end if strcmp(get(hAx, 'yscale'), 'log') yLim = log10(yLim); defaultYLim = log10(mDefaultYLim); else defaultYLim = mDefaultYLim; end curentZoomX = range(defaultXLim) * 100 / range(xLim); curentZoomY = range(defaultYLim) * 100 / range(yLim); end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouse3D(direction) %ZoomMouse3D if IsZoomMouseAllowed [wcx, wcy] = GetCursorCoordOnWindow('pixels'); ZoomAxes3D(direction, wcx, wcy) end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouseExtendBegin3D() %ZoomMouseExtendBegin3D if ~fIsZoomExtend3DAllowed UpdateCurrentZoomAxes3D(); [wcx, wcy] = GetCursorCoordOnWindow('pixels'); % set new zoom grid for extend zoom SetNewZoomGrid3D(mZoomMinPow, mZoomMaxPow, mZoom3DExtendNum); mZoom3DStartX = wcx; mZoom3DStartY = wcy; mZoom3DBindX = wcx; mZoom3DBindY = wcy; fIsZoomExtend3DAllowed = true; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouseExtendEnd3D() %ZoomMouseExtendEnd3D if fIsZoomExtend3DAllowed SetDefaultZoomGrid3D(); fIsZoomExtend3DAllowed = false; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomMouseExtend3D() %ZoomMouseExtended3D if fIsZoomExtend3DAllowed directions = {'minus', 'plus'}; switch mZoomScroll case 'normal' case 'reverse' directions = fliplr(directions); end % Heuristic for pixel change to camera zoom factor % (taken from function ZOOM) [wcx, wcy] = GetCursorCoordOnWindow('pixels'); xy(1) = wcx - mZoom3DStartX; xy(2) = wcy - mZoom3DStartY; q = max(-0.9, min(0.9, sum(xy)/70)) + 1; if (q < 1) direction = directions{1}; elseif (q > 1) direction = directions{2}; else return; end ZoomAxes3D(direction, mZoom3DBindX, mZoom3DBindY) mZoom3DStartX = wcx; mZoom3DStartY = wcy; end end %-------------------------------------------------------------------------- %========================================================================== function ZoomAxes3D(direction, cx, cy) %ZoomAxes3D mZoom3DIndex = ChangeZoomIndex(direction, mZoom3DIndex, mZoomSteps); zoomPct = GetZoomPercent(mZoom3DIndex, mZoomGrid); axPos = GetObjPos(hAx, 'pixels'); [axPos(1), axPos(3)] = RecalcZoomAxesPos3D(axPos(1), axPos(3), ... mDefaultAxPos(3), cx, zoomPct); [axPos(2), axPos(4)] = RecalcZoomAxesPos3D(axPos(2), axPos(4), ... mDefaultAxPos(4), cy, zoomPct); SetObjPos(hAx, axPos, 'pixels'); end %-------------------------------------------------------------------------- %========================================================================== function [npc, nsz] = RecalcZoomAxesPos3D(pc, sz, dfltSz, zcCrd, zoomPct) %RecalcZoomAxesPos3D dd = dfltSz * zoomPct / 100 - sz; rng = range([pc zcCrd]); cf = rng / sz; nsz = sz + dd; npc = pc - dd * cf; end %-------------------------------------------------------------------------- %========================================================================== function UpdateCurrentZoomAxes3D() %UpdateCurrentZoomAxes3D curentZoom = GetCurrentZoomAxesPercent3D(); [nu, mZoom3DIndex] = min(abs(mZoomGrid - curentZoom)); %#ok ([~, ...]) end %-------------------------------------------------------------------------- %========================================================================== function currentZoom = GetCurrentZoomAxesPercent3D() %GetCurrentZoomAxesPercent3D axPos = GetObjPos(hAx, 'pixels'); currentZoom = axPos(3) / mDefaultAxPos(3) * 100; end %-------------------------------------------------------------------------- %========================================================================== function ZoomKeys3D(direction) %ZoomKeys3D UpdateCurrentZoomAxes3D(); SetNewZoomGrid3D(mZoomMinPow, mZoomMaxPow, mZoom3DKeysNum); [wcx, wcy] = GetCursorCoordOnWindow('pixels'); ZoomAxes3D(direction, wcx, wcy) end %-------------------------------------------------------------------------- %========================================================================== function SetNewZoomGrid3D(minPow, maxPow, num) %SetNewZoomGrid3D set new zoom grid for 3D mode [mZoomGrid, mZoomSteps] = ZoomLogGrid(minPow, maxPow, num); UpdateCurrentZoomAxes3D(); end %-------------------------------------------------------------------------- %========================================================================== function SetDefaultZoomGrid() %SetDefaultZoomGrid set default zoom grid [mDefaultZoomGrid, mDefaultZoomSteps] = ... ZoomLogGrid(mZoomMinPow, mZoomMaxPow, mZoomNum); mZoomGrid = mDefaultZoomGrid; mZoomSteps = mDefaultZoomSteps; mZoomIndexX = find(mZoomGrid == 100); mZoomIndexY = mZoomIndexX; mZoom3DIndex = mZoomIndexX; end %-------------------------------------------------------------------------- %========================================================================== function SetDefaultZoomGrid3D() %SetDefaultZoomGrid for 3D mode mZoomGrid = mDefaultZoomGrid; mZoomSteps = mDefaultZoomSteps; UpdateCurrentZoomAxes3D(); end %-------------------------------------------------------------------------- %========================================================================== function VisibleAxesKeys3D() %VisibleAxesKeys3D axi = GetCurrentAxesIndex(); if mAxesInfo(axi).isvisible set(hAx, 'Visible', 'off'); mAxesInfo(axi).isvisible = false; else set(hAx, 'Visible', 'on'); mAxesInfo(axi).isvisible = true; end end %-------------------------------------------------------------------------- %========================================================================== function SwitchAspectRatioKeys3D() %SwitchAspectRatioKeys3D axi = GetCurrentAxesIndex(); if mAxesInfo(axi).isvis3d axis(hAx, 'normal'); mAxesInfo(axi).isvis3d = false; else axis(hAx, 'vis3d'); mAxesInfo(axi).isvis3d = true; end end %-------------------------------------------------------------------------- %========================================================================== function RotateMouseBegin3D() %RotateMouseBegin3D if ~fIsRotate3DAllowed [wcx, wcy] = GetCursorCoordOnWindow('pixels'); [az, el] = view(hAx); mRotStartAZ = az; mRotStartEL = el; mRotStartX = wcx; mRotStartY = wcy; fIsRotate3DAllowed = true; end end %-------------------------------------------------------------------------- %========================================================================== function RotateMouseEnd3D() %RotateMouseEnd3D if fIsRotate3DAllowed fIsRotate3DAllowed = false; end end %-------------------------------------------------------------------------- %========================================================================== function RotateMouse3D() %RotateMouse3D if fIsRotate3DAllowed [wcx, wcy] = GetCursorCoordOnWindow('pixels'); dAZ = mRotStartX - wcx; dEL = mRotStartY - wcy; az = mRotStartAZ + dAZ; el = mRotStartEL + dEL; SetView3D(az, el); end end %-------------------------------------------------------------------------- %========================================================================== function RotateKeys3D(mode) %RotateKeys3D [az, el] = view(hAx); switch lower(mode) case 'xy' az = 0; el = 90; case 'xz' az = 0; el = 0; case 'yz' az = 90; el = 0; case 'az+' az = az + mRot3DKeysInc; case 'az-' az = az - mRot3DKeysInc; case 'el+' el = el + mRot3DKeysInc; case 'el-' el = el - mRot3DKeysInc; end SetView3D(az, el) end %-------------------------------------------------------------------------- %========================================================================== function SetView3D(az, el) %SetView3D if (el > 90), el = 90; end if (el < -90), el = -90; end view(hAx, [az, el]); end %-------------------------------------------------------------------------- %========================================================================== function PointerCrossOn() %PointerCrossOn if ~fIsPointerCross SetPointer('fullcrosshair'); % text objects h = [ text('Parent', hAx) % left text('Parent', hAx) % right text('Parent', hAx) % bottom text('Parent', hAx) % top ]; % create pointer cross struct mPointerCross = struct(... 'htext', h, ... 'left', 1, ... 'right', 2, ... 'bottom', 3, ... 'top', 4); PointerCrossSetup(); fIsPointerCross = true; PointerCrossUpdate(); end end %-------------------------------------------------------------------------- %========================================================================== function PointerCrossOff() %PointerCrossOff if fIsPointerCross delete(mPointerCross.htext); SetPointer('arrow'); fIsPointerCross = false; mPointerCross = []; end end %-------------------------------------------------------------------------- %========================================================================== function PointerCrossSetup() %PointerCrossSetup left = mPointerCross.left; right = mPointerCross.right; bottom = mPointerCross.bottom; top = mPointerCross.top; vabt = {'top', 'bottom'}; if fIsImage vabt = fliplr(vabt); end set(mPointerCross.htext(left), 'VerticalAlignment', 'bottom'); set(mPointerCross.htext(right), 'VerticalAlignment', 'bottom'); set(mPointerCross.htext(bottom), 'VerticalAlignment', vabt{1}); set(mPointerCross.htext(top), 'VerticalAlignment', vabt{2}); bgColor = [251 248 230]/255; set(mPointerCross.htext(left), 'BackgroundColor', bgColor); set(mPointerCross.htext(right), 'BackgroundColor', bgColor); set(mPointerCross.htext(bottom), 'BackgroundColor', bgColor); set(mPointerCross.htext(top), 'BackgroundColor', bgColor); edColor = [180 180 180]/255; set(mPointerCross.htext(left), 'EdgeColor', edColor); set(mPointerCross.htext(right), 'EdgeColor', edColor); set(mPointerCross.htext(bottom), 'EdgeColor', edColor); set(mPointerCross.htext(top), 'EdgeColor', edColor); end %-------------------------------------------------------------------------- %========================================================================== function PointerCrossUpdate() %PointerCrossUpdate if fIsPointerCross [xlim, ylim] = GetAxesLimits(); [acx, acy] = GetCursorCoordOnAxes(); left = mPointerCross.left; right = mPointerCross.right; bottom = mPointerCross.bottom; top = mPointerCross.top; if fIsImage xValStr = sprintf(' %d ', round(acx)); yValStr = sprintf(' %d ', round(acy)); else xtick = get(hAx, 'XTick'); ytick = get(hAx, 'YTick'); %FIXME: prth = 5; [lenTick, maxi] = max(arrayfun(@(x) length(num2str(x)), xtick)); atick = abs(xtick(maxi)); flt = mod(atick, 1); if (flt == 0) countDigX = lenTick + 1; if countDigX > prth countDigX = prth; end else countDigX = length(num2str(atick)); if (fix(acx) == 0) countDigX = countDigX - 1; end end [lenTick, maxi] = max(arrayfun(@(x) length(num2str(x)), ytick)); atick = abs(ytick(maxi)); flt = mod(atick, 1); if (flt == 0) countDigY = lenTick + 1; if countDigY > prth countDigY = prth; end else countDigY = length(num2str(atick)); if (fix(acy) == 0) countDigY = countDigY - 1; end end xValStr = sprintf(' %.*g ', countDigX, acx); yValStr = sprintf(' %.*g ', countDigY, acy); end set(mPointerCross.htext(left), 'String', yValStr); set(mPointerCross.htext(right), 'String', yValStr); set(mPointerCross.htext(bottom), 'String', xValStr); set(mPointerCross.htext(top), 'String', xValStr); extent = get(mPointerCross.htext(left), 'Extent'); xx = extent(3); if strcmp(get(hAx, 'xscale'), 'log') leftx = xlim(1); else leftx = xlim(1) - xx; end set(mPointerCross.htext(left), 'Position', [leftx, acy]); set(mPointerCross.htext(right), 'Position', [xlim(2) acy]); set(mPointerCross.htext(bottom), 'Position', [acx, ylim(1)]); set(mPointerCross.htext(top), 'Position', [acx, ylim(2)]); end end %-------------------------------------------------------------------------- %========================================================================== function RubberBandBegin() %RubberBandBegin if (~fIsRubberBandOn && ~fIsMagnifierOn) [acx, acy] = GetCursorCoordOnAxes(); % create rubber band struct mRubberBand = struct(... 'obj', [patch('Parent', hAx), patch('Parent', hAx)], ... 'x1', acx, ... 'y1', acy, ... 'x2', acx, ... 'y2', acy); hAxes2d = GetHandlesAxes2D(); if ~isempty(hAxes2d) set(hAxes2d, ... 'XLimMode', 'manual', ... 'YLimMode', 'manual'); end RubberBandSetPos(); RubberBandSetup(); fIsRubberBandOn = true; end end %-------------------------------------------------------------------------- %========================================================================== function RubberBandEnd() %RubberBandEnd if fIsRubberBandOn fIsRubberBandOn = false; delete(mRubberBand.obj); RubberBandZoomAxes(); PointerCrossUpdate(); mRubberBand = []; end end %-------------------------------------------------------------------------- %========================================================================== function RubberBandUpdate() %RubberBandUpdate if fIsRubberBandOn [acx, acy] = GetCursorCoordOnAxes(); mRubberBand.x2 = acx; mRubberBand.y2 = acy; RubberBandSetPos(); end end %-------------------------------------------------------------------------- %========================================================================== function RubberBandSetPos() %RubberBandSetPos set position of rubber band x1 = mRubberBand.x1; y1 = mRubberBand.y1; x2 = mRubberBand.x2; y2 = mRubberBand.y2; set(mRubberBand.obj, ... 'XData', [x1 x2 x2 x1], ... 'YData', [y1 y1 y2 y2]); end %-------------------------------------------------------------------------- %========================================================================== function RubberBandSetup() %RubberBandSetup set(mRubberBand.obj(1), ... 'EdgeColor', 'w', ... 'FaceColor', 'none', ... 'LineWidth', 1.5, ... 'LineStyle', '-'); set(mRubberBand.obj(2), ... 'EdgeColor', mRbEdgeColor, ... 'FaceColor', mRbFaceColor, ... 'FaceAlpha', mRbFaceAlpha, ... 'LineWidth', 0.5, ... 'LineStyle', '-'); end %-------------------------------------------------------------------------- %========================================================================== function RubberBandZoomAxes() %RubberBandZoomAxes apply zoom from rubber band xLim = sort([mRubberBand.x1, mRubberBand.x2]); yLim = sort([mRubberBand.y1, mRubberBand.y2]); if (range(xLim) == 0 || range(yLim) == 0) return; end [zoomPctX, zoomPctY] = GetCurrentZoomAxesPercent(xLim, yLim); if fIsImage zoomPctX = min(zoomPctX, zoomPctY); zoomPctY = zoomPctX; end cx = mean(xLim); cy = mean(yLim); xLim = RecalcZoomAxesLimits('x', xLim, mDefaultXLim, cx, zoomPctX); yLim = RecalcZoomAxesLimits('y', yLim, mDefaultYLim, cy, zoomPctY); SetAxesLimits(xLim, yLim); end %-------------------------------------------------------------------------- %========================================================================== function MagnifierOn() %MagnifierCreate if ~fIsMagnifierOn if fIsPointerCross isPointerCross = true; PointerCrossOff(); else isPointerCross = false; end mMgDirection = 'plus'; % create magnifier struct mMagnifier = struct(... 'obj', copyobj(hAx, hFig), ... 'frame_obj', [], ... 'size', mMgSize, ... 'zoom', mMgZoom); fIsMagnifierOn = true; MagnifierSetup(); MagnifierUpdate(); if isPointerCross PointerCrossOn(); end end end %-------------------------------------------------------------------------- %========================================================================== function MagnifierOff() %MagnifierOff if fIsMagnifierOn fIsMagnifierOn = false; set(hAx, 'Color', get(mMagnifier.obj, 'Color')); delete(mMagnifier.obj); mMagnifier = []; end end %-------------------------------------------------------------------------- %========================================================================== function MagnifierUpdate() %MagnifierUpdate if fIsMagnifierOn % see original idea of magnify by Rick Hindman -- 7/29/04 % http://www.mathworks.com/matlabcentral/fileexchange/5961 [acx, acy] = GetCursorCoordOnAxes(); [wcx, wcy] = GetCursorCoordOnWindow('pixels'); [xLim, yLim] = GetAxesLimits(); if strcmp(get(hAx, 'xscale'), 'log') xLim = log10(xLim); xLim = FixInfLogLimits('x', xLim); acx = log10(acx); isXLog = true; else isXLog = false; end if strcmp(get(hAx, 'yscale'), 'log') yLim = log10(yLim); yLim = FixInfLogLimits('y', yLim); acy = log10(acy); isYLog = true; else isYLog = false; end figPos = GetObjPos(hFig, 'pixels'); axPos = GetObjPos(hAx, 'normalized'); % always square magnifier pbar = get(hAx, 'PlotBoxAspectRatio'); af = pbar(1) / pbar(2); if (af == 1 && (pbar(1) == 1 && pbar(2) == 1)) af = figPos(3) / figPos(4); end mgSizePix = round(mMagnifier.size); mgZoom = mMagnifier.zoom; mgSize = mgSizePix / figPos(3); % normalized size mgPos(3) = mgSize * 2; mgPos(4) = mgPos(3) * af; mg3 = round(mgPos(3) * figPos(3)); mg4 = round(mgPos(4) * figPos(4)); if (mg4 < mg3) mgSize = (mgSizePix * (mg3 / mg4)) / figPos(3); end mgPos(3) = mgSize * 2; mgPos(4) = mgPos(3) * af; mgPos(1) = wcx / figPos(3) - mgSize; mgPos(2) = wcy / figPos(4) - mgSize * af; mgXLim = acx + (1 / mgZoom) * (mgPos(3) / axPos(3)) * diff(xLim) * [-0.5 0.5]; mgYLim = acy + (1 / mgZoom) * (mgPos(4) / axPos(4)) * diff(yLim) * [-0.5 0.5]; SetObjPos(mMagnifier.obj, mgPos, 'normalized'); if isXLog mgXLim = 10.^mgXLim; end if isYLog mgYLim = 10.^mgYLim; end set(mMagnifier.obj, ... 'XLim', mgXLim, ... 'YLim', mgYLim); MagnifierBorderUpdate(); end end %-------------------------------------------------------------------------- %========================================================================== function MagnifierSetup() %MagnifierSetup set(mMagnifier.obj, ... 'Box', 'on', ... 'XMinorTick', 'on', ... 'YMinorTick', 'on'); title(mMagnifier.obj, ''); xlabel(mMagnifier.obj, ''); ylabel(mMagnifier.obj, ''); if fIsImage mMagnifier.frame_obj = ... [patch('Parent', mMagnifier.obj), ... patch('Parent', mMagnifier.obj)]; set(mMagnifier.frame_obj, 'FaceColor', 'none'); set(mMagnifier.frame_obj(1), ... 'LineWidth', 1.5, ... 'EdgeColor', 'w') set(mMagnifier.frame_obj(2), ... 'LineWidth', 1, ... 'EdgeColor', 'k') MagnifierBorderUpdate(); end hLines = findobj(mMagnifier.obj, 'Type', 'line'); if ~isempty(hLines) if (mMgLinesWidth ~= 1) set(hLines, 'LineWidth', mMgLinesWidth); end end set(hAx, 'Color', get(hAx, 'Color')*mMgShadow); end %-------------------------------------------------------------------------- %========================================================================== function MagnifierBorderUpdate() %MagnifierBorderUpdate if fIsImage x = get(mMagnifier.obj, 'XLim'); y = get(mMagnifier.obj, 'YLim'); set(mMagnifier.frame_obj, ... 'XData', [x(1) x(2) x(2) x(1)], ... 'YData', [y(1) y(1) y(2) y(2)]); end end %-------------------------------------------------------------------------- %========================================================================== function MagnifierSizeChange(direction) %MagnifierSizeChange if fIsMagnifierOn switch direction case 'plus' if (mMagnifier.size < mMgMaxSize) mMagnifier.size = mMagnifier.size + mMgSizeStep; end case 'minus' if (mMagnifier.size > mMgMinSize) mMagnifier.size = mMagnifier.size - mMgSizeStep; end end MagnifierUpdate(); end end %-------------------------------------------------------------------------- %========================================================================== function MagnifierZoomChange(direction) %MagnifierZoomChange if fIsMagnifierOn switch direction case 'plus' if (mMagnifier.zoom < mMgMaxZoom) mMagnifier.zoom = mMagnifier.zoom * mMgZoomStep; end case 'minus' if (mMagnifier.zoom > mMgMinZoom) mMagnifier.zoom = mMagnifier.zoom / mMgZoomStep; end end MagnifierUpdate(); end end %-------------------------------------------------------------------------- %========================================================================== function MagnifierReset() %MagnifierReset if fIsMagnifierOn mMagnifier.size = mMgSize; mMagnifier.zoom = mMgZoom; MagnifierUpdate(); end end %-------------------------------------------------------------------------- %========================================================================== function SetLinkAxesKeys(modifier) %SetLinkAxesKeys Set Linking of 2-D axes if isempty(modifier) mLinkOpt = 'xy'; else switch modifier{1} case 'control' mLinkOpt = 'x'; case 'alt' mLinkOpt = 'y'; end end if fIsLinkAxesOn LinkAxesOff(); else LinkAxesOn(); end UserData = get(hFig, 'UserData'); UserData.tools.islinkaxeson = fIsLinkAxesOn; set(hFig, 'UserData', UserData); end %-------------------------------------------------------------------------- %========================================================================== function LinkAxesOn() %LinkAxesOn On of 2-D axes linking if ~fIsLinkAxesOn hAxes2d = GetHandlesAxes2D(); if (length(hAxes2d) > 1) linkaxes(hAxes2d, mLinkOpt); fIsLinkAxesOn = true; SetFigureName(); end end end %-------------------------------------------------------------------------- %========================================================================== function LinkAxesOff() %LinkAxesOff Off of 2-D axes linking if fIsLinkAxesOn fIsLinkAxesOn = false; SetFigureName(); hAxes2d = GetHandlesAxes2D(); linkaxes(hAxes2d, 'off'); end end %-------------------------------------------------------------------------- %========================================================================== function DeleteOldTools() %DeleteOldTools UserData = get(hFig, 'UserData'); if (~isempty(UserData) && isfield(UserData, 'tools')) if ~isempty(UserData.tools.pointercross) mPointerCross = UserData.tools.pointercross; fIsPointerCross = true; PointerCrossOff(); UserData.tools.pointercross = []; end if UserData.tools.islinkaxeson fIsLinkAxesOn = true; LinkAxesOff(); UserData.tools.islinkaxeson = false; end set(hFig, 'UserData', UserData); end end %-------------------------------------------------------------------------- %========================================================================== function hAxes2d = GetHandlesAxes2D() %GetHandlesAxes2D Get handles of 2-D axes isAxes2d = arrayfun(@(x) x.is2d && ~x.islegend, mAxesInfo); hAxes2d = hAxes(isAxes2d); if ~isempty(hAxes2d) % Set current axes on first position hAxes2d(eq(hAxes2d, hAx)) = 0; hAxes2d = sort(hAxes2d); hAxes2d(eq(hAxes2d, 0)) = hAx; end end %-------------------------------------------------------------------------- %========================================================================== function ResetAxesToOrigView() %ResetAxesToOrigView reset axes to original limits SetAxesLimits(mDefaultXLim, mDefaultYLim); PointerCrossUpdate(); mZoomIndexX = find(mZoomGrid == 100); mZoomIndexY = mZoomIndexX; end %-------------------------------------------------------------------------- %========================================================================== function ResetAxesToOrigView3D() %ResetAxesToOrigView3D reset axes to original position in 3D mode % position reset axi = GetCurrentAxesIndex(); pos = mAxesInfo(axi).normposition; SetObjPos(hAx, pos, 'normalized'); % view reset resetplotview(hAx, 'ApplyStoredView'); % (!!!) undocumented function if mAxesInfo(axi).isvis3d axis(hAx, 'vis3d'); end % zoom reset mZoom3DIndex = find(mZoomGrid == 100); end %-------------------------------------------------------------------------- %========================================================================== function [x, y, z] = GetCursorCoordOnAxes() %GetCursorCoordOnAxImg crd = get(hAx, 'CurrentPoint'); x = crd(2,1); y = crd(2,2); z = crd(2,3); end %-------------------------------------------------------------------------- %========================================================================== function [x, y] = GetCursorCoordOnWindow(units) %GetCursorCoordOnWindow if (nargin < 1), units = 'pixels'; end dfltUnits = get(hFig, 'Units'); set(hFig, 'Units', units); crd = get(hFig, 'CurrentPoint'); x = crd(1); y = crd(2); set(hFig, 'Units', dfltUnits); end %-------------------------------------------------------------------------- %========================================================================== function pos = GetObjPos(h, units) %GetObjPos get object position if (nargin < 2), units = get(h, 'Units'); end dfltUnits = get(h, 'Units'); set(h, 'Units', units); pos = get(h, 'Position'); set(h, 'Units', dfltUnits); end %-------------------------------------------------------------------------- %========================================================================== function SetObjPos(h, pos, units) %SetObjPos set object position if (nargin < 3), units = get(h, 'Units'); end dfltUnits = get(h, 'Units'); set(h, 'Units', units); set(h, 'Position', pos); set(h, 'Units', dfltUnits); end %-------------------------------------------------------------------------- %========================================================================== function [xLim, yLim] = GetAxesLimits() %GetAxesLimits xLim = get(hAx, 'XLim'); yLim = get(hAx, 'YLim'); end %-------------------------------------------------------------------------- %========================================================================== function SetAxesLimits(xLim, yLim) %SetAxesLimits set(hAx, 'XLim', xLim); set(hAx, 'YLim', yLim); end %-------------------------------------------------------------------------- %========================================================================== function SetPointerCrossKeys() %SetPointerCrossKeys set pointer fullcross if fIsPointerCross PointerCrossOff(); else PointerCrossOn(); end UserData = get(hFig, 'UserData'); UserData.tools.pointercross = mPointerCross; set(hFig, 'UserData', UserData); end %-------------------------------------------------------------------------- %========================================================================== function SetPointer(pointerType) %SetPointer set pointer symbol set(hFig, 'Pointer', pointerType); end %-------------------------------------------------------------------------- %========================================================================== function SetAxesGridKeys() %SetAxesGridKeys on/off axes grid if fIsAxesGrid action = 'off'; fIsAxesGrid = false; else action = 'on'; fIsAxesGrid = true; end set(hAx, 'XGrid', action, 'YGrid', action, 'ZGrid', action); if fIsMagnifierOn set(mMagnifier.obj, 'XGrid', action, 'YGrid', action); end end %-------------------------------------------------------------------------- %========================================================================== function SetSmoothKeys() %SetSmoothKeys on/off cmoothing plots if fIsSmoothing action = 'off'; fIsSmoothing = false; else action = 'on'; fIsSmoothing = true; end if ~fIsImage %FIXME: bug with switching opengl/painter renderer here %Lost figure focus hLine = findobj(hAx, 'Type', 'Line'); if ~isempty(hLine) set(hLine, 'LineSmooth', action); % !!! Undocumented property end end end %-------------------------------------------------------------------------- %========================================================================== function [zg, st] = ZoomLogGrid(a, b, n) %ZoomLogGrid log zoom grid zg = unique(round(logspace(a, b, n))); zg(zg<10) = []; % begin zoom == 10% st = length(zg); if isempty(find(zg == 100, 1)) error('dragzoom:badZoomGridOptions', 'Options for zoom grid is bad.') end end %-------------------------------------------------------------------------- %========================================================================== function tf = IsZoomMouseAllowed() %IsZoomMouseAllowed [wcx, wcy] = GetCursorCoordOnWindow(); figPos = get(hFig, 'Position'); if (wcx >= 1 && wcx <= figPos(3) && wcy >= 1 && wcy <= figPos(4)) tf = true; else tf = false; end end %-------------------------------------------------------------------------- %========================================================================== function tf = IsImageOnAxes(ax) %IsImageOnAxes if (nargin < 1), ax = hAx; end h = findobj(ax, 'Type', 'Image'); if isempty(h) tf = false; else tf = true; end end %-------------------------------------------------------------------------- %========================================================================== function tf = IsAxes2D(ax) %IsAxes2D if (nargin < 1), ax = hAx; end tf = is2D(ax); % (!!!) internal undocumented function end %-------------------------------------------------------------------------- %========================================================================== function tf = IsLegendAxes(ax) %IsLegendAxes tf = strcmp(get(ax, 'Tag'), 'legend'); end %-------------------------------------------------------------------------- %========================================================================== function targetInBounds = IsInBoundsAxes(ax) %InBoundsAxes Check if the user clicked within the bounds of the axes. If not, do nothing targetInBounds = true; tol = 3e-16; cp = get(ax, 'CurrentPoint'); XLims = get(ax, 'XLim'); if ((cp(1,1) - min(XLims)) < -tol || (cp(1,1) - max(XLims)) > tol) && ... ((cp(2,1) - min(XLims)) < -tol || (cp(2,1) - max(XLims)) > tol) targetInBounds = false; end YLims = get(ax, 'YLim'); if ((cp(1,2) - min(YLims)) < -tol || (cp(1,2) - max(YLims)) > tol) && ... ((cp(2,2) - min(YLims)) < -tol || (cp(2,2) - max(YLims)) > tol) targetInBounds = false; end ZLims = get(ax, 'ZLim'); if ((cp(1,3) - min(ZLims)) < -tol || (cp(1,3) - max(ZLims)) > tol) && ... ((cp(2,3) - min(ZLims)) < -tol || (cp(2,3) - max(ZLims)) > tol) targetInBounds = false; end end %-------------------------------------------------------------------------- %========================================================================== function tf = IsCurrentAxes(ax) %IsCurrentAxes hcAx = get(hFig, 'CurrentAxes'); tf = eq(ax, hcAx); end %-------------------------------------------------------------------------- %========================================================================== function tf = IsAxesVis3D(ax) %IsAxesVis3D visProp = { get(ax, 'PlotBoxAspectRatioMode') get(ax, 'DataAspectRatioMode') get(ax, 'CameraViewAngleMode') }; tf = all(strcmpi(visProp, 'manual')); end %-------------------------------------------------------------------------- %========================================================================== function AxesInfo = GetAxesInfo() %GetAxesInfo make and get axes info struct countAxes = length(hAxes); AxesInfo = struct(... 'handle', cell(1, countAxes), ... 'iscurrent', cell(1, countAxes), ... 'is2d', cell(1, countAxes), ... 'isimage', cell(1, countAxes), ... 'isvisible', cell(1, countAxes), ... 'isvis3d', cell(1, countAxes), ... 'islegend', cell(1, countAxes), ... 'position', cell(1, countAxes), ... 'normposition', cell(1, countAxes), ... 'xlim', cell(1, countAxes), ... 'ylim', cell(1, countAxes), ... 'camtarget', cell(1, countAxes), ... 'camposition', cell(1, countAxes)); for i = 1:countAxes h = hAxes(i); AxesInfo(i).handle = h; AxesInfo(i).iscurrent = IsCurrentAxes(h); AxesInfo(i).is2d = IsAxes2D(h); AxesInfo(i).isimage = IsImageOnAxes(h); AxesInfo(i).isvisible = strcmpi(get(h, 'Visible'), 'on'); AxesInfo(i).isvis3d = IsAxesVis3D(h); AxesInfo(i).islegend = IsLegendAxes(h); AxesInfo(i).position = GetObjPos(h, 'pixels'); AxesInfo(i).normposition = GetObjPos(h, 'normalized'); AxesInfo(i).xlim = get(h, 'XLim'); AxesInfo(i).ylim = get(h, 'YLim'); AxesInfo(i).camtarget = get(h, 'CameraTarget'); AxesInfo(i).camposition = get(h, 'CameraPosition'); end end %-------------------------------------------------------------------------- %========================================================================== function SelectAxesUnderCursor() %SelectAxesUnderCursor select axes under cursor as current axi = GetAxesIndexUnderCursor(); if (axi > 0) fIsEnableControl = true; if ~mAxesInfo(axi).iscurrent caxi = GetCurrentAxesIndex(); if isempty(caxi) DeleteInvalidAxesInfo(); axi = GetAxesIndexUnderCursor(); isCax2d = mAxesInfo(axi).is2d; else isCax2d = mAxesInfo(caxi).is2d; end SetCurrentAxes(axi); % for fix "legend" axes capture if mAxesInfo(axi).islegend; fIsMouseOnLegend = true; else fIsMouseOnLegend = false; end % check callbacks if (isCax2d ~= mAxesInfo(axi).is2d) % if dimension of axes has changed SetCallbacks(); if fIsPointerCross % disable pointer cross PointerCrossOff() end else if fIsPointerCross % reset pointer cross PointerCrossOff() SetPointerCrossKeys() end end end else fIsEnableControl = false; end end %-------------------------------------------------------------------------- %========================================================================== function SetCurrentAxes(axi) %SetCurrentAxes set current axes and work mode hAx = mAxesInfo(axi).handle; set(hFig, 'CurrentAxes', hAx); for i = 1:numel(mAxesInfo) mAxesInfo(i).iscurrent = false; end mAxesInfo(axi).iscurrent = true; fIsAxes2D = mAxesInfo(axi).is2d; fIsImage = mAxesInfo(axi).isimage; mDefaultAxPos = mAxesInfo(axi).position; mDefaultXLim = mAxesInfo(axi).xlim; mDefaultYLim = mAxesInfo(axi).ylim; % save info to work correctly after saving figures UserData = get(hFig, 'UserData'); UserData.axesinfo = mAxesInfo; set(hFig, 'UserData', UserData); end %-------------------------------------------------------------------------- %========================================================================== function axi = GetCurrentAxesIndex() %GetCurrentAxesIndex axi = []; for i = 1:numel(mAxesInfo) if (ishandle(mAxesInfo(i).handle) && mAxesInfo(i).iscurrent) axi = i; return; end end end %-------------------------------------------------------------------------- %========================================================================== function axi = GetAxesIndexUnderCursor() %FindAxesUnderCursor find current axes under cursor axi = GetCurrentAxesIndex(); if ~fIsSelectedCurrentAxes caxi = GetCurrentAxesIndex(); if ~IsInBoundsAxes(mAxesInfo(caxi).handle) axi = 0; end return; end for i = 1:numel(mAxesInfo) if (ishandle(mAxesInfo(i).handle) && IsInBoundsAxes(mAxesInfo(i).handle)) axi = i; return; else axi = 0; % without axes end end end %-------------------------------------------------------------------------- %========================================================================== function axLim = FixInfLogLimits(ax, axLim) %FixInfLogLimits Fix Axes Inf Log Limits if (~all(isfinite(axLim)) || ~all(isreal(axLim))) % The following code has been taken from zoom.m % If any of the public limits are inf then we need the actual limits % by getting the hidden deprecated RenderLimits. oldstate = warning('off', 'MATLAB:HandleGraphics:NonfunctionalProperty:RenderLimits'); renderlimits = get(hAx, 'RenderLimits'); warning(oldstate); switch ax case 'x' axLim = renderlimits(1:2); case 'y' axLim = renderlimits(3:4); end axLim = log10(axLim); end end %-------------------------------------------------------------------------- %========================================================================== function DeleteInvalidAxesInfo() %DeleteInvalidAxesInfo invalidAxes = arrayfun(@(x) ~ishandle(x.handle), mAxesInfo); mAxesInfo(invalidAxes) = []; hAxes(invalidAxes) = []; end %-------------------------------------------------------------------------- %========================================================================== function isWithStatus = ParseInputs(varargin) %ParseInputs parse input arguments isWithStatus = false; switch nargin case 0 hObj = gcf; status = 'on'; ih = 0; case 1 if ischar(varargin{1}) isWithStatus = true; hObj = gcf; status = varargin{1}; ih = 2; is = 1; else hObj = varargin{1}; status = 'on'; ih = 1; is = 2; end case 2 isWithStatus = true; hObj = varargin{1}; status = varargin{2}; ih = 1; is = 2; end switch lower(status) case 'on' fIsEnabled = true; case 'off' fIsEnabled = false; otherwise error('dragzoom:invalidInputs', ... 'Input Argument %d must be a string "on" or "off".', is) end if all(ishandle(hObj)) handleType = get(hObj(1), 'Type'); switch handleType case 'axes' hAxes = unique(hObj); hFig = ancestor(hAxes(1), 'figure'); case 'figure' hFig = hObj; hAxes = findobj(hFig, 'Type', 'axes'); % all axes if isempty(hAxes) warning('dragzoom:notFoundAxes', 'Not found axes objects on figure.') end otherwise error('dragzoom:invalidHandle', ... 'Input Argument %d must be figure or axes handle.', ih) end else error('dragzoom:invalidInputs', ... 'Input Argument %d must be a figure or axes handle.', ih) end end %-------------------------------------------------------------------------- %========================================================================== function res = range(x) %RANGE res = abs(diff([min(x) max(x)])); end %-------------------------------------------------------------------------- end % DRAGZOOM