www.gusucode.com > signal 工具箱matlab源码程序 > signal/private/rpmmapplot.m
function rpmmapplot(map, freqVect, timeVect, rpmVect, res, type, scale, amp, rpmRef, timeRef) %RPMMAPPLOT Plotter function for RPM maps. % This function is for internal use only. It may be removed in the future. % % Inputs: % map - order or frequency map matrix % freqVect - vector of frequencies or orders % timeVect - time vector % rpmVect - vector of RPM values % res - frequency or order resolution % type - map type, can be 'Order' or 'Frequency' % scale - scale can be linear or dB % amp - can be 'rms', 'peak' or 'power' % Copyright 2015 MathWorks, Inc. % Create and render UI Framework hFrame = createUIFramework(res,type); % Create body of the GUI (e.g., axes, images, etc) createGraphics(hFrame.WidgetHandle, map, freqVect, timeVect, rpmVect, scale, amp, rpmRef, timeRef); end %---------------------------------------------------------- function toggle2D3DView(~,~,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); haxSpec = ud.hax(1); % If currently in 3D, then change to 2D and vice versa if ud.View3DStatus % Go to 2D view set(haxSpec,'View',[0 90],... 'XTickLabel',''); set(get(haxSpec,'XLabel'),'String',''); set(haxSpec, 'Position',ud.haxSpecSizeLarge); set(get(haxSpec,'YLabel'),'Rotation',90); maxZ = max(get(haxSpec,'ZLim')); set(ud.hspecX,'ZData',[maxZ, maxZ]); set(ud.hspecY,'ZData',[maxZ, maxZ]); set(ud.hCursors3D,'Visible','off'); set(haxSpec,'YTickMode','auto'); set(haxSpec,'XTickMode','auto'); else % Go to 3D view set(haxSpec,'View',[45,50],... 'XTickLabelMode','auto'); set(haxSpec, 'Position',ud.haxSpecSizeMedium); set(get(haxSpec,'YLabel'),'Rotation',0); % Move cursors to the floor of the 3D plot minZ = min(get(haxSpec,'ZLim')); set(ud.hspecX,'ZData',[minZ, minZ]); set(ud.hspecY,'ZData',[minZ, minZ]); set(ud.hCursors3D,'Visible','on'); end ud.View3DStatus = ~ud.View3DStatus; set(hfig,'UserData',ud); updateAxesWithEngUnits(hfig); update3DControlItems(hfig); % Fix the number of ticks to prevent repeated values as the axes rotate if ud.View3DStatus set(haxSpec,'YTickMode','manual'); set(haxSpec,'XTickMode','manual'); end end %---------------------------------------------------------- function rotate3DViewLeft(~,~,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); if ~ud.View3DStatus % Not in 3D mode so return return; end haxSpec = ud.hax(1); newView = get(haxSpec,'View'); newView(1) = min(75, newView(1)+5); if newView(1) == 20 rot = 48; elseif newView(1) == 15 rot = 55; else rot = 0; end if newView(1) >= 25 && newView(1) <= 65 set(haxSpec, 'Position',ud.haxSpecSizeMedium); set(get(haxSpec,'YLabel'),'Rotation',rot); set(haxSpec,'View',newView); elseif newView(1) >= 15 && newView(1) <= 75 %set(haxSpec, 'Position',ud.haxSpecSizeSmall); set(haxSpec,'View',newView); set(get(haxSpec,'YLabel'),'Rotation',rot); end end %---------------------------------------------------------- function rotate3DViewRight(~,~,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); if ~ud.View3DStatus % Not in 3D mode so return return; end haxSpec = ud.hax(1); newView = get(haxSpec,'View'); newView(1) = max(15, newView(1)-5); if newView(1) == 20 rot = 48; elseif newView(1) == 15 rot = 55; else rot = 0; end if newView(1) >= 25 && newView(1) <= 65 set(haxSpec, 'Position',ud.haxSpecSizeMedium); set(haxSpec,'View',newView); set(get(haxSpec,'YLabel'),'Rotation',rot); elseif newView(1) >= 15 && newView(1) <= 75 %set(haxSpec, 'Position',ud.haxSpecSizeSmall); set(haxSpec,'View',newView); set(get(haxSpec,'YLabel'),'Rotation',rot); end end %---------------------------------------------------------- function reset3DView(~,~,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); if ~ud.View3DStatus % Not in 3D mode so return return; end haxSpec = ud.hax(1); set(haxSpec,'View',[45,50]); set(haxSpec, 'Position',ud.haxSpecSizeMedium); set(get(haxSpec,'YLabel'),'Rotation',0); end %---------------------------------------------------------- function toggleZoom(ctrl,~,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); if isprop(ctrl,'Checked') % Menu item was clicked - if not checked, then user wants to turn % clicked mode on, if checked user wants to turn clicked mode off if strcmp(ctrl.Checked,'off') % Turn mode on ud.ZoomOn = true; ud.ZoomMode = getZoomModeFromTag(ctrl); else % Turn mode off ud.ZoomOn = false; ud.ZoomMode = []; end elseif strcmp(ctrl.State,'on') % Toolbar button was pressed ud.ZoomOn = true; ud.ZoomMode = getZoomModeFromTag(ctrl); else % Toolbar button was de-pressed ud.ZoomOn = false; ud.ZoomMode = []; end set(hfig,'UserData',ud); updateZoomControlItems(hfig); end %---------------------------------------------------------- function zoomFull(hco,eventStruct,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); focusTimeReset(hco, eventStruct, hfig); % reset focus window to full extent % Get time range of full spectrogram and update surfXdata = get(ud.hsurface,'XData'); newXlim = [min(surfXdata), max(surfXdata)]; set(ud.hax(1),'XLim',newXlim); surfYdata = get(ud.hsurface,'YData'); newYlim = [min(surfYdata), max(surfYdata)]; set(ud.hax(1),'YLim',newYlim); % Update the thumbnail: set(ud.hthumb,'XData',newXlim([1 2 2 1 1])); updateAxesWithEngUnits(hfig); end %--------------------------------------------------------------- function setCrosshairs(hfig,x,y) % Get current point in axis ASAP: ud = get(hfig,'UserData'); hax = ud.hax(1); % Update cache if isempty(x) x = ud.crosshair.xctr; else ud.crosshair.xctr = x; end if nargin == 3 if isempty(y) y = ud.crosshair.yctr; else ud.crosshair.yctr = y; end else y = ud.crosshair.yctr; end set(hfig,'UserData',ud); % Update crosshairs set([ud.hspecY ud.htimeY], 'XData',[x x]); set(ud.hspecX, 'YData',[y y]); % Update 3D cursors zLim = get(hax, 'ZLim'); z0 = zLim(1); z1 = zLim(2); xData = get(ud.hspecX,'XData'); x0 = xData(1); x1 = xData(2); xPatch = [x0 x1 x1 x0]; yPatch = [y y y y]; zPatch = [z0 z0 z1 z1]; set(ud.hCursors3D(1), 'XData',xPatch, 'YData',yPatch, 'ZData', zPatch); yData = get(ud.hspecY,'YData'); y0 = yData(1); y1 = yData(2); xPatch = [x x x x]; yPatch = [y0 y1 y1 y0]; zPatch = [z0 z0 z1 z1]; set(ud.hCursors3D(2), 'XData',xPatch, 'YData',yPatch, 'ZData', zPatch); % Update readouts updateTimeReadout(hfig); updateFreqReadout(hfig); updateAmpReadout(hfig); updateRpmReadout(hfig); end %--------------------------------------------------------------- function centerCursors(~,~,hfig) if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); % Determine center of spectrogram axis: xlim=get(ud.hax(1),'XLim'); ylim=get(ud.hax(1),'YLim'); setCrosshairs(hfig,mean(xlim),mean(ylim)); end %--------------------------------------------------------------- function bringCursorsIntoZoomRegion(hfig) % If cursors are already in zoom region do nothing, but if they are not, % then bring them to center of region. if nargin < 3 hfig=gcbf; end ud = get(hfig,'UserData'); % Determine center of spectrogram axis: xlim=get(ud.hax(1),'XLim'); ylim=get(ud.hax(1),'YLim'); xPos = []; yPos = []; if ud.crosshair.yctr < ylim(1) || ud.crosshair.yctr > ylim(2) yPos = mean(ylim); end if ud.crosshair.xctr < xlim(1) || ud.crosshair.xctr > xlim(2) xPos = mean(xlim); end setCrosshairs(hfig,xPos,yPos); end %--------------------------------------------------------------- function wbmotionThumb(~,~) % thumbnail motion % Get current point in axis ASAP: hfig = gcbf; ud = get(hfig,'UserData'); hax = ud.hax(2); cp = get(hax,'CurrentPoint'); currX = cp(1,1); xmotion = currX - ud.thumb.origPt; width = ud.thumb.width; xdata = ud.thumb.xdata + xmotion; % Constrain to axis limits, so we don't lose cursor: xlim=get(hax,'XLim'); minXdata = min(xdata); maxXdata = max(xdata); if minXdata < xlim(1), xdata=[xlim(1) xlim([1 1])+width xlim([1 1])]; elseif maxXdata > xlim(2), xdata = [xlim(2)-width xlim([2 2]) xlim([2 2])-width]; end % If the patch is larger than the zoom window if min(xdata)<=xlim(1) && max(xdata)>=xlim(2) return end % Update the thumbnail: set(ud.hthumb,'XData',xdata); % Scroll the spectrogram: set(ud.hax(1),'XLim',xdata(1:2)); % [1 3] if ud.View3DStatus % Update spectrogram time axis if in 3d view updateSpecTimeAxesWithEngUnits(hfig); end end %--------------------------------------------------------------- function wbmotionThumbLeft(~,~) % thumbnail LEFT motion % Get current point in axis ASAP: hfig = gcbf; ud = get(hfig,'UserData'); % current object may be either the patch, or the signal line hax = ud.hax(2); cp = get(hax,'CurrentPoint'); currX = cp(1,1); xmotion = currX - ud.thumb.origPt; xdata = ud.thumb.xdata; xdata([1 4 5]) = xdata([1 4 5]) + xmotion; % Constrain to axis limits, so we don't lose cursor: xlim = get(hax,'XLim'); minXdata = min(xdata); if minXdata < xlim(1) xdata=[xlim(1) xdata([2 3])' xlim([1 1])]; elseif minXdata >= xdata(2), xdata = ud.thumb.xdata; end % Update the thumbnail: set(ud.hthumb,'XData',xdata); % Scroll the spectrogram: set(ud.hax(1),'XLim',xdata(1:2)); if ud.View3DStatus % Update spectrogram time axis if in 3d view updateSpecTimeAxesWithEngUnits(hfig); end end %--------------------------------------------------------------- function wbmotionThumbright(~,~) % thumbnail RIGHT motion % Get current point in axis ASAP: hfig = gcbf; ud = get(hfig,'UserData'); hax = ud.hax(2); cp = get(hax,'CurrentPoint'); currX = cp(1,1); xmotion = currX - ud.thumb.origPt; xdata = ud.thumb.xdata; xdata([2 3]) = xdata([2 3]) + xmotion; % Constrain to axis limits, so we don't lose cursor: xlim = get(hax,'XLim'); maxXdata = max(xdata); if maxXdata > xlim(2), xdata(2:3) = xlim(2); elseif maxXdata <= xdata(1), xdata = ud.thumb.xdata; end % Update the thumbnail: set(ud.hthumb,'XData',xdata); % Scroll the spectrogram: set(ud.hax(1),'XLim',xdata(1:2)); if ud.View3DStatus % Update spectrogram time axis if in 3d view updateSpecTimeAxesWithEngUnits(hfig); end end %--------------------------------------------------------------- function wbupThumb(~,~) % set spectrogram and time-slice xlims hfig = gcbf; ud = get(hfig,'UserData'); % Commented out, due to flash: % set(ud.hax([1 3]),'XLim',xlim); % % This is fine: % set(ud.hax(1),'XLim',xlim); % % the following line causes flash in the spect image % this is the time-slice axis: % why does this affect the spectrogram axis? (overlap? clipping?) % set(ud.hax(3),'XLim',xlim); changePtr(gcbf,'hand'); installCursorFcns(gcbf,'thumb'); % Turn back on image axis visibility, % which was turned off during wbdownThumb % so that it does not flash while panning: % Leave off! %set(ud.hax(1),'Visible','on'); % % Turn on crosshair visibility, which was shut off % during thumbnail panning (wbdownThumb): set([ud.hspecY ud.hspecX],'Visible','on'); if ud.View3DStatus % Update spectrogram time axis if in 3d view updateSpecTimeAxesWithEngUnits(hfig); end end %--------------------------------------------------------------- function wbupThumbLeft(~,~) % set spectrogram and time-slice xlims hfig = gcbf; ud = get(hfig,'UserData'); xdata = get(ud.hthumb,'XData'); xlim = [min(xdata) max(xdata)]; % Commented out, due to flash: %set(ud.hax([1 3]),'XLim',xlim); % % This is fine: set(ud.hax(1),'XLim',xlim); % % the following line causes flash in the spect image % this is the time-slice axis: %set(ud.hax(3),'XLim',xlim); changePtr(gcbf,'ldrag'); installCursorFcns(gcbf,'thumbleft'); % Turn on crosshair visibility, which was shut off during thumbnail panning % (wbdownThumb): set([ud.hspecY ud.hspecX],'Visible','on'); if ud.View3DStatus % Update spectrogram time axis if in 3d view updateSpecTimeAxesWithEngUnits(hfig); end end %--------------------------------------------------------------- function wbupThumbRight(~,~) % set spectrogram and time-slice xlims hfig = gcbf; ud = get(hfig,'UserData'); xdata = get(ud.hthumb,'XData'); xlim = [min(xdata) max(xdata)]; % Commented out, due to flash: %set(ud.hax([1 3]),'XLim',xlim); % % This is fine: set(ud.hax(1),'XLim',xlim); % % the following line causes flash in the spect image % this is the time-slice axis: %set(ud.hax(3),'XLim',xlim); changePtr(gcbf,'rdrag'); installCursorFcns(gcbf,'thumbright'); % Turn on crosshair visibility, which was shut off during thumbnail panning % (wbdownThumb): set([ud.hspecY ud.hspecX],'Visible','on'); if ud.View3DStatus % Update spectrogram time axis if in 3d view updateSpecTimeAxesWithEngUnits(hfig); end end %--------------------------------------------------------------- function updateStatus(hfig, str) % updateStatus Update status text. ud = get(hfig,'UserData'); hstatusbar = ud.huiframe.findchild('StatusBar'); if(isa(hstatusbar, 'uimgr.uistatusbar')) if nargin == 2 && ischar(str) hstatusbar.WidgetHandle.Text = str; elseif nargin == 1 strres = [ud.ResTxt, ud.ResValue ' ' ud.ResUnits]; hstatusbar.findchild('Res').WidgetHandle.Text = strres; else return; end end end %--------------------------------------------------------------- function setCmapLimits(hfig, new_dr) % Set new colormap limits ud = get(hfig,'UserData'); haxSpec = ud.hax(1); haxCbar = ud.hax(3); himageCbar = ud.himageCbar; % Set new dynamic range limits into spectrogram image set(haxSpec,'CLim',new_dr); % colorbar is 1:256 % Actual spectrogram dynamic range is orig_dr new spectrogram dynamic range % is new_dr origDr = get(himageCbar,'YData'); diffDr = new_dr - origDr; cmapIndices_per_dB = 256./diff(origDr); % a constant diffClim = diffDr .* cmapIndices_per_dB; cbarClim = [1 256] + diffClim; set(himageCbar,'CDataMapping','scaled'); % do during creation set(haxCbar,'CLim',cbarClim); end %--------------------------------------------------------------- function resetCmapLimits(~,~) % Reset colormap limits to dynamic range of spectrogram data hfig = gcbf; ud = get(hfig,'UserData'); origDr = get(ud.himageCbar,'YData'); setCmapLimits(hfig, origDr); end %--------------------------------------------------------------- function manualCmapLimits(~,~,hfig) % manualCmapLimits Manual change to colormap dynamic range limits if nargin < 3 hfig = gcbf; end ud = get(hfig,'UserData'); haxSpec = ud.hax(1); % Prompt for changes to cmap limits: clim = get(haxSpec,'CLim'); prompt={getStrFromCat('topColor'),getStrFromCat('bottomColor')}; def = {num2str(clim(2)), num2str(clim(1))}; dlgTitle = getStrFromCat('color'); lineNo=1; strs=inputdlg(prompt,dlgTitle,lineNo,def); if isempty(strs), return end new_dr = [str2double(strs{2}) str2double(strs{1})]; setCmapLimits(hfig,new_dr); end %--------------------------------------------------------------- function wbmotionCmap(~,~) % wbmotionCmap Graphical change to colormap dynamic range limits hfig = gcbf; ud = get(hfig,'UserData'); haxSpec = ud.hax(1); haxCbar = ud.hax(3); % Determine cursor starting and current points ASAP: cp = get(haxCbar,'CurrentPoint'); newPt = cp(1,2); % y-coord only dy = newPt - ud.cbar.origPt; % if SelectionType was normal, update top or bottom of colorbar, only, % depending on whether user started drag in the top or bottom of bar, % respectively. % % if SelectionType was extend, update both top AND bottom of bar % simultaneously, translating colormap region. if strcmp(ud.cbar.SelectionType,'extend'), change_dr = [dy dy]; else if ud.cbar.StartInTop, change_dr = [0 dy]; else change_dr = [dy 0]; end end newDr = ud.cbar.starting_dr + change_dr; if diff(newDr)<=0, newDr = ud.cbar.starting_dr; end % Colorbar range is 1 to 256. Actual spectrogram dynamic range is orig_dr. % New spectrogram dynamic range is new_dr. origDr = get(ud.himageCbar,'YData'); % a constant cmapIndices_per_dB = 256./diff(origDr); % a constant diffDr = newDr - origDr; diffClim = diffDr .* cmapIndices_per_dB; cbarClim = [1 256] + diffClim; if diff(cbarClim)>0, % Protect against poor choice of values set(haxCbar,'CLim',cbarClim,'UserData',newDr); end % We defer setting the new dynamic range limits into the spectrogram image % axis, as it will create too much flash. Instead, on button-up, the new % limit is set. See wbupCmap() for details. % Set new dynamic range limits into spectrogram image. Note: userdata could % be empty if this is the first entry... set(haxSpec,'CLim',newDr); end %--------------------------------------------------------------- function isChange = changePtr(hfig, newPtr) % Get current pointer name: ud = get(hfig,'UserData'); % Is this a change in pointer type? isChange = ~strcmp(ud.currPtr,newPtr); if isChange setptr(hfig, newPtr); ud.currPtr = newPtr; set(hfig,'UserData',ud); end end %--------------------------------------------------------------- function wbmotionGeneral(~,~,hfig) % General button motion % % Determines if cursor is over a crosshair. If so, changes pointer and % installs crosshair buttondowns If not, changes back to normal cursor and % general buttondowns as necessary. if nargin < 3 hfig = gcbf; end ud = get(hfig,'UserData'); [isOverHV, isSpecgramAxis, isCmapAxis,isTopHalfCmap, isThumb] = overCrosshair(hfig); if ~any(isOverHV) % Not hovering over a crosshair if isSpecgramAxis % Do nothing over the spectrogram axes unless in zoom XY mode if ud.ZoomOn if strcmp(ud.ZoomMode,'ZoomOut') changePtr(hfig, 'glassminus'); installCursorFcns(hfig,'zoomout'); else changePtr(hfig, 'glassplus'); installCursorFcns(hfig,'zoomdrag'); end else changePtr(hfig,'arrow'); installCursorFcns(hfig,'general'); end elseif isCmapAxis % Over the colormap axes % Install the up/down pointer: if isTopHalfCmap if changePtr(hfig,'udrag'), updateStatus(hfig,getStrFromCat('upperShiftToTranslate')); installCursorFcns(hfig,'cmap'); end else if changePtr(hfig,'ddrag'), updateStatus(hfig,getStrFromCat('lowerShiftToTranslate')); installCursorFcns(hfig,'cmap'); end end elseif any(isThumb) % Over thumbnail - isThumb is a 3-element vector, [left center right], % indicating whether cursor is over left edge, right edge, or is over % the general thumbnail patch itself. % Install appropriate pointer: if isThumb(1) % Over left edge if changePtr(hfig,'ldrag'), installCursorFcns(hfig,'thumbleft'); end elseif isThumb(3) % Over right edge if changePtr(hfig,'rdrag'), installCursorFcns(hfig,'thumbright'); end else % Over general patch region if changePtr(hfig,'hand'), installCursorFcns(hfig,'thumb'); end end else % Not over a special axes: if changePtr(hfig,'arrow'), installCursorFcns(hfig,'general'); end end else % Pointer is over a crosshair (vert or horiz or both) if all(isOverHV) % Over both horiz and vert (near crosshair center): if changePtr(hfig,'fleur'), installCursorFcns(hfig,'hvcross'); end elseif isOverHV(1) % Over H crosshair if changePtr(hfig,'uddrag'), installCursorFcns(hfig,'hcross'); end else % Over V crosshair if changePtr(hfig,'lrdrag'), installCursorFcns(hfig,'vcross'); end end end end %--------------------------------------------------------------- function [y,isSpecAxis,isCmapAxis,isTopHalfCmap, isThumb] = overCrosshair(hfig) % Is the cursor hovering over the crosshairs? % % There are two crosshairs, one an H-crosshair, the other a V-crosshair. % The H and V crosshairs span several different axes. % % Function returns a 2-element vector, indicating whether the cursor is % currently over the H- and/or V-crosshairs. % % y = [isOverH isOverV] y = [0 0]; isSpecAxis = 0; isCmapAxis = 0; isTopHalfCmap = 0; isThumb = [0 0 0]; % left, middle, right regions % First, are we over any axes? hax = overAxes(hfig); if isempty(hax) return; end % not over an axis % Get current point in axis: cp = get(hax,'CurrentPoint'); ud = get(hfig,'UserData'); isCmapAxis = (hax == ud.hax(3)); isSpecAxis = (hax == ud.hax(1)); % Determine if any horiz or vert crosshairs are in this axis - store as % [anyHoriz anyVert]: hasHVCrossHairs = [hax == ud.hax(1) any(hax == ud.hax(1:2))]; % Is cursor in colormap axis? if (isCmapAxis), % is cursor in top half of colormap axis? orig_dr = get(ud.hax(1),'CLim'); isTopHalfCmap = (cp(1,2) >= sum(orig_dr)/2); end if any(hasHVCrossHairs), % Get cursor & crosshair positions: crosshairPos = [ud.crosshair.xctr ud.crosshair.yctr]; curretPt = cp(2,1:2); cursorDelta = abs(crosshairPos - curretPt); axisDx = diff(get(hax,'XLim')); axisDy = diff(get(hax,'YLim')); axisDelta = [axisDx axisDy]; % Is cursor within 1 percent of crosshair centers? % Limit test uses the reciprocal of the percentage tolerance % 1-percent -> 1 / 0.01 = 100 % 1.5-percent -> 1 / 0.015 ~= 67 % 2-percent -> 1 / 0.02 = 50 % % Finally, allow a true result only if the axis % has a crosshair of the corresponding type % y = fliplr(cursorDelta * 67 < axisDelta) & hasHVCrossHairs; end % Are we over the thumbnail patch? % Check if we're over the time axis: if (hax == ud.hax(2)), % Get thumb patch limits: xdata=get(ud.hthumb,'XData'); xlim=[min(xdata) max(xdata)]; % Is cursor over general patch area? thumb_delta = xlim - cp(1,1); isThumb(2) = thumb_delta(1)<=0 & thumb_delta(2)>=0; % Is cursor over left or right thumbnail edge? % Use same tolerance as crosshair test: axisDx = diff(get(hax,'XLim')); isThumb([1 3]) = (abs(thumb_delta) * 67 < axisDx); end end %--------------------------------------------------------------- function h = overAxes(hfig) % overAxes Determine if pointer is currently over an axis of the figure; % the axis list comes from the figure UserData (ud.hax). fig = get(hfig); ud = fig.UserData; obj = hittest(hfig); switch obj.Tag case {'rpmmapplotSpecAxesTag','rpmmapplotSurfaceTag',... 'rpmmapplotTopOfSpecAxesTag','rpmmapplotSpecCursorXTag',... 'rpmmapplotSpecCursorYTag','rpmmapplotSpecCursorPatch1Tag',... 'rpmmapplotSpecCursorPatch2Tag'} h = ud.hax(1); case {'rpmmapplotPannerAxesTag','rpmmapplotPannerPatchTag',... 'rpmmapplotPannerLineTag','rpmmapplotPannerMarkerTag',... 'rpmmapplotPannerCursorTag'} h = ud.hax(2); case {'rpmmapplotCBarAxesTag','rpmmapplotCBarImgTag'} h = ud.hax(3); otherwise h = []; end end %--------------------------------------------------------------- function y = isLeftClick(hfig) % Keywords for key/button combinations: % Left Right % none: normal alt % Shift: extend alt % Ctrl: alt alt % Double: open alt y=strcmp(get(hfig,'SelectionType'),'normal'); end %--------------------------------------------------------------- function wbdownHCross(~,~) % window button down in h-crosshair mode if ~isLeftClick(gcbf) return; end ud = get(gcbf,'UserData'); set(ud.hCursors3D(1),'FaceAlpha',.4); installCursorFcns(gcbf,'hcross_buttondown'); wbmotionCross([],[],'h'); end %--------------------------------------------------------------- function wbdownVCross(~,~) % window button down in v-crosshair mode if ~isLeftClick(gcbf) return; end ud = get(gcbf,'UserData'); set(ud.hCursors3D(2),'FaceAlpha',.4); installCursorFcns(gcbf,'vcross_buttondown'); wbmotionCross([],[],'v'); end %--------------------------------------------------------------- function wbdownHVCross(~,~) % window button down in hv-crosshair mode if ~isLeftClick(gcbf) return; end ud = get(gcbf,'UserData'); set(ud.hCursors3D,'FaceAlpha',.4); installCursorFcns(gcbf,'hvcross_buttondown'); wbmotionCross([],[],'hv'); end %--------------------------------------------------------------- function wbdownThumb(~,~) % window button down in thumbnail mode if ~isLeftClick(gcbf) return; end % cache y-coord of pointer ud = get(gcbf,'UserData'); haxTime = ud.hax(2); cp = get(haxTime,'CurrentPoint'); xdata = get(ud.hthumb,'XData'); width = max(xdata)-min(xdata); ud.thumb.origPt = cp(1,1); % x-coord only ud.thumb.width = width; ud.thumb.xdata = xdata; set(gcbf,'UserData',ud); changePtr(gcbf,'closedhand'); installCursorFcns(gcbf,'thumb_buttondown'); % Turn off image axis visibility, % so that it does not flash while panning: % % off permanently now: %set(ud.hax(1),'Visible','off'); % % Turn off crosshair visibility: set([ud.hspecY ud.hspecX],'Visible','off'); end %--------------------------------------------------------------- function wbdownThumbLeft(~,~) % window button down in LEFT thumbnail mode if ~isLeftClick(gcbf) return; end % cache y-coord of pointer ud = get(gcbf,'UserData'); hax_time = ud.hax(2); cp = get(hax_time,'CurrentPoint'); xdata = get(ud.hthumb,'XData'); width = max(xdata)-min(xdata); ud.thumb.origPt = cp(1,1); % x-coord only ud.thumb.width = width; ud.thumb.xdata = xdata; set(gcbf,'UserData',ud); installCursorFcns(gcbf,'thumbleft_buttondown'); % Turn off crosshair visibility: set([ud.hspecY ud.hspecX],'Visible','off'); end %--------------------------------------------------------------- function wbdownThumbRight(~,~) % window button down in LEFT thumbnail mode if ~isLeftClick(gcbf) return; end % cache y-coord of pointer ud = get(gcbf,'UserData'); haxTime = ud.hax(2); cp = get(haxTime,'CurrentPoint'); xdata = get(ud.hthumb,'XData'); width = max(xdata)-min(xdata); ud.thumb.origPt = cp(1,1); % x-coord only ud.thumb.width = width; ud.thumb.xdata = xdata; set(gcbf,'UserData',ud); installCursorFcns(gcbf,'thumbright_buttondown'); % Turn off crosshair visibility: set([ud.hspecY ud.hspecX],'Visible','off'); end %---------------------------------------------------- function wbdownCmap(~,~) % window button down in colormap mode hfig = gcbf; % Only allow left (normal) or shift+left (extend) st = get(hfig,'SelectionType'); i = find(strncmp(st,{'normal','extend','open'}, length(st))); if isempty(i) return; end if i==3, % open dynamic range menu manualCmapLimits([],[],hfig); return elseif i==2, % Shift+left button = translate, % show up/down cursor during drag % NOTE: cannot update cursor when shift is pressed % but no mouse button is pressed (no event!) changePtr(hfig,'uddrag'); end ud = get(hfig,'UserData'); % cache y-coord of pointer haxCbar = ud.hax(3); cp = get(haxCbar,'CurrentPoint'); ud.cbar.origPt = cp(1,2); % y-coord only ud.cbar.SelectionType = st; % normal or extend % The current clim is in the spectrogram image. We want to know the midpoint % of this origDr = get(ud.hax(1),'CLim'); ud.cbar.midPt = sum(origDr)/2; % Determine if pointer went down in top or bottom half of colorbar: ud.cbar.StartInTop = (ud.cbar.origPt >= ud.cbar.midPt); % Cache original dynamic range: haxSpec = ud.hax(1); ud.cbar.starting_dr = get(haxSpec,'CLim'); set(hfig,'UserData',ud); installCursorFcns(hfig,'cmap_buttondown'); % Set initial clim into userdata in case motion callback not performed % (motion updates userdata). wbupCmap reads the userdata % % Turn off visibility during drag to prevent flash set(haxCbar, ... 'UserData',ud.cbar.starting_dr, ... 'Visible','off'); end %--------------------------------------------------------------- function wbupHCross(~,~) % window button up in h-crosshair mode installCursorFcns(gcbf,'hcross'); ud = get(gcbf,'UserData'); set(ud.hCursors3D,'FaceAlpha',.05); end %--------------------------------------------------------------- function wbupVCross(~,~) % window button up in v-crosshair mode installCursorFcns(gcbf,'vcross'); ud = get(gcbf,'UserData'); set(ud.hCursors3D,'FaceAlpha',.05); end %--------------------------------------------------------------- function wbupHVCross(~,~) % window button up in hv-crosshair mode installCursorFcns(gcbf,'hvcross'); ud = get(gcbf,'UserData'); set(ud.hCursors3D,'FaceAlpha',.05); end %--------------------------------------------------------------- function wbupCmap(~,~) % window button up in colormap mode installCursorFcns(gcbf,'cmap'); % Set new dynamic range limits into spectrogram image. Note: userdata could % be empty if this is the first entry... ud = get(gcbf,'UserData'); haxCbar = ud.hax(3); set(ud.hax(1),'CLim',get(haxCbar,'UserData')); set(haxCbar,'Visible','on'); % re-enable axis vis % Set new status msg, since it doesn't update in the installCursorFcns fcn % for cmap callbacks Do this by calling the general mouse-motion fcn: wbmotionGeneral([],[]); end %--------------------------------------------------------------- function wbdownZoom(~,~) if ~isLeftClick(gcbf) return; end hfig = gcbf; ud = get(hfig,'UserData'); haxSpec = ud.hax(1); cp = get(haxSpec,'CurrentPoint'); ud.ZoomOrigPt = cp(2,1:2); ud.ZoomDestPt = []; if ud.View3DStatus set(ud.hthumbZoom3D,'Xdata',NaN,'YData',NaN,'ZData',NaN,'Visible','on'); else set(ud.hthumbZoom,'Xdata',NaN,'YData',NaN,'Visible','on'); end installCursorFcns(gcbf,'zoom_buttondown'); % Turn off crosshair visibility: set([ud.hspecY ud.hspecX],'Visible','off'); set(ud.hCursors3D,'Visible','off'); set(hfig,'UserData',ud); end %--------------------------------------------------------------- function wbmotionZoom(~,~,hfig) % Paint thumb region based on mouse movement and cache zoom limits if nargin < 3 hfig = gcbf; end ud = get(hfig,'UserData'); haxSpec = ud.hax(1); axXlims = haxSpec.XLim; axYlims = haxSpec.YLim; cp = get(haxSpec,'CurrentPoint'); xo = ud.ZoomOrigPt(1); yo = ud.ZoomOrigPt(2); if cp(1,2) < 0 % Do not move the region if pointer is outside axes return; end switch ud.ZoomMode case 'ZoomIn' x1 = cp(2,1); y1 = cp(2,2); case 'ZoomX' x1 = cp(2,1); yo = min(axYlims); y1 = max(axYlims); case 'ZoomY' y1 = cp(2,2); xo = min(axXlims); x1 = max(axXlims); case 'ZoomOut' return; end ud.ZoomDestPt = [x1,y1]; minX = max(min(xo,x1),min(axXlims)); maxX = min(max(xo,x1),max(axXlims)); minY = max(min(yo,y1),min(axYlims)); maxY = min(max(yo,y1),max(axYlims)); ud.Zoom_XLimits = [minX maxX]; ud.Zoom_YLimits = [minY maxY]; xCoords = [minX maxX maxX minX]; yCoords = [minY minY maxY maxY]; if ud.View3DStatus % Draw 3D zoom region x0 = minX; x1 = maxX; y0 = minY; y1 = maxY; zLim = get(haxSpec, 'ZLim'); z0 = zLim(1); z1 = zLim(2); x = [x0 x1 x1 x0; x1 x1 x1 x0; x1 x1 x0 x0; x0 x1 x0 x0]; y = [y0 y0 y1 y1; y0 y0 y1 y0; y0 y1 y1 y0; y0 y1 y1 y1]; z = [z0 z0 z0 z0; z0 z1 z1 z0; z1 z1 z1 z1; z1 z0 z0 z1]; set(ud.hthumbZoom3D,'Xdata',x,'YData',y,'ZData',z); else % Draw 2D zoom patch maxZ = max(get(haxSpec,'ZLim')); set(ud.hthumbZoom,'Xdata',xCoords,'YData',yCoords,'ZData',[maxZ maxZ maxZ maxZ]); end set(hfig,'UserData',ud); end %--------------------------------------------------------------- function wbupZoom(~,~) hfig = gcbf; ud = get(hfig,'UserData'); % Remove zoom thumb regions set(ud.hthumbZoom,'Xdata',NaN,'YData',NaN,'Visible','off'); set(ud.hthumbZoom3D,'Xdata',NaN,'YData',NaN,'ZData',NaN,'Visible','off'); % Turn on crosshair visibility: set([ud.hspecY ud.hspecX],'Visible','on'); set(ud.hCursors3D,'Visible','on'); switch ud.ZoomMode case 'ZoomIn' % Go back to zoom mode installCursorFcns(gcbf,'zoomdrag'); doZoomX(hfig,ud); doZoomY(hfig,ud); case 'ZoomX' installCursorFcns(gcbf,'zoomdrag'); doZoomX(hfig,ud) case 'ZoomY' installCursorFcns(gcbf,'zoomdrag'); doZoomY(hfig,ud) case 'ZoomOut' installCursorFcns(gcbf,'zoomout'); doZoomX(hfig,ud,true); doZoomY(hfig,ud,true); end % Update ticks and labels updateAxesWithEngUnits(hfig); bringCursorsIntoZoomRegion(hfig); end %--------------------------------------------------------------- function doZoomX(hfig,ud,zoomOutFlag) if nargin == 1 ud = get(hfig,'UserData'); end if nargin < 3 zoomOutFlag = false; end % Pixel spacing of data. x axis points can be non uniformly sampled so pick % smallest width (values at end of data). surfXdata = get(ud.hsurface,'XData'); minXData = min(surfXdata); maxXData = max(surfXdata); dataDx = surfXdata(end)-surfXdata(end-1); currentXLimits = get(ud.hax(1),'XLim'); if zoomOutFlag % Do 50% zoom out in x newDeltaXLim = diff(currentXLimits)*2; deltaXData = maxXData - minXData; if newDeltaXLim > deltaXData % New delta limits exceed data limits so do full zoom zoomXLim = [minXData, maxXData]; else xCenter = ud.ZoomOrigPt(1); xLeft = xCenter - newDeltaXLim/2; xRight = xCenter + newDeltaXLim/2; if xLeft < minXData % Min limits are smaller than min data so pick left half of data % limits zoomXLim = [minXData, minXData+deltaXData]; elseif xRight > maxXData % Max limits are larger than max data so pick right half of data % limits zoomXLim = [maxXData-deltaXData, maxXData]; else zoomXLim = [xLeft, xRight]; end end elseif isempty(ud.ZoomDestPt) || diff(ud.Zoom_XLimits) == 0 % Single click so do 50% zoom in x % If we can place the center at the point where mouse was clicked without % exceeding min/max data limits do so. Otherwise if mouse was clicked to % the left of the current axes center, zoom to the left half or if mouse % was clicked to the right of the current axes center, zoom to the left % half. newDeltaXLim = diff(currentXLimits)/2; xCenter = ud.ZoomOrigPt(1); xLeft = xCenter - newDeltaXLim/2; xRight = xCenter + newDeltaXLim/2; if xLeft >minXData && xRight < maxXData zoomXLim = [xLeft, xRight]; else % If left of center zoom to left half, otherwise, zoom to right half xCenter = mean(currentXLimits); if ud.ZoomOrigPt(1) < xCenter zoomXLim = [currentXLimits(1), xCenter]; else zoomXLim = [xCenter, currentXLimits(2)]; end end if diff(zoomXLim) <= 0 % Do not zoom if zoom delta is zero return; end else % Check that the zoom region is not zero width in X. If it is, then % increase the zoom width to half pixel width. % Get X zoom limits zoomXLim = ud.Zoom_XLimits; % Zoom delta X dxLim = diff(zoomXLim); if dxLim <= 0 % Increase second zoom X limit by 0.5*pixel width or max current limit zoomXLim(2) = min(currentXLimits(2),zoomXLim(2)+dataDx/2); end end % Perform zoom (also update the panner thumbnail x data). Do this only if % we have different min max values, if diff(zoomXLim) > 0 set(ud.hax(1),'XLim',zoomXLim); set(ud.hthumb,'XData',zoomXLim([1 2 2 1 1])); end end %--------------------------------------------------------------- function doZoomY(hfig,ud,zoomOutFlag) if nargin == 1 ud = get(hfig,'UserData'); end if nargin < 3 zoomOutFlag = false; end % Pixel spacing of data. surfYdata = get(ud.hsurface,'YData'); minYData = min(surfYdata); maxYData = max(surfYdata); dataDy = surfYdata(2)-surfYdata(1); currentYLimits = get(ud.hax(1),'YLim'); if zoomOutFlag % Do 50% zoom out in y newDeltaYLim = diff(currentYLimits)*2; deltaYData = maxYData - minYData; if newDeltaYLim > deltaYData % New delta limits exceed data limits so do full zoom zoomYLim = [minYData, maxYData]; else yCenter = ud.ZoomOrigPt(2); yLow = yCenter - newDeltaYLim/2; yUp = yCenter + newDeltaYLim/2; if yLow < minYData % Min limits are smaller than min data so pick lower half of data % limits zoomYLim = [minYData, minYData+deltaYData]; elseif yUp > maxYData % Max limits are larger than max data so pick upper half of data % limits zoomYLim = [maxYData-deltaYData, maxYData]; else zoomYLim = [yLow, yUp]; end end elseif isempty(ud.ZoomDestPt) || diff(ud.Zoom_YLimits) == 0 % Single click so do 50% zoom in x % If we can place the center at the point where mouse was clicked without % exceeding min/max data limits do so. Otherwise if mouse was clicked % above the current axes center, zoom to the upper half or if mouse was % clicked below the current axes center, zoom to the lower half. newDeltaYLim = diff(currentYLimits)/2; yCenter = ud.ZoomOrigPt(2); yLow = yCenter - newDeltaYLim/2; yUp = yCenter + newDeltaYLim/2; if yLow > minYData && yUp < maxYData zoomYLim = [yLow, yUp]; else % If below of center zoom to bottom half, otherwise, zoom to top half yCenter = mean(currentYLimits); if ud.ZoomOrigPt(2) < yCenter zoomYLim = [currentYLimits(1), yCenter]; else zoomYLim = [yCenter, currentYLimits(2)]; end end if diff(zoomYLim) <= 0 % Do not zoom if zoom delta is zero return; end else % Check that the zoom region is not zero width in Y. If it is, then % increase the zoom width to half pixel width. % Get Y zoom limits zoomYLim = ud.Zoom_YLimits; % Zoom delta Y dyLim = diff(zoomYLim); if dyLim <= 0 % Increase second zoom Y limit by 0.5*pixel width or max current limit zoomYLim(2) = min(currentYLimits(2),zoomYLim(2)+dataDy/2); end end % Perform zoom only if we have 2 different values if diff(zoomYLim) > 0 set(ud.hax(1),'YLim',zoomYLim); end end %--------------------------------------------------------------- function [i,j] = getAdjustedCrosshairIdx(hfig) % Find image matrix coordinate pair (j,i) under crosshair. % Adjust crosshair for "half-pixel offset" implicit in image display ud = get(hfig,'UserData'); xc = ud.crosshair.xctr; yc = ud.crosshair.yctr; hsurface = ud.hsurface; im = get(hsurface,'CData'); % Get image pixel size: xdata = get(hsurface,'XData'); if length(xdata)>1 dx = xdata(2)-xdata(1); else dx=0; end ydata=get(hsurface,'YData'); if length(ydata)>1 dy = ydata(2)-ydata(1); else dy=0; end % Remove half a pixel size from apparent cursor Position: xc = xc-dx/2; yc = yc-dy/2; % Find pixel coordinate under the crosshair: i = find(xc>=xdata); if isempty(i) i=1; else i=i(end)+1; end j=find(yc>=ydata); if isempty(j) j=1; else j=j(end)+1; end sz=size(im); if i>sz(2) i=sz(2); end if j>sz(1) j=sz(1); end end %--------------------------------------------------------------- function v = getSpecVal(hfig) ud = get(hfig,'UserData'); surfCData = get(ud.hsurface,'CData'); [i,j] = getAdjustedCrosshairIdx(hfig); v = double(surfCData(j,i)); end %--------------------------------------------------------------- function v = getRPMVal(hfig) ud = get(hfig,'UserData'); yd = get(ud.htimePlot,'YData'); i = getAdjustedCrosshairIdx(hfig); v = double(yd(i)); end %--------------------------------------------------------------- function updateTimeReadout(hfig) ud = get(hfig,'UserData'); t = ud.crosshair.xctr; prefix='T = '; % Update time readout [y,~,u] = engunits(t, 'latex','time'); if strcmp(u, 'secs') u = 's'; end str = [prefix sprintf('%.3f',y) ' ' u]; set(ud.htextTime,'String',str); end %--------------------------------------------------------------- function updateFreqReadout(hfig) ud = get(hfig,'UserData'); isOrderMap = strcmpi(ud.MapType, 'Order'); f = ud.crosshair.yctr; if isOrderMap str= [getStrFromCat('orderReadoutLbl') ' = ' sprintf('%.3f',f)]; else [y,~,u] = engunits(f,'latex'); prefix='F = '; unitsPostFix = 'Hz'; str=[prefix sprintf('%.3f',y) ' ' u unitsPostFix]; end % Update freq readout set(ud.htextFreq,'String',str); end %--------------------------------------------------------------- function updateRpmReadout(hfig) ud = get(hfig,'UserData'); prefix = 'RPM = '; rpm = getRPMVal(hfig); str = [prefix sprintf('%.3f',rpm)]; set(ud.htextRpm,'String',str); end %--------------------------------------------------------------- function updateAmpReadout(hfig) ud = get(hfig,'UserData'); switch ud.AmplitudeType case 'rms' prefix = [getStrFromCat('rmsAmpReadoutLbl') ' = ']; case 'peak' prefix = [getStrFromCat('peakAmpReadoutLbl') ' = ']; case 'power' prefix = [getStrFromCat('power') ' = ']; end if strcmpi(ud.Scale, 'dB') postfix = ' dB'; else postfix = ''; end % Update amplitude readout a = getSpecVal(hfig); str=[prefix sprintf('%.3f',a) postfix]; set(ud.htextAmp,'String',str); end %--------------------------------------------------------------- function wbmotionCross(~,~,sel) % motion callback during horiz/vert-crosshair selection % sel='h', 'v', or 'hv' % Get current point in axis ASAP: hfig = gcbf; hco = gco; switch get(hco,'Type') case 'axes' hax=hco; otherwise hax=get(hco,'Parent'); end cp = get(hax,'CurrentPoint'); if cp(1,2) < 0 % Do not move the cursors if pointer is outside axes return; end ud = get(hfig,'UserData'); x = cp(2,1); y = cp(2,2); switch sel case 'h' x = ud.crosshair.xctr; case 'v' y = ud.crosshair.yctr; end % Constrain to axis limits, so we don't lose cursor: if any(sel == 'v'), xlim = get(hax,'XLim'); if x < xlim(1), x = xlim(1); elseif x > xlim(2), x = xlim(2); end end if any(sel == 'h'), ylim = get(hax,'YLim'); if y < ylim(1), y = ylim(1); elseif y > ylim(2), y = ylim(2); end end setCrosshairs(hfig,x,y); end %--------------------------------------------------------------- function installCursorFcns(hfig,cursorType) switch lower(cursorType) case 'none' dn = []; motion = []; up = []; status = ''; case 'general' dn = []; motion = @wbmotionGeneral; up = []; status = ''; case 'thumb' % button not pushed, thumbnail highlighted dn = @wbdownThumb; motion = @wbmotionGeneral; up = []; status = getStrFromCat('panZoomWindow'); case 'thumb_buttondown' % button pushed, thumbnail highlighted dn = []; motion = @wbmotionThumb; up = @wbupThumb; status = getStrFromCat('releaseToSetZoomWindow'); case 'thumbleft' % button not pushed, left thumbnail edge highlighted dn = @wbdownThumbLeft; motion = @wbmotionGeneral; up = []; status = getStrFromCat('adjustZoomWinLeft'); case 'thumbleft_buttondown' % button pushed, thumbnail highlighted dn = []; motion = @wbmotionThumbLeft; up = @wbupThumbLeft; status = getStrFromCat('releaseToSetZoomWindow'); case 'thumbright' % button not pushed, right thumbnail edge highlighted dn = @wbdownThumbRight; motion = @wbmotionGeneral; up = []; status = getStrFromCat('adjustZoomWinRight'); case 'thumbright_buttondown' % button pushed, right thumbnail edge highlighted dn = []; motion = @wbmotionThumbright; up = @wbupThumbRight; status = getStrFromCat('releaseToSetZoomWindow'); case 'hcross' % button not pushed, h-crosshair highlighted dn = @wbdownHCross; motion = @wbmotionGeneral; up = []; status = getStrFromCat('moveHCursor'); case 'hcross_buttondown' % button pushed while over horiz cross-hair dn = []; motion = {@wbmotionCross,'h'}; up = @wbupHCross; status = getStrFromCat('releaseToUpdateCursor'); case 'vcross' dn = @wbdownVCross; motion = @wbmotionGeneral; up = []; status = getStrFromCat('moveVCursor'); case 'vcross_buttondown' dn = []; motion = {@wbmotionCross,'v'}; up = @wbupVCross; status = getStrFromCat('releaseToUpdateCursor'); case 'hvcross' dn = @wbdownHVCross; motion = @wbmotionGeneral; up = []; status = getStrFromCat('moveCrossHairCursor'); case 'hvcross_buttondown' dn = []; motion = {@wbmotionCross,'hv'}; up = @wbupHVCross; status = getStrFromCat('releaseToUpdateCursor'); % Change dynamic range of colormap case 'cmap' dn = @wbdownCmap; motion = @wbmotionGeneral; up = []; % Status is set in wbmotionGeneral function since it depends on which % pointer we're using status = -1; case 'cmap_buttondown' dn = []; motion = @wbmotionCmap; up = @wbupCmap; status = getStrFromCat('releaseToUpdateCmap'); case 'zoomdrag' dn = @wbdownZoom; motion = @wbmotionGeneral; up = []; status = getStrFromCat('zoomDragStatus'); case 'zoomout' dn = @wbdownZoom; motion = @wbmotionGeneral; up = []; status = getStrFromCat('zoomOutStatus'); case 'zoom_buttondown' dn = []; motion = @wbmotionZoom; up = @wbupZoom; status = getStrFromCat('zoomButtonUpStatus'); otherwise error(message('signal:rpmmapplot:invalidParamCursorFcn')); end set(hfig, ... 'WindowButtonDownFcn', dn, ... 'WindowButtonMotionFcn',motion, ... 'WindowButtonUpFcn', up) updateStatus(hfig,status); end %--------------------------------------------------------------- function resizeFig(~,~) % Callback to resize the figure updateAxesWithEngUnits(gcbf); end %--------------------------------------------------------------- function updateAxesWithEngUnits(hfig) % Update the tick marks for axes that are using engineering units For % example, a resize could have added or removed ticks, and the axes would % no longer have the proper tick marks. ud = get(hfig,'UserData'); hFrame = getappdata(hfig, 'UIMgr'); if strcmp(hFrame.Enable, 'on') haxSpec = ud.hax(1); haxTime = ud.hax(2); % Update freq-axis labels for engineering units yy = get(haxSpec,'YTick'); [cs,eu] = convert2engstrs(yy); set(haxSpec,'YTickLabel',cs); if strcmpi(ud.MapType, 'Order') m = getMultiplier(eu); if isempty(m) set(get(haxSpec,'YLabel'),'String',getStrFromCat('orderReadoutLbl')); else set(get(haxSpec,'YLabel'),'String',... [getStrFromCat('orderReadoutLbl') ' (' m ')']); end else set(get(haxSpec,'YLabel'),... 'String',[getStrFromCat('frequencyLbl') ' (' eu 'Hz)']); end if ud.View3DStatus % Set time axis label and tick labels for spectrogram plot yy = get(haxSpec,'XTick'); [cs,eu] = convert2engstrs(yy,'time'); set(haxSpec,'XTickLabel',cs); if strcmp(eu,'secs') eu = 's'; end set(get(haxSpec,'XLabel'),'String',[getStrFromCat('timeLbl') ' (' eu ')']); end % Update time-axis labels for engineering units xt = get(haxTime,'XTick'); [cs,eu] = convert2engstrs(xt,'time'); set(haxTime,'XTickLabel',cs); if strcmp(eu,'secs') eu = 's'; end set(get(haxTime,'XLabel'),'String',[getStrFromCat('timeLbl') ' (' eu ')']); if ud.RPMVect(end) >= 10e3 yt = get(haxTime,'YTick'); [cs,eu] = convert2engstrs(yt); set(haxTime,'YTickLabel',cs); m = getMultiplier(eu); if isempty(m) set(get(haxTime,'YLabel'),'String','RPM'); else set(get(haxTime,'YLabel'),'String',... ['RPM' ' (' m ')']); end end end end %--------------------------------------------------------------- function updateSpecTimeAxesWithEngUnits(hfig) ud = get(hfig,'UserData'); haxSpec = ud.hax(1); % Set time axis label and tick labels for spectrogram plot yy = get(haxSpec,'XTick'); [cs,eu] = convert2engstrs(yy,'time'); set(haxSpec,'XTickLabel',cs); if strcmp(eu,'secs') eu = 's'; end set(get(haxSpec,'XLabel'),'String',[getStrFromCat('timeLbl') ' (' eu ')']); end %--------------------------------------------------------------- function updateGUI(~, ~, hfig) if nargin < 3 hfig=gcbf; end ptr.ptr = get(hfig,'Pointer'); ptr.shape = get(hfig,'PointerShapeCData'); ptr.hot = get(hfig,'PointerShapeHotSpot'); setptr(hfig,'watch'); % set user's expectations... ud = get(hfig,'UserData'); haxSpec = ud.hax(1); haxTime = ud.hax(2); haxCbar = ud.hax(3); b = ud.Map; t = ud.t; f = ud.f; % Delete map matrix to reduce memory usage ud.Map = []; if strcmpi(ud.Scale, 'dB') % Handle -inf's: i_inf = find(isinf(b(:))); if ~isempty(i_inf), % Set all -inf points to next-lowest value: b(i_inf)=inf; min_val=min(b(:)); b(i_inf)=min_val; end end blim = [min(b(:)) max(b(:))]; rpmlim = [min(ud.RPMRef) max(ud.RPMRef)]; % Leave 20% space in upper limit deltaLim = diff(blim); rpmdeltaLim = diff(rpmlim); % If the upper and lower limits are the same, set rpmdeltaLim to the % rpm limit value if rpmdeltaLim == 0 rpmdeltaLim = rpmlim(1); end specZlim = [blim(1) blim(2)+deltaLim*.2]; specXlim = [0 max(t)]; specYlim = [0 max(f)]; % Leave 10% space in upper limit and lower limit rpmYlim = [rpmlim(1)-rpmdeltaLim*0.1 rpmlim(2)+rpmdeltaLim*0.1]; % Update spectrogram set(ud.hsurface,'CData',b, 'ZData',b, 'XData',t, 'YData',f); haxSpec.View = [0 90]; set(haxSpec,'XLim',specXlim, 'YLim', specYlim, 'ZLim', specZlim); % Update colorbar set(ud.himageCbar,'XData',[0 1], 'YData',blim, 'CData', (1:256)'); set(haxCbar,'XLim',[0 1],'YLim',blim); % This creates the RPM trace that goes on the pannable time plot below the % main plot set(ud.hrpmRef,'XData',ud.TimeRef,'YData',ud.RPMRef); set(ud.htimePlot,'XData',t,'YData',ud.RPMVect); set(haxTime,'XLim',specXlim); set(haxTime,'YLim',rpmYlim); % setup thumbnail patch axylim = get(haxTime,'YLim'); ymax = axylim(2); ymin = axylim(1); tmax = max(t); tmin = min(t); set(ud.hthumb, ... 'XData',[tmin tmax tmax tmin tmin], ... 'YData',[ymin ymin ymax ymax ymin]); % Reset crosshair positions crosshair = ud.crosshair; crosshair.xctr = mean(specXlim); crosshair.yctr = mean(specYlim); timeYlim = get(haxTime,'YLim'); % Crosshairs: set(ud.hspecX, ... 'XData',specXlim, ... 'YData',[crosshair.yctr crosshair.yctr],... 'ZData',[specZlim(2), specZlim(2)]); set(ud.hspecY, ... 'XData',[crosshair.xctr crosshair.xctr],... 'YData',specYlim,... 'ZData',[specZlim(2), specZlim(2)]); set(ud.htimeY, ... 'XData',[crosshair.xctr crosshair.xctr],... 'YData',timeYlim); % Update user data: ud.crosshair = crosshair; set(hfig,'UserData',ud); % Text readouts: updateTimeReadout(hfig); updateFreqReadout(hfig); updateAmpReadout(hfig); updateRpmReadout(hfig); % Re-establish pointer cursor, etc: set(hfig,'Pointer',ptr.ptr, ... 'PointerShapeCData',ptr.shape, ... 'PointerShapeHotSpot',ptr.hot); %Set to normal display zoomFull(0, 0, hfig); end %--------------------------------------------------------------- function printdlgCb(~,~) printdlg(gcbf); end %--------------------------------------------------------------- function printpreviewCb(~,~, ~) printpreview(gcbf); end %--------------------------------------------------------------- function closeCb(~,~) delete(gcbf); end %--------------------------------------------------------------- function createGraphics(hfig, map, freqVect, timeVect, rpmVect, scale, amp, rpmRef, timeRef) %createGraphics Render the graphics. hfig.Colormap = parula; ud = get(hfig,'UserData'); hVisParent = hfig; if isappdata(hfig, 'UIMgr') hVisParent = get(getappdata(hfig, 'UIMgr'), 'hVisParent'); end haxSpecSizeLarge = [.1 .32 .74 .63]; haxSpecSizeMedium = [.1 .37 .67 .58]; haxSpecSizeSmall = [.115 .38 .64 .57]; haxCbarSizeLarge = [.85 .321 .03 .630]; haxTimeSizeLarge = [.1 .15 .74 .14]; % specgram axes haxSpec = axes('Parent',hVisParent, 'Position',haxSpecSizeLarge); set(haxSpec, 'Box','on', 'XTickLabel','', 'XGrid', 'on','YGrid', 'on', ... 'ZGrid','on','Tag','rpmmapplotSpecAxesTag'); if strcmpi(ud.MapType, 'order') str = getStrFromCat('orderMap'); else str = getStrFromCat('freqMap'); end set(get(haxSpec,'Title'),'String', str); % specgram surface hSurf = surface('Parent',haxSpec, 'edgecolor', 'none',... 'Tag','rpmmapplotSurfaceTag'); % colorbar cmapLen = 256; haxCbar = axes('Parent',hVisParent,'Position',haxCbarSizeLarge); himageCbar = image([0 1],[0 1],(1:cmapLen)','Tag','rpmmapplotCBarImgTag'); set(himageCbar,'CDataMapping','scaled'); set(haxCbar, ... 'Box','on', ... 'YDir','normal', ... 'XTickLabel','', ... 'XTick',[],... 'YAxisLocation','right',... 'Tag','rpmmapplotCBarAxesTag'); str = getStrFromCat(amp); if strcmpi(scale,'dB') str = [str ' (dB)']; end set(get(haxCbar,'YLabel'),'String', str); % RPM panner haxTime = axes('Parent',hVisParent, 'Position',haxTimeSizeLarge); % RPM plot - shows original RPM profile curve htimePlot = line('Parent', haxTime, 'Color','b','Tag','rpmmapplotPannerMarkerTag'); set(htimePlot,'LineStyle','none','Marker','o','MarkerSize',2,'MarkerFaceColor',[1 0 0],'MarkerEdgeColor',[1 0 0]); % RPM markers - show RPM values at center of each computed spectrogram % window hrpmRef = line('Parent', haxTime, 'Color','b','Tag','rpmmapplotPannerLineTag'); set(haxTime, ... 'Box','on',... 'YAxisLocation','left',... 'XGrid', 'on',... 'YGrid', 'on',... 'Tag','rpmmapplotPannerAxesTag'); axis tight ylabel('Parent',haxTime, 'RPM'); % xlabel will be updated later % thumbnail patch for panner bgclr = 'b'; hthumb = patch([0 0 1 1 0], [0 1 1 0 0], bgclr, 'Parent',haxTime,... 'Tag','rpmmapplotPannerPatchTag'); transparency = 0.1; % [0,1] controls transparency of patch FaceColor. bgclr = [.1 .1 .1]; % FaceColor of the patch set(hthumb,'EdgeColor',bgclr,'EdgeAlpha',transparency, ... 'FaceColor',bgclr,'FaceAlpha',transparency); % Put all spectrogram cursors, patches and zoom patches on an invisible % axes on top of spectrogram axes. Link View, Position, scale and limits of % spectrogram and cursor axes. haxTopOfSpec = axes('Parent',hVisParent, 'Position',haxSpecSizeLarge); set(haxTopOfSpec, 'Visible','off','Tag','rpmmapplotTopOfSpecAxesTag'); % haxSpec is first on vector so that its property values are set initially % on linked objects. hLinkAxesProps = linkprop([haxSpec, haxTopOfSpec],{'Position','XLim',... 'YLim','ZLim','XScale','YScale','View'}); % Cursors crosshair lines hspecX = line('Parent',haxTopOfSpec,'Tag','rpmmapplotSpecCursorXTag'); hspecY = line('Parent',haxTopOfSpec,'Tag','rpmmapplotSpecCursorYTag'); htimeY = line('Parent',haxTime,'Tag','rpmmapplotPannerCursorTag'); % Cursors cross-patches for 3D plot transparency = 0.05; % [0,1] controls transparency of patch FaceColor. bgclr = [.5 .5 .5]; % FaceColor of the patch hCursors3D = [... patch(NaN, NaN, bgclr, 'Parent',haxTopOfSpec,'Visible','off','Tag','rpmmapplotSpecCursorPatch1Tag'),... patch(NaN, NaN, bgclr, 'Parent',haxTopOfSpec,'Visible','off','Tag','rpmmapplotSpecCursorPatch2Tag')]; set(hCursors3D,'EdgeColor',bgclr,'EdgeAlpha',transparency, ... 'FaceColor',bgclr,'FaceAlpha',transparency,'Visible','off'); % Thumbnail patch for zoom hthumbZoom = patch([0 0 1 1 0], [0 1 1 0 0], bgclr, 'Parent',haxTopOfSpec); transparency = 0.3; % [0,1] controls transparency of patch FaceColor. bgclr = [.5 .5 .5]; % FaceColor of the patch set(hthumbZoom,'EdgeColor',bgclr,'EdgeAlpha',transparency, ... 'FaceColor',bgclr,'FaceAlpha',transparency,'Visible','off'); % Patches for for 3D zoom transparency = 0.2; % [0,1] controls transparency of patch FaceColor. bgclr = [.5 .5 .5]; % FaceColor of the patch hthumbZoom3D = [... patch([0 0 1 1 0], [0 1 1 0 0], bgclr, 'Parent',haxTopOfSpec,'Visible','off'),... patch([0 0 1 1 0], [0 1 1 0 0], bgclr, 'Parent',haxTopOfSpec,'Visible','off'),... patch([0 0 1 1 0], [0 1 1 0 0], bgclr, 'Parent',haxTopOfSpec,'Visible','off'),... patch([0 0 1 1 0], [0 1 1 0 0], bgclr, 'Parent',haxTopOfSpec,'Visible','off')]; set(hthumbZoom3D,'EdgeColor',bgclr,'EdgeAlpha',transparency, ... 'FaceColor',bgclr,'FaceAlpha',transparency,'Visible','off'); % Text readouts: w = 0.247; h = 0.04; xpos = 0.006; ypos = 0.007; lblXpos = .018; lblYpos = 0.5; font = {'FontSize',8}; haxReadout1 = axes('Parent',hVisParent,'Position',[xpos ypos w h],'Visible','off',... 'Tag','rpmmapplotReadout1Tag'); patch([0 1 1 0 0],[0 0 1 1 0],'w'); htextFreq = text('Parent',haxReadout1, 'Position',[lblXpos lblYpos], font{:}); haxReadout2 = axes('Parent',hVisParent,'Position',[xpos+w ypos w h],'Visible','off',... 'Tag','rpmmapplotReadout2Tag'); patch([0 1 1 0 0],[0 0 1 1 0],'w'); htextRpm = text('Parent',haxReadout2, 'Position',[lblXpos lblYpos], font{:}); haxReadout3 = axes('Parent',hVisParent,'Position',[xpos+2*w ypos w h],'Visible','off',... 'Tag','rpmmapplotReadout3Tag'); patch([0 1 1 0 0],[0 0 1 1 0],'w'); htextTime = text('Parent',haxReadout3, 'Position',[lblXpos lblYpos], font{:}); haxReadout4 = axes('Parent',hVisParent,'Position',[xpos+3*w ypos w h],'Visible','off',... 'Tag','rpmmapplotReadout4Tag'); patch([0 1 1 0 0],[0 0 1 1 0],'w'); htextAmp = text('Parent',haxReadout4, 'Position',[lblXpos lblYpos], font{:}); set([haxTopOfSpec haxCbar haxTime], 'SortMethod','childorder'); % Retain info in figure userdata ud.hfig = hfig; ud.hax = [haxSpec, haxTime, haxCbar]; ud.hspecX = hspecX; ud.hspecY = hspecY; ud.htimeY = htimeY; ud.htimePlot = htimePlot; ud.hrpmRef = hrpmRef; ud.htextTime = htextTime; ud.htextFreq = htextFreq; ud.htextAmp = htextAmp; ud.htextRpm = htextRpm; ud.htextStatus = []; ud.crosshair = []; ud.hsurface = hSurf; ud.himageCbar = himageCbar; ud.hthumb = hthumb; ud.hthumbZoom = hthumbZoom; ud.hthumbZoom3D = hthumbZoom3D; ud.hCursors3D = hCursors3D; ud.currPtr = ''; % Need to save link object or properties will not be linked ud.hLinkAxesProps = hLinkAxesProps; ud.haxSpecSizeLarge = haxSpecSizeLarge; ud.haxSpecSizeMedium = haxSpecSizeMedium; ud.haxSpecSizeSmall = haxSpecSizeSmall; ud.haxCbarSizeLarge = haxCbarSizeLarge; ud.haxTimeSizeLarge = haxTimeSizeLarge; ud.f = freqVect; ud.t = timeVect; ud.Map = map; ud.RPMVect = rpmVect; ud.RPMRef = rpmRef; ud.TimeRef = timeRef; ud.Scale = scale; ud.AmplitudeType = amp; ud.ZoomOn = false; ud.ZoomMode = []; ud.ZoomOrigPt = []; ud.ZoomDestPt = []; ud.Zoom_XLimits = []; ud.Zoom_YLimits = []; ud.param_dlg = []; set(hfig,'UserData',ud); % Protect GUI from user plots, etc: set([hfig ud.hax],'HandleVisibility','Callback'); % After GUI has all elements in it, install context help: installContextHelp(hfig); installContextMenus(hfig); % Populate GUI with data, limits, etc: updateGUI([],[],hfig); % Enable general (non-segmenting) mouse functions: installCursorFcns(hfig,'general'); set(hfig,'Visible','on'); if isappdata(hfig, 'UIMgr') hFrame = getappdata(hfig, 'UIMgr'); hFrame.Enable = 'on'; end % Initial settings updateAxesWithEngUnits(hfig); updateStatus(hfig); centerCursors([],[],hfig); end % --------------------------------------------------------------- % H E L P S Y S T E M % -------------------------------------------------------------- %-------------------------------------------------------------- function installContextHelp(hfig) ud = get(hfig,'UserData'); main = {'Label','&What''s This?', 'Callback',@HelpGeneral, 'Parent'}; setWTC(hfig, main, [ud.hsurface ud.hax(1)], 'Spectrogram image'); setWTC(hfig, main, ud.hthumb, 'Zoom Window Panner'); setWTC(hfig, main, [ud.himageCbar ud.hax(3)], 'Colorbar'); setWTC(hfig, main, ud.htextStatus, 'Status Bar'); setWTC(hfig, main, ud.htextAmp, 'Magnitude Readout'); setWTC(hfig, main, ud.htextFreq, 'Frequency Readout'); setWTC(hfig, main, ud.htextTime, 'Time Readout'); setWTC(hfig, main, [ud.htimePlot ud.hax(2)], 'Time Plot'); setWTC(hfig,main, ud.hspecX, 'Frequency Crosshair'); setWTC(hfig,main, [ud.htimeY ud.hspecY], 'Time Crosshair'); setWTC(hfig,main, ud.hfig, 'Spectrogram Demo'); end %-------------------------------------------------------------- function setWTC(hfig,main,hItem,tagStr) %#ok<INUSD,INUSL> % setWT Set the "What's This?" context menu and callback: hc = uicontextmenu('Parent',hfig); % Do not add context help for now, we will support this later. %uimenu(main{:},hc, 'Tag',['WT?' tagStr]); set(hItem,'UIContextMenu',hc); end % --------------------------------------------------------------- % C O N T E X T M E N U S % -------------------------------------------------------------- %----------------------------------------------------------------- function installContextMenus(hfig) installSpecgramModeMenus(hfig); installColorbarMenus(hfig); installTimePannerMenus(hfig); end %----------------------------------------------------------------- function installSpecgramModeMenus(hfig) % Additional menus to prepend to the spectrogram context menu: ud = get(hfig,'UserData'); hc = get(ud.hsurface,'UIContextMenu'); % Update the menu on-the-fly: set(hc,'Callback', @specgramMenuRenderCallback); hEntry=[]; opts={hc,getStrFromCat('fullView'),@zoomFull, 'Tag', 'fullViewCtxMenu'}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('centerCursors'),@centerCursors, 'Separator','on',... 'Tag', 'centerCursorstxMenu'}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('cascadePlot'),@toggle2D3DView, 'Separator','on',... 'Checked','off','Tag', 'cascadePlotCtxMenu'}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('rotateLeft'),@rotate3DViewLeft,... 'Tag', 'rotLeftCtxMenu'}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('rotateRight'),@rotate3DViewRight,... 'Tag', 'rotRightCtxMenu'}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('reset3DView'),@reset3DView,... 'Tag', 'reset3DViewCtxMenu'}; hEntry(end+1) = createContext(opts); % Give each menu item a vector of handles to all peer menus set(hEntry,'UserData',hEntry); end %----------------------------------------------------------------- function installColorbarMenus(hfig) % Additional menus to prepend to the colorbar context menu: ud = get(hfig,'UserData'); hc = get(ud.himageCbar,'UIContextMenu'); % ud.hax(1) also? opts={hc,getStrFromCat('colormap'),''}; hCmap = createContext(opts); hEntry=[]; % holds handles to each colormap menu item opts={hCmap,'Parula',@changeCMap, 'Checked','on'}; hEntry(end+1) = createContext(opts); opts={hCmap,'Jet',@changeCMap}; hEntry(end+1) = createContext(opts); opts={hCmap,'Hot',@changeCMap}; hEntry(end+1) = createContext(opts); opts={hCmap,'Gray',@changeCMap}; hEntry(end+1) = createContext(opts); opts={hCmap,'Bone',@changeCMap}; hEntry(end+1) = createContext(opts); opts={hCmap,'Copper',@changeCMap}; hEntry(end+1) = createContext(opts); opts={hCmap,'Pink',@changeCMap}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('setLimits'),@manualCmapLimits, 'Separator','on'}; createContext(opts); opts={hc,getStrFromCat('resetLimits'),@resetCmapLimits}; createContext(opts); % Give each menu item a vector of handles to all peer menus set(hEntry,'UserData',hEntry); %fixupContextOrder(hc); end %----------------------------------------------------------------- function installTimePannerMenus(hfig) % Additional menus to prepend to the time-panner context menu: ud = get(hfig,'UserData'); hthumb = ud.hthumb; % add to time axis as well? hc = get(hthumb, 'UIContextMenu'); % Update the menu on-the-fly: set(hc,'Callback', @focusMenuRenderCallback); hEntry=[]; % holds handles to each colormap menu item opts={hc,getStrFromCat('focusIn'),@focusTimeIn}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('previousFocus'),@focusTimePrev}; hEntry(end+1) = createContext(opts); opts={hc,getStrFromCat('resetFocus'),@focusTimeReset}; hEntry(end+1) = createContext(opts); % Give each menu item a vector of handles to all peer menus set(hEntry,'UserData',hEntry); %fixupContextOrder(hc); updateFocusHistoryMenu(hfig); % pass any focus context menu end %----------------------------------------------------------------- function specgramMenuRenderCallback(~, ~) hfig=gcbf; hparent=gcbo; ud = get(hfig,'UserData'); hAllMenus = get(hparent,'Children'); % vector of handles to context menus tags = {hAllMenus.Tag}; hRotateRight = hAllMenus(strcmp(tags, 'rotRightCtxMenu')); hRotateLeft = hAllMenus(strcmp(tags, 'rotLeftCtxMenu')); hReset = hAllMenus(strcmp(tags, 'reset3DViewCtxMenu')); if ud.View3DStatus ena = 'on'; else ena = 'off'; end set(hRotateRight,'Enable',ena); set(hRotateLeft,'Enable',ena); set(hReset,'Enable',ena); end %----------------------------------------------------------------- function hMenu = createContext(opts) % Helper function to append additional context menus args = {'Parent',opts{1}, 'Tag',opts{2}, 'Label',opts{2},'Callback',opts{3:end}}; hMenu = uimenu(args{:}); end %----------------------------------------------------------------- function fixupContextOrder(hContext) %#ok<DEFNU> % Put the first context menu entry (the "What's This?" entry) % last in the context menu list, and turn on the separator % for the "What's This?" entry childList = get(hContext,'Children'); childList = childList([end 1:end-1]); set(hContext,'Children',childList); set(childList(1),'Separator','on'); end %--------------------------------------------------------------- function changeCMap(~,~) hco=gcbo; hfig=gcbf; % Reset checks on all colormap menu items: set(get(hco,'UserData'),'Checked','off'); set(hco,'Checked','on'); % Update figure colormap: cmapStr = lower(get(hco,'Label')); cmap = feval(cmapStr); set(hfig,'Colormap',cmap); end % --------------------------------------------------------------- % F O C U S S Y S T E M % -------------------------------------------------------------- %--------------------------------------------------------------- function pushCurrToFocusHistory(hfig) ud = get(hfig,'UserData'); haxTime = ud.hax(2); % focus history is stored in userdata of time-panner axis as either an % empty vector or cell, or as a cell-array of 2-element x-lim vector. % get current time-axis limits currXlim = get(haxTime,'XLim'); currHistory = get(haxTime,'UserData'); if isempty(currHistory), updated_focus_history = {currXlim}; else updated_focus_history = [currHistory {currXlim}]; end set(haxTime,'UserData',updated_focus_history); updateFocusHistoryMenu(hfig); end %--------------------------------------------------------------- function hist_xlim = popFromFocusHistory(hfig) ud = get(hfig,'UserData'); haxTime = ud.hax(2); currXlim = get(haxTime,'XLim'); % get current time-axis limits currHistory = get(haxTime,'UserData'); if isempty(currHistory), % no prev focus info recorded warning(message('signal:rpmmapplot:popEmptyFocusStack')); hist_xlim = currXlim; else % Pop last history xlim hist_xlim = currHistory{end}; currHistory(end) = []; set(haxTime,'UserData',currHistory); end updateFocusHistoryMenu(hfig); end %--------------------------------------------------------------- function clearFocusHistory(hfig) % Remove all previous focus entries ud = get(hfig,'UserData'); haxTime = ud.hax(2); set(haxTime,'UserData',[]); updateFocusHistoryMenu(hfig); end %--------------------------------------------------------------- function updateFocusHistoryMenu(hfig) ud = get(hfig,'UserData'); haxTime = ud.hax(2); % Update 'Previous Focus' context menu label currHistory = get(haxTime,'UserData'); histLen = length(currHistory); str = getStrFromCat('prevFocus'); if histLen>0, str = [str ' (' num2str(histLen) ')']; ena = 'on'; else ena = 'off'; end % Get panner context menu handle: hmenu = findobj( get(get(ud.hthumb, 'UIContextMenu'),'Children'),'Tag',getStrFromCat('focusIn')); hAllMenus = get(hmenu,'UserData'); % vector of handles to context menus hFocusPrev = hAllMenus(2); set(hFocusPrev, 'Label',str); set(hAllMenus(2:3), 'Enable',ena); % Prev and Reset Focus menus end %--------------------------------------------------------------- function focusMenuRenderCallback(~, ~) % Used to update the enable of the "Focus In" menu item. Only enabled if % thumb_xlim ~= curr_xlim hfig=gcbf; hparent=gcbo; ud = get(hfig,'UserData'); hAllMenus = get(hparent,'Children'); % vector of handles to context menus % Enable 'Focus on Window' if zoom window is less than entire panner % hFocusIn = hAllMenus(end); % 'Focus on Zoom' entry haxTime = ud.hax(2); currXlim = get(haxTime,'XLim'); % get current time-axis limits % Get thumbnail xlim vector: thumbXdata = get(ud.hthumb,'XData'); % current thumbnail patch coords thumbXlim = [min(thumbXdata) max(thumbXdata)]; % convert to xlim if ~isequal(currXlim, thumbXlim) ena='on'; else ena='off'; end set(hFocusIn,'Enable',ena); end %--------------------------------------------------------------- function focusTimeIn(~,~) hfig=gcbf; % get current time-axis (panner) limits ud = get(hfig,'UserData'); haxTime = ud.hax(2); currXlim = get(haxTime,'XLim'); % Get thumbnail xlim vector: thumbXdata = get(ud.hthumb,'XData'); % current thumbnail patch coords thumbXlim = [min(thumbXdata) max(thumbXdata)]; % convert to xlim if ~isequal(currXlim, thumbXlim), pushCurrToFocusHistory(hfig); % Zoom in to thumb limits haxTime = ud.hax(2); set(haxTime,'XLim', thumbXlim); updateAxesWithEngUnits(gcbf); end end %--------------------------------------------------------------- function focusTimePrev(~,~) hfig=gcbf; ud = get(hfig,'UserData'); haxTime = ud.hax(2); % Reset to last focus xlim = popFromFocusHistory(hfig); set(haxTime, 'XLim',xlim); updateAxesWithEngUnits(gcbf); end %--------------------------------------------------------------- function focusTimeReset(~,~,hfig) % Remove all previous focus entries if nargin < 3 hfig=gcbf; end clearFocusHistory(hfig); % Reset focus zoom: ud = get(hfig,'UserData'); hax_time = ud.hax(2); surfXdata = get(ud.hsurface,'XData'); if length(surfXdata) == 1 set(hax_time, 'XLim', [0 surfXdata]); else set(hax_time,'XLim',[min(surfXdata), max(surfXdata)]); end updateAxesWithEngUnits(hfig); end % --------------------------------------------------------------- % UTILITY FUNCTIONS % -------------------------------------------------------------- function hFrame = createUIFramework(res, type) %createUIFramework Create the uiframework. % Create uimgr UI frame hFrame = CreateUIFrame(... type,... CreateBaseMenus,... CreateBaseToolbar,... CreateBaseStatusbar); % Render uimgr ui objets hFrame.render; % Top of the uimgr tree % technically, this is the only handle we really need to keep % all others could be found from this, using hFrame.findchild(...) ud.huiframe = hFrame; % Other params in the userdata: ud.bGraphic = false; ud.param_dlg = []; if strcmpi(type,'Order') ud.ResUnits = getStrFromCat('resReadoutUnits'); else ud.ResUnits = 'Hz'; end ud.ResTxt = [getStrFromCat('resReadoutLbl') ': ']; ud.ResValue = sprintf('%.3f',res); ud.MapType = type; ud.View3DStatus = false; set(hFrame.WidgetHandle,... 'Tag', 'rpmmapFigTag',... 'CloseRequestFcn', @closeCb, ... 'UserData', ud); hPrintBehavior = hggetbehavior(hFrame.WidgetHandle,'Print'); set(hPrintBehavior,'WarnOnCustomResizeFcn','off'); end %---------------------------------------------------------- function hm = CreateBaseMenus % Menus group hm = uimgr.uimenugroup('Menus'); % Files mFile = uimgr.uimenugroup('File', getStrFromCat('menuFile')); mFilePrint = uimgr.uimenugroup('PrintOpt'); mPrint = uimgr.uimenu('Print', getStrFromCat('menuPrint')); mPrint.setWidgetPropertyDefault('Callback',@printdlgCb); mPrintview = uimgr.uimenu('Printview', getStrFromCat('menuPrintPreview')); mPrintview.setWidgetPropertyDefault('Callback',@printpreviewCb); mFilePrint.add(mPrint, mPrintview); mFileOpt = uimgr.uimenugroup('FileOpt'); mClose = uimgr.uimenu('Close', getStrFromCat('menuClose')); mClose.setWidgetPropertyDefault('Callback', @closeCb); mFileOpt.add(mClose); mFile.add(mFilePrint, mFileOpt); % Tools mTool = uimgr.uimenugroup('Tools',getStrFromCat('menuTools')); mTitle = uimgr.uimenu('ChangeTitle', getStrFromCat('menuChangeTitle')); mTitle.setWidgetPropertyDefault('Callback', @changeTitle,... 'Tag','changeTitleToolsMenuItem'); mTitlegroup = uimgr.uimenugroup('Titlegroup',mTitle); mZoomfull = uimgr.uimenu('ZoomFull', getStrFromCat('menuFullView')); mZoomfull.setWidgetPropertyDefault('Callback', @zoomFull,... 'Tag','fullViewToolsMenuItem'); mZoomIn = uimgr.uimenu('ZoomIn', getStrFromCat('menuZoomIn')); mZoomIn.setWidgetPropertyDefault('Callback', @toggleZoom,... 'Tag','zoomInToolsMenuItem'); mZoomOut = uimgr.uimenu('ZoomOut', getStrFromCat('menuZoomOut')); mZoomOut.setWidgetPropertyDefault('Callback', @toggleZoom,... 'Tag','zoomOutToolsMenuItem'); mZoomX = uimgr.uimenu('ZoomX', getStrFromCat('menuZoomX')); mZoomX.setWidgetPropertyDefault('Callback', @toggleZoom,... 'Tag','zoomXToolsMenuItem'); mZoomY = uimgr.uimenu('ZoomY', getStrFromCat('menuZoomY')); mZoomY.setWidgetPropertyDefault('Callback', @toggleZoom,... 'Tag','zoomYToolsMenuItem'); mZoomgroup = uimgr.uimenugroup('Zoomgroup',mZoomfull,mZoomIn,mZoomOut,mZoomX,mZoomY); mCenterCursors = uimgr.uimenu('CenterCursors', getStrFromCat('menuCenterCursors')); mCenterCursors.setWidgetPropertyDefault('Callback', @centerCursors,... 'Tag','centerCursorsToolsMenuItem'); mCentergroup = uimgr.uimenugroup('Centergroup',mCenterCursors); m3D = uimgr.uimenu('3D', getStrFromCat('menuCascadePlot')); m3D.setWidgetPropertyDefault('Callback', @toggle2D3DView, ... 'Checked', 'off', 'Tag','cascadePlotToolsMenuItem'); mRotLeft = uimgr.uimenu('rotLeft3D', getStrFromCat('rotateLeft')); mRotLeft.setWidgetPropertyDefault('Callback', @rotate3DViewLeft,... 'Tag','rotLeftToolsMenuItem','Enable','off'); mRotRight = uimgr.uimenu('rotRight3D', getStrFromCat('rotateRight')); mRotRight.setWidgetPropertyDefault('Callback', @rotate3DViewRight,... 'Tag','rotRightToolsMenuItem','Enable','off'); mRotReset = uimgr.uimenu('rotReset3D', getStrFromCat('reset3DView')); mRotReset.setWidgetPropertyDefault('Callback', @reset3DView,... 'Tag','reset3DViewToolsMenuItem','Enable','off'); m3Dgroup = uimgr.uimenugroup('View3DGroup',m3D,mRotLeft,mRotRight,mRotReset); mTool.add(mTitlegroup,mZoomgroup,mCentergroup,m3Dgroup); hm.add(mFile, mTool); end %---------------------------------------------------------- function ht = CreateBaseToolbar icon_file = 'rpmmapploticons.mat'; icons = spcwidgets.LoadIconFiles(icon_file); bCenter = uimgr.uipushtool('Center'); bCenter.IconAppData = 'center_crosshair'; bCenter.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarCenterCursors'), ... 'ClickedCallback',@centerCursors, 'Tag', 'centerCursorsToolbarButton'); bCentergroup = uimgr.uibuttongroup('Centergroup', bCenter); bNormal = uimgr.uipushtool('normal'); bNormal.IconAppData = 'fit_to_view'; bNormal.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarFullView'), ... 'ClickedCallback', @zoomFull, 'Tag', 'fullViewToolbarButton'); bZoomIn = uimgr.uitoggletool('ZoomIn'); bZoomIn.IconAppData = 'zoom_in'; bZoomIn.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarZoomIn'), ... 'ClickedCallback',@toggleZoom,... 'Tag','zoomInToolbarButton'); bZoomOut = uimgr.uitoggletool('ZoomOut'); bZoomOut.IconAppData = 'zoom_out'; bZoomOut.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarZoomOut'), ... 'ClickedCallback',@toggleZoom,... 'Tag','zoomOutToolbarButton'); bZoomX = uimgr.uitoggletool('ZoomX'); bZoomX.IconAppData = 'toggle_zoom_x'; bZoomX.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarZoomX'), ... 'ClickedCallback',@toggleZoom, 'Tag', 'zoomXToolbarButton'); bZoomY = uimgr.uitoggletool('ZoomY'); bZoomY.IconAppData = 'toggle_zoom_y'; bZoomY.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarZoomY'), ... 'ClickedCallback',@toggleZoom, 'Tag', 'zoomYToolbarButton'); bCascade = uimgr.uitoggletool('CascadePlot'); bCascade.IconAppData = 'waterfall'; bCascade.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('toolbarCascadePlot'), ... 'ClickedCallback',@toggle2D3DView, 'Tag', 'cascadePlotToolbarButton'); bRotLeft = uimgr.uipushtool('rotLeft'); bRotLeft.IconAppData = 'rotateLeft'; bRotLeft.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('rotateLeft'), ... 'ClickedCallback',@rotate3DViewLeft, 'Tag', 'rotLeftToolbarButton',... 'Enable','off'); bRotRight = uimgr.uipushtool('rotRight'); bRotRight.IconAppData = 'rotateRight'; bRotRight.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('rotateRight'), ... 'ClickedCallback',@rotate3DViewRight, 'Tag', 'rotRightToolbarButton',... 'Enable','off'); bRotReset = uimgr.uipushtool('rotReset'); bRotReset.IconAppData = 'rotateReset'; bRotReset.setWidgetPropertyDefault(... 'TooltipString',getStrFromCat('reset3DView'), ... 'ClickedCallback',@reset3DView, 'Tag', 'resetViewToolbarButton',... 'Enable','off'); b3Dgroup = uimgr.uibuttongroup('view3DGroup', bCascade, bRotLeft,... bRotRight,bRotReset); bZoomgroup = uimgr.uibuttongroup('zoomgroup', bNormal, bZoomIn, bZoomOut, bZoomX, bZoomY); ht = uimgr.uitoolbar('Toolbar', bZoomgroup, bCentergroup, b3Dgroup); setappdata(ht, icons); end %---------------------------------------------------------- function hs = CreateBaseStatusbar hs = uimgr.uistatusbar('StatusBar'); hs.setWidgetPropertyDefault('Text', ''); hsRes = uimgr.uistatus('Res'); hsRes.setWidgetPropertyDefault(... 'Text', '', ... 'Tooltip', getStrFromCat('resReadoutToolTip'), ... 'Width', 160); hs.add(hsRes); % Use these if we want cursor readouts in status bar: % hsTime = uimgr.uistatus('Time'); % hsTime.setWidgetPropertyDefault(... % 'Text', 'T: ', ... % 'Tooltip', 'Time at vertical cursor.', ... % 'Width', 100); % hs.add(hsTime); % % hsFreq = uimgr.uistatus('Freq'); % hsFreq.setWidgetPropertyDefault(... % 'Text', 'F: ', ... % 'Tooltip', 'Frequency at horizontal cursor.', ... % 'Width', 100); % hs.add(hsFreq); % % hsRPM = uimgr.uistatus('RPM'); % hsRPM.setWidgetPropertyDefault(... % 'Text', 'RPM: ', ... % 'Tooltip', 'RPM at vertical cursor.', ... % 'Width', 100); % hs.add(hsRPM); % % hsAmp = uimgr.uistatus('Amp'); % hsAmp.setWidgetPropertyDefault(... % 'Text', 'A: ', ... % 'Tooltip', 'Amplitude at cursors intersection.', ... % 'Width', 100); % hs.add(hsAmp); end %---------------------------------------------------------- function hFrame = CreateUIFrame(type, hMenu, hToolbar, hStatusbar) hFrame = uimgr.uifigure('UIFrame',... hMenu,... hToolbar,... hStatusbar); hFrame.Visible = 'off'; if strcmpi(type,'Order') titStr = getStrFromCat('orderMap'); else titStr = getStrFromCat('freqMap'); end hFrame.setWidgetPropertyDefault('NumberTitle','off', ... 'Name',titStr, ... 'MenuBar','none', ... 'ToolBar','none', ... 'ResizeFcn',@resizeFig, ... 'Position',[624, 236, 720, 540],... 'PaperPositionMode','auto',... 'DockControls','Off'); hFrame.Enable = 'off'; end %---------------------------------------------------------- function update3DControlItems(hfig) ud = get(hfig,'UserData'); flag = ud.View3DStatus; tags = {... 'rotLeftToolsMenuItem',... 'rotRightToolsMenuItem',... 'reset3DViewToolsMenuItem',... 'rotLeftCtxMenu',... 'rotRightCtxMenu',... 'reset3DViewCtxMenu',... 'rotLeftToolbarButton',... 'rotRightToolbarButton',... 'resetViewToolbarButton'}; if flag % We are in 3D mode % Enable tool menu items and check the cascade plot checkbox enab = 'on'; else enab = 'off'; end item = findobj('Tag','cascadePlotToolsMenuItem'); set(item,'Checked',enab); item = findobj('Tag','cascadePlotCtxMenu'); set(item,'Checked',enab); item = findobj('Tag','cascadePlotToolbarButton'); set(item,'State',enab); for idx = 1:numel(tags) item = findobj('Tag',tags{idx}); set(item,'Enable',enab); end end %---------------------------------------------------------- function updateZoomControlItems(hfig) % Check if zoom is on, and the zoom state and synchronize all menu and % toolbar controls ud = get(hfig,'UserData'); zoomOn = ud.ZoomOn; zoomMode = ud.ZoomMode; tagsZoomIn = {'zoomInToolsMenuItem','zoomInToolbarButton','zoomInCtxMenu'}; tagsZoomOut = {'zoomOutToolsMenuItem','zoomOutToolbarButton','zoomOutCtxMenu'}; tagsZoomX = {'zoomXToolsMenuItem','zoomXToolbarButton','zoomXCtxMenu'}; tagsZoomY = {'zoomYToolsMenuItem','zoomYToolbarButton','zoomYCtxMenu'}; if zoomOn switch zoomMode case 'ZoomIn' setCtrlState(hfig,tagsZoomIn,'on'); setCtrlState(hfig,[tagsZoomOut,tagsZoomX,tagsZoomY],'off'); case 'ZoomOut' setCtrlState(hfig,tagsZoomOut,'on'); setCtrlState(hfig,[tagsZoomIn,tagsZoomX,tagsZoomY],'off'); case 'ZoomX' setCtrlState(hfig,tagsZoomX,'on'); setCtrlState(hfig,[tagsZoomIn,tagsZoomOut,tagsZoomY],'off'); case 'ZoomY' setCtrlState(hfig,tagsZoomY,'on'); setCtrlState(hfig,[tagsZoomIn,tagsZoomOut,tagsZoomX],'off'); end else setCtrlState(hfig,[tagsZoomIn,tagsZoomOut,tagsZoomX,tagsZoomY],'off'); end end %---------------------------------------------------------- function status = getZoomModeFromTag(ctrl) switch ctrl.Tag case {'zoomInToolsMenuItem','zoomInToolbarButton','zoomInCtxMenu'} status = 'ZoomIn'; case {'zoomOutToolsMenuItem','zoomOutToolbarButton','zoomOutCtxMenu'} status = 'ZoomOut'; case {'zoomXToolsMenuItem','zoomXToolbarButton','zoomXCtxMenu'} status = 'ZoomX'; case {'zoomYToolsMenuItem','zoomYToolbarButton','zoomYCtxMenu'} status = 'ZoomY'; otherwise status = []; end end %---------------------------------------------------------- function setCtrlState(hfig,tags,state) % Set checked or state property of control with tag in tags cell array to % the state in state input. for idx = 1:numel(tags) item = findobj(hfig,'Tag',tags{idx}); if ~isempty(item) if isprop(item,'Checked') item.Checked = state; elseif isprop(item,'State') item.State = state; end end end end %---------------------------------------------------------- function changeTitle(~,~,hfig) if nargin < 3 hfig = gcbf; end ud = get(hfig,'UserData'); haxSpec = ud.hax(1); dlgTitle = getStrFromCat('title'); prompt={[getStrFromCat('title') ':']}; tit = get(haxSpec,'Title'); def = {tit.String}; numLines = 1; strs = inputdlg(prompt,dlgTitle,numLines,def); if isempty(strs), return end tit.String = strs{1}; end %---------------------------------------------------------- function str = getStrFromCat(inStr) % Get string from catalog str = getString(message(['signal:rpmmapplot:' inStr])); end %---------------------------------------------------------- function m = getMultiplier(units) if isempty(units) m = ''; return; end switch units case 'y' m = '\times 1e-24'; case 'z' m = '\times 1e-21'; case 'a' m = '\times 1e-18'; case 'f' m = '\times 1e-15'; case 'p' m = '\times 1e-12'; case 'n' m = '\times 1e-9'; case '\mu' m = '\times 1e-6'; case 'm' m = '\times 1e-3'; case 'k' m = '\times 1e3'; case 'M' m = '\times 1e6'; case 'G' m = '\times 1e9'; case 'T' m = '\times 1e12'; case 'P' m = '\times 1e15'; case 'E' m = '\times 1e18'; case 'Z' m = '\times 1e21'; case 'Y' m = '\times 1e24'; end end