How to plot arrow with data coordinates in Matlab?
I know there is a function named annotation can plot arrows or double arrows. But annotation can only plot in normalized unit. For example:
annotation('arrows',[x1 x2],[y1 y2])
Here, [x1, x2] should be a ratio number less than one.
So, my question is how can I plot arrows with a true value rather than a normalized value?
I wonder if there is any other function can approach this or is there any function I can get the axis value of the figure so that I can adjust the true value into a normalized value.
I've just discovered this method, since I don't want to have to bother with normalised units. Use the latex interpreter:
figure plot([1:5],[1:5]*3,'.-') %// Say I want to put an arrow pointing to the location, [3 9] text(2.94,8.3,'\uparrow','fontsize',20) text(2.8,7.8,'point [3,9]')
To make the arrow longer, use a larger fontsize.
- Easier, faster and quicker than using normalised units
- Don't need to install any functions (good for us lazy people..)
- making use of the LaTeX interpreter, there is a whole range of arrows (up, down, left, right and other angles (see Symbol list)
- Definitely needs trial and error/tweaking to get the correct location of the arrow head relative to the POI.
- There is limited control over the length of the arrow
- Some latex commands aren't understood by the interpreter (boo).
For the positioning of annotations, Matlab offers the function dsxy2figxy to convert data space points to normalized space coordinates. However, for whatever reasons, the function is not included in the Matlab distribution and has to be "created" first.
Copy the following line into the command window and execute it to open the function in your editor.
To use the function dsxy2figxy save it somewhere in your matlab search path.
Please find the full instructions for the function dsxy2figxy at matlab-central: http://www.mathworks.de/help/techdoc/creating_plots/bquk5ia-1.html
Even though annotation uses normalized as default units, you can associate these objects to the current axes (gca) and use data units for setting X and Y properties.
Here is an example of plotting a single arrow.
plot(1:10); ha = annotation('arrow'); % store the arrow information in ha ha.Parent = gca; % associate the arrow the the current axes ha.X = [5.5 5.5]; % the location in data units ha.Y = [2 8]; ha.LineWidth = 3; % make the arrow bolder for the picture ha.HeadWidth = 30; ha.HeadLength = 30;
For anyone who comes across this topic looking to draw arrows in "data space" rather than in units relative to the figure and/or axes, I highly recommend arrow.m from the file exchange.
If I remember correctly you need to calculate the position of the axes in relation to the figure.
it should go like:
%% example plot clf plot(rand(5,2)*5) %% get info specific to the axes you plan to plot into set(gcf,'Units','normalized') set(gca,'Units','normalized') ax = axis; ap = get(gca,'Position') %% annotation from 1,2 to 3,4 xo = [1,3]; yo = [2,4]; xp = (xo-ax(1))/(ax(2)-ax(1))*ap(3)+ap(1); yp = (yo-ax(3))/(ax(4)-ax(3))*ap(4)+ap(2); ah=annotation('arrow',xp,yp,'Color','r');
Note Fixed offset in original calculation - ap(3),ap(4) are width and height of gca, not corner positions
After creating the annotation object you should set the property Units to an absolute one. Example:
arrowObj = annotation('arrow', [0.1 0.1], [0.5 0.5]); set(arrowObj, 'Units', 'centimeters'); set(arrowObj, 'Position', [1 1 3 5]);
One approach would be to define an arrowhead in the axis units:
Ax=[0 -0.003 0.003 0]; % (Ax,Ay) form an upward pointing arrowhead. Ay=[0.01 0.0060 0.0060 0.01]; Ax=Ax-mean(Ax); % center it on zero Ay=Ay-mean(Ay);
Then at desired arrowhead index in on a curve vv, compute
x1=vv(in,1); y1=vv(in,2); x2=vv(in+1,1); y2=vv(in+1,2); u=x2-x1; v=y2-y1; th=-pi/2+atan2(v,u); R=[cos(th) -sin(th); sin(th) cos(th)]; % Rotation matrix for local slope of vv. A=R*[Ax;Ay]; % Rotate the arrowhead. patch(x1+A(1,:),y1+A(2,:),'r','LineWidth',0.01) % plot rotated arrowhead at (x1,y1). plot(x1+A(1,:),y1+A(2,:),'r','LineWidth',0.01) % Kludge to make boundary red too (I'm sure there is a more elegant way).
Worked for me, for my particular circumstances.
You can use the 'arrow' component in the (well-documented) DaVinci Draw toolbox (full disclosure: I wrote/sell the toolbox, though arrows are free).
Example syntax and example output are below.
davinci( 'arrow', 'X', [0 10], 'Y', [0 2], <plus-lots-of-options> )