Positioning Annotations in Data Space

Example — Pinning Textarrows and Ellipses

Some annotation object types (arrow, doublearrow, textarrow, and ellipse) are attached to figures rather than to axes. This makes it difficult to programmatically place them precisely on an axes, especially if the axes changes its position. You can, however, still locate figure-based annotations in data space by applying a transformation to their coordinates. The following example shows how to do this using a function called dsxy2figxy that transforms figure coordinates to axes coordinates for the four types of annotations listed above.

Before following the steps given below, copy the code for dsxy2figxy and save in your current directory or elsewhere on the MATLAB® path.

  1. Create sine function data and make a line plot of it:

    x1 = 1:.1:4*pi;
    y1 = sin(x1)./sqrt(x1);
    figure
    plot(x1,y1)
    axis tight
  2. Interactively place a textarrow on the graph

    Using ginput, interactively locate a textarrow annotation. Two clicks are required by ginput:

    disp('Click graph to place arrow; first tail, then head:')
    [axx axy] = ginput(2);      % Returns list of x, list of y in data space
    % Get coords in figure space; gca will be correct even for subplots
    % Transform from data space to fig space
    [arrowx,arrowy] = dsxy2figxy(gca, axx, axy);
    har = annotation('textarrow',arrowx,arrowy);
    content = sprintf('(%4.2f,%4.2f)',axx(2), axy(2));
    % Plot anno text centered at the tail of the arrow
    set(har,'String',content,'Fontsize',8)
    

  3. Place an ellipse on the axes

    To place ellipses, a coordinate box (position rectangle) is needed instead of two x-y tuples. The function dsxy2figxy computes and returns a position rectangle if it is called with one:

    disp('Click in the axes to define the bounding box of an ellipse:')
    [axx axy] = ginput(2);      % Returns list of x, list of y in data space
    abox(1) = min(axx); abox(2) = min(axy);     % Get least x and y coords
    abox(3) = abs(axx(1)-axx(2));               % Get box width
    abox(4) = abs(axy(1)-axy(2));               % Get box height
    % Get coords in figure space; gca will be correct even for subplots
    [bbox] = dsxy2figxy(gca, abox);    % Xform from axes to fig space
    annotation('ellipse',bbox);
    

Here is the code for dsxy2figxy ; copy it to an M-file that can be called when you execute the example above:

function varargout = dsxy2figxy(varargin)
% dsxy2figxy -- Transform point or position from axis to figure coords
% 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);
%   [figx figy] = getaxannopos(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)]
axwidth = diff(axlim(1:2));
axheight = diff(axlim(3:4));
%% 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)/axwidth + axpos(1);
	varargout{2} = (y-axlim(3))*axpos(4)/axheight + axpos(2);
else                    % Transform and return a position rectangle
	pos(1) = (pos(1)-axlim(1))/axwidth*axpos(3) + axpos(1);
	pos(2) = (pos(2)-axlim(3))/axheight*axpos(4) + axpos(2);
	pos(3) = pos(3)*axpos(3)/axwidth;
	pos(4) = pos(4)*axpos(4)/axheight;
	varargout{1} = pos;
end
%% Restore axes units
set(hAx,'Units',axun)
  


 © 1984-2008- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS