Calculate angle between two vectors python

I need to determine the angle[s] between two n-dimensional vectors in Python. For example, the input can be two lists like the following: [1,2,3,4] and [6,7,8,9].

Gabriel

38k69 gold badges218 silver badges379 bronze badges

asked May 13, 2010 at 14:06

1

Note: all of the other answers here will fail if the two vectors have either the same direction [ex, [1, 0, 0], [1, 0, 0]] or opposite directions [ex, [-1, 0, 0], [1, 0, 0]].

Here is a function which will correctly handle these cases:

import numpy as np

def unit_vector[vector]:
    """ Returns the unit vector of the vector.  """
    return vector / np.linalg.norm[vector]

def angle_between[v1, v2]:
    """ Returns the angle in radians between vectors 'v1' and 'v2'::

            >>> angle_between[[1, 0, 0], [0, 1, 0]]
            1.5707963267948966
            >>> angle_between[[1, 0, 0], [1, 0, 0]]
            0.0
            >>> angle_between[[1, 0, 0], [-1, 0, 0]]
            3.141592653589793
    """
    v1_u = unit_vector[v1]
    v2_u = unit_vector[v2]
    return np.arccos[np.clip[np.dot[v1_u, v2_u], -1.0, 1.0]]

answered Dec 12, 2012 at 21:47

David WoleverDavid Wolever

142k84 gold badges330 silver badges492 bronze badges

9

import math

def dotproduct[v1, v2]:
  return sum[[a*b] for a, b in zip[v1, v2]]

def length[v]:
  return math.sqrt[dotproduct[v, v]]

def angle[v1, v2]:
  return math.acos[dotproduct[v1, v2] / [length[v1] * length[v2]]]

Note: this will fail when the vectors have either the same or the opposite direction. The correct implementation is here: //stackoverflow.com/a/13849249/71522

answered May 13, 2010 at 14:14

Alex MartelliAlex Martelli

823k163 gold badges1202 silver badges1379 bronze badges

13

Using numpy [highly recommended], you would do:

from numpy import [array, dot, arccos, clip]
from numpy.linalg import norm

u = array[[1.,2,3,4]]
v = ...
c = dot[u,v]/norm[u]/norm[v] # -> cosine of the angle
angle = arccos[clip[c, -1, 1]] # if you really want the angle

answered May 13, 2010 at 14:13

Olivier VerdierOlivier Verdier

45k26 gold badges97 silver badges90 bronze badges

5

The other possibility is using just numpy and it gives you the interior angle

import numpy as np

p0 = [3.5, 6.7]
p1 = [7.9, 8.4]
p2 = [10.8, 4.8]

''' 
compute angle [in degrees] for p0p1p2 corner
Inputs:
    p0,p1,p2 - points in the form of [x,y]
'''

v0 = np.array[p0] - np.array[p1]
v1 = np.array[p2] - np.array[p1]

angle = np.math.atan2[np.linalg.det[[v0,v1]],np.dot[v0,v1]]
print np.degrees[angle]

and here is the output:

In [2]: p0, p1, p2 = [3.5, 6.7], [7.9, 8.4], [10.8, 4.8]

In [3]: v0 = np.array[p0] - np.array[p1]

In [4]: v1 = np.array[p2] - np.array[p1]

In [5]: v0
Out[5]: array[[-4.4, -1.7]]

In [6]: v1
Out[6]: array[[ 2.9, -3.6]]

In [7]: angle = np.math.atan2[np.linalg.det[[v0,v1]],np.dot[v0,v1]]

In [8]: angle
Out[8]: 1.8802197318858924

In [9]: np.degrees[angle]
Out[9]: 107.72865519428085

answered Feb 1, 2016 at 15:17

MK83MK83

1,29210 silver badges11 bronze badges

2

If you're working with 3D vectors, you can do this concisely using the toolbelt vg. It's a light layer on top of numpy.

import numpy as np
import vg

vec1 = np.array[[1, 2, 3]]
vec2 = np.array[[7, 8, 9]]

vg.angle[vec1, vec2]

You can also specify a viewing angle to compute the angle via projection:

vg.angle[vec1, vec2, look=vg.basis.z]

Or compute the signed angle via projection:

vg.signed_angle[vec1, vec2, look=vg.basis.z]

I created the library at my last startup, where it was motivated by uses like this: simple ideas which are verbose or opaque in NumPy.

answered Apr 4, 2019 at 13:29

paulmelnikowpaulmelnikow

16.6k7 gold badges61 silver badges113 bronze badges

Easy way to find angle between two vectors[works for n-dimensional vector],

Python code:

import numpy as np

vector1 = [1,0,0]
vector2 = [0,1,0]

unit_vector1 = vector1 / np.linalg.norm[vector1]
unit_vector2 = vector2 / np.linalg.norm[vector2]

dot_product = np.dot[unit_vector1, unit_vector2]

angle = np.arccos[dot_product] #angle in radian

answered Apr 5, 2020 at 13:15

Kevin PatelKevin Patel

5168 silver badges10 bronze badges

David Wolever's solution is good, but

If you want to have signed angles you have to determine if a given pair is right or left handed [see wiki for further info].

My solution for this is:

def unit_vector[vector]:
    """ Returns the unit vector of the vector"""
    return vector / np.linalg.norm[vector]

def angle[vector1, vector2]:
    """ Returns the angle in radians between given vectors"""
    v1_u = unit_vector[vector1]
    v2_u = unit_vector[vector2]
    minor = np.linalg.det[
        np.stack[[v1_u[-2:], v2_u[-2:]]]
    ]
    if minor == 0:
        raise NotImplementedError['Too odd vectors =[']
    return np.sign[minor] * np.arccos[np.clip[np.dot[v1_u, v2_u], -1.0, 1.0]]

It's not perfect because of this NotImplementedError but for my case it works well. This behaviour could be fixed [cause handness is determined for any given pair] but it takes more code that I want and have to write.

answered Jun 9, 2019 at 15:24

sgt peppersgt pepper

4247 silver badges13 bronze badges

For the few who may have [due to SEO complications] ended here trying to calculate the angle between two lines in python, as in [x0, y0], [x1, y1] geometrical lines, there is the below minimal solution [uses the shapely module, but can be easily modified not to]:

from shapely.geometry import LineString
import numpy as np

ninety_degrees_rad = 90.0 * np.pi / 180.0

def angle_between[line1, line2]:
    coords_1 = line1.coords
    coords_2 = line2.coords

    line1_vertical = [coords_1[1][0] - coords_1[0][0]] == 0.0
    line2_vertical = [coords_2[1][0] - coords_2[0][0]] == 0.0

    # Vertical lines have undefined slope, but we know their angle in rads is = 90° * π/180
    if line1_vertical and line2_vertical:
        # Perpendicular vertical lines
        return 0.0
    if line1_vertical or line2_vertical:
        # 90° - angle of non-vertical line
        non_vertical_line = line2 if line1_vertical else line1
        return abs[[90.0 * np.pi / 180.0] - np.arctan[slope[non_vertical_line]]]

    m1 = slope[line1]
    m2 = slope[line2]

    return np.arctan[[m1 - m2]/[1 + m1*m2]]

def slope[line]:
    # Assignments made purely for readability. One could opt to just one-line return them
    x0 = line.coords[0][0]
    y0 = line.coords[0][1]
    x1 = line.coords[1][0]
    y1 = line.coords[1][1]
    return [y1 - y0] / [x1 - x0]

And the use would be

>>> line1 = LineString[[[0, 0], [0, 1]]] # vertical
>>> line2 = LineString[[[0, 0], [1, 0]]] # horizontal
>>> angle_between[line1, line2]
1.5707963267948966
>>> np.degrees[angle_between[line1, line2]]
90.0

answered Apr 21, 2019 at 0:53

Building on sgt pepper's great answer and adding support for aligned vectors plus adding a speedup of over 2x using Numba

@njit[cache=True, nogil=True]
def angle[vector1, vector2]:
    """ Returns the angle in radians between given vectors"""
    v1_u = unit_vector[vector1]
    v2_u = unit_vector[vector2]
    minor = np.linalg.det[
        np.stack[[v1_u[-2:], v2_u[-2:]]]
    ]
    if minor == 0:
        sign = 1
    else:
        sign = -np.sign[minor]
    dot_p = np.dot[v1_u, v2_u]
    dot_p = min[max[dot_p, -1.0], 1.0]
    return sign * np.arccos[dot_p]

@njit[cache=True, nogil=True]
def unit_vector[vector]:
    """ Returns the unit vector of the vector.  """
    return vector / np.linalg.norm[vector]

def test_angle[]:
    def npf[x]:
        return np.array[x, dtype=float]
    assert np.isclose[angle[npf[[1, 1]], npf[[1,  0]]],  pi / 4]
    assert np.isclose[angle[npf[[1, 0]], npf[[1,  1]]], -pi / 4]
    assert np.isclose[angle[npf[[0, 1]], npf[[1,  0]]],  pi / 2]
    assert np.isclose[angle[npf[[1, 0]], npf[[0,  1]]], -pi / 2]
    assert np.isclose[angle[npf[[1, 0]], npf[[1,  0]]],  0]
    assert np.isclose[angle[npf[[1, 0]], npf[[-1, 0]]],  pi]

%%timeit results without Numba

  • 359 µs ± 2.86 µs per loop [mean ± std. dev. of 7 runs, 1000 loops each]

And with

  • 151 µs ± 820 ns per loop [mean ± std. dev. of 7 runs, 10000 loops each]

answered Jan 13, 2020 at 22:05

crizCraigcrizCraig

7,9485 gold badges53 silver badges52 bronze badges

Use some functions from numpy.

import numpy as np

def dot_product_angle[v1,v2]:

    if np.linalg.norm[v1] == 0 or np.linalg.norm[v2] == 0:
        print["Zero magnitude vector!"]
    else:
        vector_dot_product = np.dot[v1,v2]
        arccos = np.arccos[vector_dot_product / [np.linalg.norm[v1] * np.linalg.norm[v2]]]
        angle = np.degrees[arccos]
        return angle
    return 0

answered Apr 25, 2021 at 12:35

Using numpy and taking care of BandGap's rounding errors:

from numpy.linalg import norm
from numpy import dot
import math

def angle_between[a,b]:
  arccosInput = dot[a,b]/norm[a]/norm[b]
  arccosInput = 1.0 if arccosInput > 1.0 else arccosInput
  arccosInput = -1.0 if arccosInput < -1.0 else arccosInput
  return math.acos[arccosInput]

Note, this function will throw an exception if one of the vectors has zero magnitude [divide by 0].

answered Mar 12, 2013 at 23:16

PacePace

39.4k12 gold badges112 silver badges147 bronze badges

0

The traditional approach to obtaining an angle between two vectors [i.e. arccos[dot[u, v] / [norm[u] * norm[v]]], as presented in the other answers] suffers from numerical instability in several corner cases. The following code works for n-dimensions and in all corner cases [it doesn't check for zero length vectors, but that's easy to add, as shown in some of the other answers]. See notes below.

from numpy import arctan, pi, signbit
from numpy.linalg import norm


def angle_btw[v1, v2]:
    u1 = v1 / norm[v1]
    u2 = v2 / norm[v2]

    y = u1 - u2
    x = u1 + u2

    a0 = 2 * arctan[norm[y] / norm[x]]

    if [not signbit[a0]] or signbit[pi - a0]:
        return a0
    elif signbit[a0]:
        return 0.0
    else:
        return pi

This code is adapted from a Julia implementation by Jeffrey Sarnoff [MIT license], in turn based on these notes by Prof. W. Kahan [page 15].

answered Jan 20 at 16:06

fakenfaken

6,3224 gold badges24 silver badges27 bronze badges

3

How do you find the angle between two vectors given two vectors?

The angle between two vectors a and b is found using the formula θ = cos-1 [ [a · b] / [|a| |b|] ]. If the two vectors are equal, then substitute b = a in this formula, then we get θ = cos-1 [ [a · a] / [|a| |a|] ] = cos-1 [|a|2/|a|2] = cos-11 = 0°.

How do you find the angle in Python?

angle[] function is used when we want to compute the angle of the complex argument. A complex number is represented by “ x + yi ” where x and y are real number and i= [-1]^1/2 . The angle is calculated by the formula tan-1[x/y].

Chủ Đề