Code covered by the BSD License  

Highlights from
Annotation pinned to axes

image thumbnail
from Annotation pinned to axes by Fred Gruber
This function extends the standard annotation function by making them pinned to the axes.

oh=annotation_pinned(varargin)
function oh=annotation_pinned(varargin)
% Create annotations that are pinned to the current axes. The use is the same as
% the standard annotation function (see help annotation). The only
% difference is that you can provide the axes.
% For example:
% figure
% ah1=subplot(2,1,1);
% 
% ah2=subplot(2,1,2);
% annotation_pinned('arrow',[0.1,0.2],[0.5,0.1],'axes',ah1);
% annotation_pinned('textarrow',[0.3,0.5],[0.3,0.5],'axes',ah2,'String','test $x^2$','Interpreter','Latex')
%
% Author: Fred Gruber
% August 2011

otherp={};
indo=1;
indn=1;
axesh=[];
tagn=[];
while indn<=nargin
    if strcmp(varargin{indn},'axes')
        axesh=varargin{indn+1};
        indn=indn+2;
    elseif strcmp(varargin{indn},'tag')
        tagn=varargin{indn+1};
        indn=indn+2;
    else
        otherp{indo}=varargin{indn};
        %             otherp{indo+1}=varargin{indn+1};
        indo=indo+1;
        indn=indn+1;
        
    end
    
    
end

if isempty(axesh)
   axesh= gca;
end
figh=get(axesh,'Parent');
ud=get(figh,'Userdata');

if ~isfield(ud,'annh')
   ud.annh={}; 
end

Na=length(ud.annh);
annh=[];
tempNa=Na+1;
if isempty(tagn)
    namea=['txtann' num2str(Na+1)];
   tagn=namea; 
   
else %does it exist. iF it does erase it
    namea=tagn;
    for indt=1:Na
       temp=ud.annh{indt};
       if strcmp(temp.tag,tagn)
           delete(temp.handle);
           %            annh=temp.handle;
           tempNa=indt;
       end
    end
end


set(figh,'Units','normalized');
% annh=findall(figh,'Tag',tagn);

annh=annotation( otherp{:});
set(annh,'Tag',namea);

pos=get(annh,'Position');
X(1)=pos(1);
X(2)=pos(3)+X(1);
Y(1)=pos(2);
Y(2)=pos(4)+Y(1);
[xaf,yaf] = dsxy2figxy_log(axesh,X,Y);

annf=get(annh);
if isfield(annf,'X')
    set(annh,'X',xaf,'Y',yaf);
else
    pos2=[xaf(1),yaf(1),xaf(2)-xaf(1),yaf(2)-yaf(1)];
    set(annh,'Position',pos2);
end
ud.annh{tempNa}=struct('X',X,'Y',Y,'tag',namea,'handle',annh,...
        'axes',axesh);
    
zh=zoom(figh);
set(zh,'ActionPostCallback',@afterzoom);
ph=pan(figh);
set(ph,'ActionPostCallback',@afterzoom);
set(ph,'ButtonDownFilter',@pandrag);
set(figh,'Userdata',ud);
set(figh,'WindowButtonUpFcn',@stopDragFcn);
end   

function afterzoom(obj,event_obj)

  ud=get(obj,'Userdata');
  
  if ~isempty(ud)
      for ind1=1:length(ud.annh)
          X=ud.annh{ind1}.X;
          Y=ud.annh{ind1}.Y;
           ah=ud.annh{ind1}.axes;
           av=axis(ah);
          [xaf,yaf] = dsxy2figxy_log(ah,X,Y);
          txth=ud.annh{ind1}.handle;
          pos=[xaf(1),yaf(1),xaf(2)-xaf(1),yaf(2)-yaf(1)];
          set(txth,'Position',pos);
          if av(1)>X(2) | av(4)<Y(2)|av(2)<X(2)|av(3)>Y(2)
              set(txth,'Visible','off');
          else
              set(txth,'Visible','on');
          end
      end
  end
    
     
     
     
     
end
 
function res=pandrag(obj,event_obj)
if strcmp(get(obj,'type'),'axes')
    fh=get(obj,'Parent');
else
    fh=get(get(obj,'Parent'),'Parent');
