# Continous angle variation between 2d data and some fixed reference point

For a list of 2d coordinates I want to determine the variation of the embedded angle between the line which is connecting each coordinate and a fixed reference point and the x axis.

(* some example coordinates *)

step = 0.1;
x = Table[Sin[alpha] + Sin[0.7 alpha], {alpha, 0, 2*Pi, step}];
y = Table[Cos[2 alpha], {alpha, 0, 2*Pi, step}];

coordinates = Transpose[{x, y}];

Show[
ListPlot[coordinates, AspectRatio -> Automatic, PlotRange -> All,
Frame -> True, FrameLabel -> {"x", "y"}],
Graphics[{Red, Line[{{0, 0}, {x[[5]], y[[5]]}}]}],
Graphics[{Red, Line[{{0, 0}, {x[[5]], 0}, {x[[5]], 0}}]}],
Graphics[{Red, Text["angle", {0.3, 0.1}]}],
Graphics[{Red,
Circle[{0, 0},
x[[5]], {VectorAngle[{x[[5]], 0}, {x[[5]], y[[5]]}], 0}]}]
]


{xref, yref} = {0, 0}; (* reference point *)

x = x - xref;
y = y - yref;

angle = ArcTan[x, y ]*180/Pi;

n = Length@coordinates;
coordinateNumber = Range[n];
data = Transpose[{coordinateNumber, angle}];


Question: How can I plot the angles where angle-"jumps" occur as a continuation of the data points seen before.

Here are three examples which are showing how the angle plot looks like (top: plot of data) and what I want to receive (below).

Case 1: x = Table[Sin[alpha] + Sin[0.7*alpha], {alpha, 0, 2*Pi, step}];

Case 2: x = Table[Sin[0.9*alpha] + Sin[0.7*alpha], {alpha, 0, 2*Pi, step}];

Case 3:

step = 0.01;
x = Table[Sin[alpha] + Sin[0.7 alpha], {alpha, 0, 10*Pi, step}];
y = Table[Cos[2 alpha], {alpha, 0, 10*Pi, step}];


I assume you have no jumps larger than 180° between consecutive points (otherwise, it's not obvious which way and how many turns the angle jumps). Having said that, we transform angles in the list of increments and force all increments to be in range (−180°; 180°):

MakeContinuous[angles_, fullCircle_: 360] := Accumulate[
{angles[[1]]} ~Join~ Mod[Differences[angles], fullCircle, -fullCircle/2]
]


That gives you the desired result with relative ease:

continuousAngle = MakeContinuous[angle];
continuousData = Transpose[{coordinateNumber, continuousAngle}];
ListPlot[continuousData]


### Second example

Your second example is somewhat different. If you look carefully at the equation

\begin{aligned}x&=\sin(0.9\alpha)+\sin(0.7\alpha)\\y&=\cos(2\alpha)\end{aligned}

you can notice that when $\alpha=\frac{5\pi}{4}$, $y=\cos\frac{5\pi}2=0$, $x=\sin\frac{7\pi}{8} + \sin\frac{9\pi}8=0$. So your curve goes exactly through the point of reference $(0,0)$:

ParametricPlot[{Sin[0.7 t] + Sin[0.9 t], Cos[2 t]}, {t, 0, 2 Pi}]


So you should expect the jump of 180°, but it's you to decide whether it should be +180° or −180° jump.

If you want a continuous function in these cases too, you may consider plotting “line angle” instead of “vector angle” (projective circle, if you want) by saying that full circle is 180°:

continuousAngle = MakeContinuous[angle, 180];
continuousData = Transpose[{coordinateNumber, continuousAngle}];
ListPlot[continuousData]


• This is great, but unfortunately does not solve Case 2. What could be the reason? @Carl Woll describes also a problem for the second example. – mrz Feb 22 '18 at 21:41
• I have added the explanation and suggestion about Case 2. – Vasily Mitch Feb 23 '18 at 11:31

Just modify the definition of the angles:

first case:

    angle = 180/\[Pi] If[#[[1]] < 0 && #[[2]] < 0,
ArcTan[-#[[1]], -#[[2]]] + \[Pi],
ArcTan[#[[1]], #[[2]]]] & /@ coordinates;


second case:

angle = 180/Pi Which[#[[1]] < 0 && #[[2]] < 0, ArcTan[-#[[1]], -#[[2]]],
#[[1]] < 0 && #[[2]] > 0, ArcTan[#[[1]], #[[2]]] - \[Pi],
True, ArcTan[#[[1]], #[[2]]]] & /@ coordinates;


• Thank you for your help. Is it possible to obtain a single general solution for the angle modification? For example when x = Table[ Sin[1.6 alpha] + Sin[0.1 alpha] + Sin[0.9 alpha], {alpha, 0, 2*Pi, step}]; another modification would be necessary (i.imgur.com/U9RzcIV.jpg). – mrz Feb 20 '18 at 16:35

You could use an NDSolveValue based approach. First, convert your angle definition into an ODE:

eqn = angle[coord] == ArcTan[x[coord], y[coord]];
D[eqn, coord]


angle'[ coord] == -((y[coord] x'[coord])/( x[coord]^2 + y[coord]^2)) + (x[coord] y'[coord])/( x[coord]^2 + y[coord]^2)

Next, convert your $x$ and $y$ data into interpolating functions:

step = 0.1;
x = Interpolation @ Table[Sin[alpha] + Sin[0.7 alpha], {alpha, 0, 2*Pi, step}];
y = Interpolation @ Table[Cos[2 alpha], {alpha, 0, 2*Pi, step}];


Finally, use NDSolveValue:

sol = NDSolveValue[
{D[eqn, coord], eqn /. coord -> 1},
angle,
{coord, 1, 2 Pi 10}
];


Visualization:

ListPlot[sol[Range[1, 2 Pi 10]]]


This approach seems to have a problem with your second example which I don't have time to investigate. For the third example we get:

step = 0.1;
x = Interpolation @ Table[Sin[alpha] + Sin[0.7 alpha], {alpha, 0, 10*Pi, step}];
y = Interpolation @ Table[Cos[2 alpha], {alpha, 0, 10*Pi, step}];

sol = NDSolveValue[
{D[eqn, coord], eqn /. coord -> 1},
angle,
{coord, 1, 100 Pi}
];

ListPlot[sol[Range[1, 100 Pi, .1]]]


With this approach you could also just use Plot

Plot[sol[x], {x, 1, 100 Pi}]


• Thanks a lot for this very interesting solution. Also Vasily Mitch in his answer mentions that with his code Case 2 cannot be solved. – mrz Feb 23 '18 at 11:00