Syntax :
atan2 (y, x)
Parameter :
(y, x)  Both must be a numeric value.
radians. The double value is
Type Error:
Returns a TypeError if anything other than float is passed.
Code # 1:

Output:
atan2 (0.5, 0.5): 2.356194490192345 atan2 (1.2, 1.5): 0.6747409422235526 atan2 (1.2, 1.5): 2.4668517113662407
Code # 2:

Output:
0.16514867741462683 0.5880026035475675 0.40489178628508343 0.4636476090008061
Code # 3: Program showing error

Output:
Traceback (most recent call last): File "/home/622586ab389561bcdbfff258aca01e65.py", line 9, in theta = math.atan2 ([y], [x]) TypeError: a float is required
Practical Use:
This function is used to determine the slope in radians when given Y and X coordinates.
Code # 4:

Output:
0.7853981633974483
For people (like me) coming here via search engine and just looking for a solution which works out of the box, I recommend installing mpu
. Install it via pip install mpu user
and use it like this to get the haversine distance:
import mpu
# Point one
lat1 = 52.2296756
lon1 = 21.0122287
# Point two
lat2 = 52.406374
lon2 = 16.9251681
# What you were looking for
dist = mpu.haversine_distance((lat1, lon1), (lat2, lon2))
print(dist) # gives 278.45817507541943.
An alternative package is gpxpy
.
If you don"t want dependencies, you can use:
import math
def distance(origin, destination):
"""
Calculate the Haversine distance.
Parameters

origin : tuple of float
(lat, long)
destination : tuple of float
(lat, long)
Returns

distance_in_km : float
Examples

>>> origin = (48.1372, 11.5756) # Munich
>>> destination = (52.5186, 13.4083) # Berlin
>>> round(distance(origin, destination), 1)
504.2
"""
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km
dlat = math.radians(lat2  lat1)
dlon = math.radians(lon2  lon1)
a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
math.sin(dlon / 2) * math.sin(dlon / 2))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1  a))
d = radius * c
return d
if __name__ == "__main__":
import doctest
doctest.testmod()
The other alternative package is haversine
from haversine import haversine, Unit
lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)
haversine(lyon, paris)
>> 392.2172595594006 # in kilometers
haversine(lyon, paris, unit=Unit.MILES)
>> 243.71201856934454 # in miles
# you can also use the string abbreviation for units:
haversine(lyon, paris, unit="mi")
>> 243.71201856934454 # in miles
haversine(lyon, paris, unit=Unit.NAUTICAL_MILES)
>> 211.78037755311516 # in nautical miles
They claim to have performance optimization for distances between all points in two vectors
from haversine import haversine_vector, Unit
lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)
new_york = (40.7033962, 74.2351462)
haversine_vector([lyon, lyon], [paris, new_york], Unit.KILOMETERS)
>> array([ 392.21725956, 6163.43638211])
Update: User cphyc has kindly created a Github repository for the code in this answer (see here), and bundled the code into a package which may be installed using pip install matplotliblabellines
.
Pretty Picture:
In matplotlib
it"s pretty easy to label contour plots (either automatically or by manually placing labels with mouse clicks). There does not (yet) appear to be any equivalent capability to label data series in this fashion! There may be some semantic reason for not including this feature which I am missing.
Regardless, I have written the following module which takes any allows for semiautomatic plot labelling. It requires only numpy
and a couple of functions from the standard math
library.
The default behaviour of the labelLines
function is to space the labels evenly along the x
axis (automatically placing at the correct y
value of course). If you want you can just pass an array of the x coordinates of each of the labels. You can even tweak the location of one label (as shown in the bottom right plot) and space the rest evenly if you like.
In addition, the label_lines
function does not account for the lines which have not had a label assigned in the plot
command (or more accurately if the label contains "_line"
).
Keyword arguments passed to labelLines
or labelLine
are passed on to the text
function call (some keyword arguments are set if the calling code chooses not to specify).
1
and 10
annotations in the top left plot. I"m not even sure this can be avoided.y
position instead sometimes.x
axis values are float
slabelLines
function assumes that all data series span the range specified by the axis limits. Take a look at the blue curve in the top left plot of the pretty picture. If there were only data available for the x
range 0.5
1
then then we couldn"t possibly place a label at the desired location (which is a little less than 0.2
). See this question for a particularly nasty example. Right now, the code does not intelligently identify this scenario and rearrange the labels, however there is a reasonable workaround. The labelLines function takes the xvals
argument; a list of x
values specified by the user instead of the default linear distribution across the width. So the user can decide which x
values to use for the label placement of each data series.Also, I believe this is the first answer to complete the bonus objective of aligning the labels with the curve they"re on. :)
label_lines.py:
from math import atan2,degrees
import numpy as np
#Label line with line2D label data
def labelLine(line,x,label=None,align=True,**kwargs):
ax = line.axes
xdata = line.get_xdata()
ydata = line.get_ydata()
if (x < xdata[0]) or (x > xdata[1]):
print("x label location is outside data range!")
return
#Find corresponding y coordinate and angle of the line
ip = 1
for i in range(len(xdata)):
if x < xdata[i]:
ip = i
break
y = ydata[ip1] + (ydata[ip]ydata[ip1])*(xxdata[ip1])/(xdata[ip]xdata[ip1])
if not label:
label = line.get_label()
if align:
#Compute the slope
dx = xdata[ip]  xdata[ip1]
dy = ydata[ip]  ydata[ip1]
ang = degrees(atan2(dy,dx))
#Transform to screen coordinates
pt = np.array([x,y]).reshape((1,2))
trans_angle = ax.transData.transform_angles(np.array((ang,)),pt)[0]
else:
trans_angle = 0
#Set a bunch of keyword arguments
if "color" not in kwargs:
kwargs["color"] = line.get_color()
if ("horizontalalignment" not in kwargs) and ("ha" not in kwargs):
kwargs["ha"] = "center"
if ("verticalalignment" not in kwargs) and ("va" not in kwargs):
kwargs["va"] = "center"
if "backgroundcolor" not in kwargs:
kwargs["backgroundcolor"] = ax.get_facecolor()
if "clip_on" not in kwargs:
kwargs["clip_on"] = True
if "zorder" not in kwargs:
kwargs["zorder"] = 2.5
ax.text(x,y,label,rotation=trans_angle,**kwargs)
def labelLines(lines,align=True,xvals=None,**kwargs):
ax = lines[0].axes
labLines = []
labels = []
#Take only the lines which have labels other than the default ones
for line in lines:
label = line.get_label()
if "_line" not in label:
labLines.append(line)
labels.append(label)
if xvals is None:
xmin,xmax = ax.get_xlim()
xvals = np.linspace(xmin,xmax,len(labLines)+2)[1:1]
for line,x,label in zip(labLines,xvals,labels):
labelLine(line,x,label,align,**kwargs)
Test code to generate the pretty picture above:
from matplotlib import pyplot as plt
from scipy.stats import loglaplace,chi2
from labellines import *
X = np.linspace(0,1,500)
A = [1,2,5,10,20]
funcs = [np.arctan,np.sin,loglaplace(4).pdf,chi2(5).pdf]
plt.subplot(221)
for a in A:
plt.plot(X,np.arctan(a*X),label=str(a))
labelLines(plt.gca().get_lines(),zorder=2.5)
plt.subplot(222)
for a in A:
plt.plot(X,np.sin(a*X),label=str(a))
labelLines(plt.gca().get_lines(),align=False,fontsize=14)
plt.subplot(223)
for a in A:
plt.plot(X,loglaplace(4).pdf(a*X),label=str(a))
xvals = [0.8,0.55,0.22,0.104,0.045]
labelLines(plt.gca().get_lines(),align=False,xvals=xvals,color="k")
plt.subplot(224)
for a in A:
plt.plot(X,chi2(5).pdf(a*X),label=str(a))
lines = plt.gca().get_lines()
l1=lines[1]
labelLine(l1,0.6,label=r"$Re=${}".format(l1.get_label()),ha="left",va="bottom",align = False)
labelLines(lines[:1],align=False)
plt.show()
First find the difference between the start point and the end point (here, this is more of a directed line segment, not a "line", since lines extend infinitely and don"t start at a particular point).
deltaY = P2_y  P1_y
deltaX = P2_x  P1_x
Then calculate the angle (which runs from the positive X axis at P1
to the positive Y axis at P1
).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
But arctan
may not be ideal, because dividing the differences this way will erase the distinction needed to distinguish which quadrant the angle is in (see below). Use the following instead if your language includes an atan2
function:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (Feb. 22, 2017): In general, however, calling atan2(deltaY,deltaX)
just to get the proper angle for cos
and sin
may be inelegant. In those cases, you can often do the following instead:
(deltaX, deltaY)
as a vector.deltaX
and deltaY
by the vector"s length (sqrt(deltaX*deltaX+deltaY*deltaY)
), unless the length is 0.deltaX
will now be the cosine of the angle between the vector and the horizontal axis (in the direction from the positive X to the positive Y axis at P1
).deltaY
will now be the sine of that angle.EDIT (Feb. 28, 2017): Even without normalizing (deltaX, deltaY)
:
deltaX
will tell you whether the cosine described in step 3 is positive or negative.deltaY
will tell you whether the sine described in step 4 is positive or negative.deltaX
and deltaY
will tell you which quadrant the angle is in, in relation to the positive X axis at P1
:
+deltaX
, +deltaY
: 0 to 90 degrees.deltaX
, +deltaY
: 90 to 180 degrees.deltaX
, deltaY
: 180 to 270 degrees (180 to 90 degrees).+deltaX
, deltaY
: 270 to 360 degrees (90 to 0 degrees).An implementation in Python using radians (provided on July 19, 2015 by Eric Leschinski, who edited my answer):
from math import *
def angle_trunc(a):
while a < 0.0:
a += pi * 2
return a
def getAngleBetweenPoints(x_orig, y_orig, x_landmark, y_landmark):
deltaY = y_landmark  y_orig
deltaX = x_landmark  x_orig
return angle_trunc(atan2(deltaY, deltaX))
angle = getAngleBetweenPoints(5, 2, 1,4)
assert angle >= 0, "angle must be >= 0"
angle = getAngleBetweenPoints(1, 1, 2, 1)
assert angle == 0, "expecting angle to be 0"
angle = getAngleBetweenPoints(2, 1, 1, 1)
assert abs(pi  angle) <= 0.01, "expecting angle to be pi, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 3)
assert abs(angle  pi/2) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 0)
assert abs(angle  (pi+pi/2)) <= 0.01, "expecting angle to be pi+pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(1, 1, 2, 2)
assert abs(angle  (pi/4)) <= 0.01, "expecting angle to be pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(1, 1, 2, 2)
assert abs(angle  (pi+pi/4)) <= 0.01, "expecting angle to be pi+pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(1, 1, 1, 2)
assert abs(angle  (pi/2)) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)
All tests pass. See https://en.wikipedia.org/wiki/Unit_circle
Edit: Just as a note, if you just need a quick and easy way of finding the distance between two points, I strongly recommend using the approach described in Kurt"s answer below instead of reimplementing Haversine  see his post for rationale.
This answer focuses just on answering the specific bug OP ran into.
It"s because in Python, all the trig functions use radians, not degrees.
You can either convert the numbers manually to radians, or use the radians
function from the math module:
from math import sin, cos, sqrt, atan2, radians
# approximate radius of earth in km
R = 6373.0
lat1 = radians(52.2296756)
lon1 = radians(21.0122287)
lat2 = radians(52.406374)
lon2 = radians(16.9251681)
dlon = lon2  lon1
dlat = lat2  lat1
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1  a))
distance = R * c
print("Result:", distance)
print("Should be:", 278.546, "km")
The distance is now returning the correct value of 278.545589351
km.
Pandas 1.x Cookbook: Practical recipes for scientific computing, time series analysis, and exploratory data analysis using Python, 2nd Edition....
05/09/2021
As information protection continues to be a growing concern for businesses today, IT security certifications have become highly desirable, even as the number of certifications has grown. Now you can s...
12/08/2021
Cloud computing provides the capability to use computing and storage resources on a metered basis and reduce the investments in an organization’s computing infrastructure. The spawning and deletion ...
10/07/2020
This book serves as a practical guide on how to utilize big data to store, process, and analyze structured data, focusing on three of the most popular Apache projects in the Hadoop ecosystem: Apache S...
10/07/2020