3

MATLAB - How can one add arrows with constant magnitude that follow a trajectory in phase space ( image attached )

enter image description here

Community
  • 1
  • 1
jarhead
  • 1,821
  • 4
  • 26
  • 46
  • 1
    See also: [How to draw good looking arrows in Matlab?](http://stackoverflow.com/q/18214874/2278029) and [How to draw an arrow in Matlab?](http://stackoverflow.com/q/25729784/2278029). – horchler Nov 24 '15 at 21:12

2 Answers2

11

MATLAB has a built-in annotation function that can be used to generate arrows and place them on your plot. However, MATLAB unhelpfully has written this function in such a way that the xy inputs are normalized to the figure window containing the axes and not mapped to the data points in your axes. This means we need to convert them, an annoying task but not a very challenging one.

I have created a small functional example with one arrow to illustrate the process. This should be compatible with any xy trajectory:

function testcode
h.myfig = figure();
h.myaxes = axes('Parent', h.myfig);

x = -10:10;
y = x.^2;
h.myplot = plot(h.myaxes, x, y);

for ii = 1:(length(x) - 1)
    [newx, newy] = coordinate2normalized(h.myaxes, [x(ii) x(ii + 1)], [y(ii) y(ii + 1)]);

    if exist('temp', 'var') 
        % No need to create another object if we have one, update existing one instead
        set(temp, 'Units', 'Normalized');
        temppos = get(temp, 'Position');
        set(temp, 'X', newx);
        set(temp, 'Y', newy);
    else
        temp = annotation('arrow', newx, newy);
    end

    pause(0.05)
end
end

function [xnorm, ynorm] = coordinate2normalized(axishandle, x, y)
set(axishandle, 'Units', 'Normalized');
axisposition = get(axishandle, 'Position'); % Get position in figure window
axislimits = axis(axishandle);

axisdatawidth  = axislimits(2) - axislimits(1);
axisdataheight = axislimits(4) - axislimits(3);

% Normalize x position
xnorm = (x - axislimits(1))*(axisposition(3)/axisdatawidth) + axisposition(1);
% Normalize y position
ynorm = (y - axislimits(3))*(axisposition(4)/axisdataheight) + axisposition(2);
end

Which produces the following:

yay

When I have time I intend to flesh out the helper function at least slightly, and it will be maintained on GitHub.

sco1
  • 12,154
  • 5
  • 26
  • 48
  • 1
    nicely done. Totally optional, but just for the sake of completeness, you should keep a reverse function (like `normalized2coordinate`) along your original one in your repository. – Hoki Nov 24 '15 at 17:01
  • 1
    @Hoki definitely! Throwing up some todos and enhancements now before I forget :) – sco1 Nov 24 '15 at 17:08
  • @excaza, looks good, I will try to implement it and tell you how it goes – jarhead Nov 25 '15 at 07:47
  • @ excaze, one small issue, how do you remove the arrow line and remain only with the arrow head, or have the arrow line in a different color – jarhead Nov 26 '15 at 14:27
  • 1
    @jarhead see the [property documentation](http://www.mathworks.com/help/matlab/ref/annotationarrow-properties.html). The LineStyle property is probably what you want to adjust. – sco1 Nov 26 '15 at 18:36
-1

Is it correct to assume you already know the trajectory through phase space? In other words, is it correct to assume that you already know the x-y location and direction for each arrow to be drawn, and all you need is a function to draw the arrows?

If it is OK to use commercial 3rd party software, the (well-documented) DaVinci Draw toolbox (full disclosure: I wrote/sell the toolbox) provides a solution.

The basic syntax is:

davinci( 'arrow', 'X', [0 10], 'Y', [0 0] )

It sounds like you want to draw the arrow head only, with no shaft. One way to achieve this is to set Head.Length to the arrow length (10 in the example above):

davinci( 'arrow', 'X', [0 10], 'Y', [0 0], 'Head.Length', 10 )

The toolbox has lots of options for how to shape and stylize the arrow head. For example, to make the width and length of the arrow head closer in size to each other than happens when default values are chosen in the example above, you can add a specification for Head.Width:

davinci( 'arrow', 'X', [0 10], 'Y', [0 0], 'Head.Length', 10, 'Head.Width', 8 )

You may want to set your axes aspect ratio at 1:1 to make the arrow appear as intended:

daspect([1 1 1])

Here are some examples from the documentation (with and without shafts):

Arrow examples

Leonard Wayne
  • 185
  • 1
  • 2
  • 4
  • Whilst this does show how you can plot arrows, it does not answer the difficult part of the question, the following of the phase graph. – Adriaan Nov 30 '15 at 23:10