%     ud=get(get(get(obj,'Parent'),'Parent'),'Userdata');
end
set(fh,'WindowButtonMotionFcn',@draggingFcn);

  res=0;
     
end
 
   function draggingFcn(varargin)
%         aH=varargin{1};
% hl
   fh=varargin{1};
   ud=get(fh,'Userdata');
   if ~isempty(ud)
      for ind1=1:length(ud.annh)
          X=ud.annh{ind1}.X;
          Y=ud.annh{ind1}.Y;
           ah=ud.annh{ind1}.axes;
           av=axis(ah);
           
          [xaf,yaf] = dsxy2figxy_log(ah,X,Y);
          txth=ud.annh{ind1}.handle;
          pos=[xaf(1),yaf(1),xaf(2)-xaf(1),yaf(2)-yaf(1)];
          set(txth,'Position',pos);
          if av(1)>X(2) | av(4)<Y(2)|av(2)<X(2)|av(3)>Y(2)
              set(txth,'Visible','off');
          else
              set(txth,'Visible','on');
          end
      end
  end
      
    end

    function stopDragFcn(varargin)
    fh=varargin{1};
        set(fh,'WindowBUttonMotionFcn','');
    end
    
 
  

    
function varargout = dsxy2figxy_log(varargin)
% dsxy2figxy -- Transform point or position from axis to figure coords
% while correctly handling log scale for either X or Y axes
% Transforms [axx axy] or [xypos] from axes hAx (data) coords into coords
% wrt GCF for placing annotation objects that use figure coords into data
% space. The annotation objects this can be used for are
% arrow, doublearrow, textarrow
% ellipses (coordinates must be transformed to [x, y, width, height])
% Note that line, text, and rectangle anno objects already are placed
% on a plot using axes coordinates and must be located within an axes.
% Usage: Compute a position and apply to an annotation, e.g.,
% [axx axy] = ginput(2);
% set(gca, 'XScale', 'log');
% [figx figy] = dsxy2figxy_log(gca, axx, axy);
% har = annotation('textarrow',figx,figy);
% set(har,'String',['(' num2str(axx(2)) ',' num2str(axy(2)) ')'])

%% Obtain arguments (only limited argument checking is performed).
% Determine if axes handle is specified
if length(varargin{1})== 1 && ishandle(varargin{1}) && ...
strcmp(get(varargin{1},'type'),'axes')
hAx = varargin{1};
varargin = varargin(2:end);
else
hAx = gca;
end;
% Parse either a position vector or two 2-D point tuples
if length(varargin)==1 % Must be a 4-element POS vector
pos = varargin{1};
else
[x,y] = deal(varargin{:}); % Two tuples (start & end points)
end
%% Get limits
axun = get(hAx,'Units');
set(hAx,'Units','normalized'); % Need normaized units to do the xform
axpos = get(hAx,'Position');
axlim = axis(hAx); % Get the axis limits [xlim ylim (zlim)]
axxscale = get(hAx, 'XScale');
axyscale = get(hAx, 'YScale');

if strcmpi(axxscale, 'log'); % Handle log scale on X and Y axis
x = log10(x); axlim(1:2) = log10(axlim(1:2));
end
if strcmpi(axyscale, 'log');
y = log10(y); axlim(3:4) = log10(axlim(3:4));
end

%% Transform data from figure space to data space
if exist('x','var') % Transform a and return pair of points
varargout{1} = (x-axlim(1))*axpos(3)/(axlim(2)-axlim(1)) + axpos(1);
varargout{2} = (y-axlim(3))*axpos(4)/(axlim(4)-axlim(3)) + axpos(2);
else % Transform and return a position rectangle
pos(1) = (pos(1)-axlim(1))/(axlim(2)-axlim(1))*axpos(3) + axpos(1);
pos(2) = (pos(2)-axlim(3))/(axlim(4)-axlim(3))*axpos(4) + axpos(2);
pos(3) = pos(3)*axpos(3)/(axlim(2)-axlim(1));
pos(4) = pos(4)*axpos(4)/(axlim(4)-axlim(3));
varargout{1} = pos;
end
%% Restore axes units
set(hAx,'Units',axun)
end

Contact us