No BSD License  

Highlights from
Harmonic Cursors

from Harmonic Cursors by Jeffrey Daniels
Display harmonic cursors in frequency or time series plots.

harmonic_cursors(h)
function harmonic_cursors(h)
% HARMONIC_CURSORS Application M-file for harmonic_cursors
%
% Uses mouse-click input from user to set the value of the first
% harmonic, which diplays a line and lines for higher harmonics.
% Displays the value of the harmonics at the top of the axis, just 
% above the axis box.  You can nudge the first harmonic in small 
% increments by using the right mouse button; a right-click to the 
% left of the first harmonic will nudge it left, and vice-versa for 
% the right.  (There is a "nudge_factor" that can be adjusted to 
% make the nudge delta larger or smaller for your application.  
% It you want to remove the cursors, click once to get the 
% crosshairs, and then click off of the axis to the left or right.  
% 
% EXAMPLES: Can be used simply as a function call after a plot has 
% been generated:
% plot(x,y)
% harmonic_cursors(gca)
% 
% Alternatively, the function can be called from the command line,
% from another function, or using a callback object by passing
% the axis handle of the plot as the argument.
%
% Written 22-Jan-2003 19:12:50 by Jeff Daniels NSWCCD - ARD


if nargin == 0  % Perform Mouse Callback Function
    % Do not perform callback if zoom tool is active
    state = getappdata(gcf,'ZOOMFigureState');
    if ~isempty(state), break, end      
    
    % Get Axis Information and user input from mouse
    yaxlim=get(gca,'YLim');             % Get Y-Axis limits
    xaxlim=get(gca,'XLim');             % Get X-Axis limits        
    [x,y,button]=ginput(1);             % Get first harmonic data point   
    warning off
    
    if button==1,   % if left-click, plot new cursors       
        % Calculated x,y position of cursors and labels
        nlines = floor(xaxlim(2)/x);    % Calculate number of lines to display
        ypoint=yaxlim(2)+(yaxlim(2)-yaxlim(1))*0.035;   % This puts the label just above the axis box, but below the title.
        for i=1:nlines,
            xpoint=x*i;            
            xmat(1:2,i)=[xpoint;xpoint];
            label_h(i)=text(xpoint,ypoint,[num2str(i),'X = ',num2str(xpoint,4)],...
                'Color','red','FontName','Arial','FontSize',[8.0]);
        end
        ymat=repmat(yaxlim',1,nlines);
        
        % Remove cursors and labels from previous uses
        try
            old_line_h=findobj('Tag',['HarmonicCursor',num2str(gca)]);
            old_label_h=findobj('Tag',['HarmonicLabel',num2str(gca)]);
            delete(old_line_h)
            delete(old_label_h)
        catch
            disp(lasterr)
        end    
        
        % Draw Cursors and Labels
        line_h=line(xmat,ymat,'Color',[1 0 0],'Tag',['HarmonicCursor',num2str(gca)],...
            'LineWidth',[1.0],'LineStyle','--');
        line_props=get(line_h);
        set(label_h,'Tag',['HarmonicLabel',num2str(gca)])
        label_props=get(label_h);
        
    elseif button==3,   % if right-click, move cursors by bin_width
        try
            % Find line handles from previous uses and determine position
            old_line_h=findobj('Tag',['HarmonicCursor',num2str(gca)]);
            old_line_h=sort(old_line_h);    
            old_line_props=get(old_line_h(1));
            old_line_xpos=old_line_props.XData;            
            % This is an unsuccessful attempt to automatically scale the nudge factor.
%             data_h=findobj(gca,'Type','line','Tag','');
%             data_len=length(get(data_h,'XData'));
%             nudge_factor=min(data_len,10000)
			% This factor seems to work well for most data lengths, but can be adjusted.
	        nudge_factor=10000;     
            
            % Calculate bin_width value to nudge first harmonic by.
            bin_width=(xaxlim(2)-xaxlim(1))/nudge_factor*sign(x-old_line_xpos(1));  
            
            % Find label handles from previous uses and determine position
            old_label_h=findobj('Tag',['HarmonicLabel',num2str(gca)]);
            old_label_h=sort(old_label_h);
            old_label_props=get(old_label_h(1));
            old_label_pos=old_label_props.Position;
            
            % Change position of lines and labels by bin_width
            new_label_pos=old_label_pos;           
            new_label_pos(1)=old_label_pos(1)+bin_width;
            new_line_xpos=old_line_xpos+bin_width;               
            nlines = floor(xaxlim(2)/new_label_pos(1)); % Calculate number of lines to display  
            for i=1:nlines,                
                next_label_pos = new_label_pos;
                next_label_pos(1) = new_label_pos(1)*i;
                next_line_xpos = new_line_xpos*i;                
                set(old_line_h(i),'XData',next_line_xpos)
                set(old_label_h(i),'Position',next_label_pos,'String',[num2str(i),'X = ',num2str(next_label_pos(1),4)])
            end
        catch
            disp(lasterr)
        end   
    end
elseif nargin == 1  % Setup Mouse Callback Function
    if ishandle(h),
        try 
            get(h,'Type')=='axes';
            set(h,'ButtonDownFcn','harmonic_cursors')
        catch
            disp('Error: Argument is not a valid axis handle!')
        end
    end
end

Contact us at files@mathworks.com