Angles – angles and angular positions in Python

Python classes and functions for representing angles

The Python module angles provides classes and functions for representing and manipulating angles.

Overview

The angles module provides a host of functions, and three classes for representing angles. It also provides a class for representing points on a sphere. A utility class for representing Cartesian vectors is also defined in this module.

All classes can create string representations of themselves. The format can be customized using attributes of the objects.

The class for representing points on a sphere can calculate bearing / position angle of another point. It can also calculate the great circle separation between two points.

Almost all the methods of the various classes call functions defined in the module. Functions in the module include those for converting between different units, normalizing angles into different ranges, parsing sexagesimal strings, creating sexagesimal strings and others. The sep() and bear() functions return the great circle distance and position angle between two points on a sphere, respectively.

Docstring of functions and classes have detailed documentation and examples. Some of these examples are also listed in the examples section below.

Installation

The module can be installed using easy_install or pip.

$ pip install angles

or,

$ easy_install angles

The module can be downloaded from the pypi page for the module.

The source code repository is at http://github.com/phn/angles.

The module is available under the BSD license (http://www.opensource.org/licenses/bsd-license.php).

Functions

Convert angles between various units

Radians to other units:

  • r2d
  • r2h
  • r2arcs

Degrees to other units:

  • d2h
  • d2r
  • d2arcs

Hours to other units:

  • h2d
  • h2r
  • h2arcs

Arc-seconds to other units:

  • arcs2d
  • arcs2h
  • arcs2r

Normalize angles into a given range

  • r2r
  • d2d
  • h2h
  • normalize

Parse sexagesimal string

  • phmsdms
  • pposition

Classes

  • Angle
  • AlphaAngle
  • DeltaAngle
  • AngularPosition
  • CartesianVector

Examples

The following are some examples of using the facilities of the module. See docstrings of functions and classes for detailed documentation and examples.

Normalizing angles

Two types of normalizations are possible. The first method is used for normalizing longitudinal angles and the second method is used for normalizing latitudinal angles. In the former, an angle of 361 degrees become 1 degree, and -1 degrees become 359 degrees. In the latter, an angle of 91 becomes 89, and -91 becomes -89 degrees. The first method is used if b=False in normalize(). The second method is used if b=True.

>>> normalize(-270,-180,180)
90.0
>>> import math
>>> math.degrees(normalize(-2*math.pi,-math.pi,math.pi))
0.0
>>> normalize(-180, -180, 180)
-180.0
>>> normalize(180, -180, 180)
-180.0
>>> normalize(180, -180, 180, b=True)
180.0
>>> normalize(181,-180,180)
-179.0
>>> normalize(181, -180, 180, b=True)
179.0
>>> normalize(-180,0,360)
180.0
>>> normalize(36,0,24)
12.0
>>> normalize(368.5,-180,180)
8.5
>>> normalize(-100, -90, 90)
80.0
>>> normalize(-100, -90, 90, b=True)
-80.0
>>> normalize(100, -90, 90, b=True)
80.0
>>> normalize(181, -90, 90, b=True)
-1.0
>>> normalize(270, -90, 90, b=True)
-90.0
>>> normalize(271, -90, 90, b=True)
-89.0

Also see d2d, r2r and h2h.

Decimal and sexagesimal

>>> deci2sexa(-11.2345678)
(-1, 11, 14, 4.444)
>>> deci2sexa(-11.2345678, pre=5)
(-1, 11, 14, 4.44408)
>>> deci2sexa(-11.2345678, pre=4)
(-1, 11, 14, 4.4441)
>>> deci2sexa(-11.2345678, pre=4, trunc=True)
(-1, 11, 14, 4.444)

>>> deci2sexa(-11.2345678, pre=1)
(-1, 11, 14, 4.4)
>>> deci2sexa(-11.2345678, pre=0)
(-1, 11, 14, 4.0)
>>> deci2sexa(-11.2345678, pre=-1)
(-1, 11, 14, 0.0)

In the following code fragment x is 24 or 0 hours, to within 3 decimal places.

>>> x = 23+59/60.0+59.99999/3600.0
>>> deci2sexa(x, pre=3, lower=0, upper=24, upper_trim=True)
(1, 0, 0, 0.0)
>>> deci2sexa(x, pre=3, lower=0, upper=24, upper_trim=False)
(1, 24, 0, 0.0)

To 5 decimal places, we get back the full value of x.

>>> deci2sexa(x, pre=5, lower=0, upper=24, upper_trim=True)
(1, 23, 59, 59.99999)

String representation of angles

>>> fmt_angle(12.348978659, pre=4, trunc=True)
'+12 20 56.3231 '
>>> fmt_angle(12.348978659, pre=5)
'+12 20 56.32317 '
>>> fmt_angle(12.348978659, s1='HH ', s2='MM ', s3='SS', pre=5)
'+12HH 20MM 56.32317SS'

>>> x = 23+59/60.0+59.99999/3600.0
>>> fmt_angle(x)
'+24 00 00.000 '
>>> fmt_angle(x, lower=0, upper=24, upper_trim=True)
'+00 00 00.000 '
>>> fmt_angle(x, pre=5)
'+23 59 59.99999 '
>>> fmt_angle(-x, lower=0, upper=24, upper_trim=True)
'+00 00 00.000 '
>>> fmt_angle(-x)
'-24 00 00.000 '

Parsing sexagesimal strings

>>> phmsdms("12")

{'parts': [12.0, None, None],
 'sign': 1,
 'units': 'degrees',
 'vals': [12.0, 0.0, 0.0]}
>>> phmsdms("12h")

{'parts': [12.0, None, None],
 'sign': 1,
 'units': 'hours',
 'vals': [12.0, 0.0, 0.0]}
>>> phmsdms("12d13m14.56")

{'parts': [12.0, 13.0, 14.56],
 'sign': 1,
 'units': 'degrees',
 'vals': [12.0, 13.0, 14.56]}
>>> phmsdms("12d13m14.56")

{'parts': [12.0, 13.0, 14.56],
 'sign': 1,
 'units': 'degrees',
 'vals': [12.0, 13.0, 14.56]}
>>> phmsdms("12d14.56ss")

{'parts': [12.0, None, 14.56],
 'sign': 1,
 'units': 'degrees',
 'vals': [12.0, 0.0, 14.56]}
>>> phmsdms("14.56ss")

{'parts': [None, None, 14.56],
 'sign': 1,
 'units': 'degrees',
 'vals': [0.0, 0.0, 14.56]}

>>> phmsdms("12h13m12.4s")

{'parts': [12.0, 13.0, 12.4],
 'sign': 1,
 'units': 'hours',
 'vals': [12.0, 13.0, 12.4]}

>>> phmsdms("12:13:12.4s")

{'parts': [12.0, 13.0, 12.4],
 'sign': 1,
 'units': 'degrees',
 'vals': [12.0, 13.0, 12.4]}

But phmsdms("12:13mm:12.4s") will not work.

Use pposition to parse coordinates of a point given as a string:

>>> ra, de = pposition("12 22 54.899 +15 49 20.57")
>>> ra
12.381916388888889
>>> de
15.822380555555556
>>> pposition("12 22")
(12.0, 22.0)

Separation and bearing of points on unit sphere

Separation i.e., great circle distance can be calculated using sep().

>>> r2d(sep(0, 0, 0, d2r(90.0)))
90.0
>>> r2d(sep(0, d2r(45.0), 0, d2r(90.0)))
45.00000000000001
>>> r2d(sep(0, d2r(-45.0), 0, d2r(90.0)))
135.0

>>> r2d(sep(0, d2r(-90.0), 0, d2r(90.0)))
180.0
>>> r2d(sep(d2r(45.0), d2r(-90.0), d2r(45.0), d2r(90.0)))
180.0
>>> r2d(sep(0, 0, d2r(90.0), 0))
90.0

>>> r2d(sep(0, d2r(45.0), d2r(90.0), d2r(45.0)))
60.00000000000001
>>> import math
>>> 90.0 * math.cos(d2r(45.0))  # Distance along latitude circle.
63.63961030678928

Bearing or position angle can be calculated using bear().

>>> angles.bear(0, 0, 0, -angles.d2r(90.0))
3.141592653589793
>>> angles.bear(0, -angles.d2r(90.0), 0, 0)
0.0
>>> angles.bear(0, -angles.d2r(45.0), 0, 0)
0.0
>>> angles.bear(0, -angles.d2r(89.678), 0, 0)
0.0

>>> r2d(bear(angles.d2r(45.0), angles.d2r(45.0),
    angles.d2r(60.0), angles.d2r(45.0)))
84.68152816060062
>>> r2d(bear(angles.d2r(45.0), angles.d2r(45.0),
    angles.d2r(46.0), angles.d2r(45.0)))
89.64644212193384

>>> r2d(bear(angles.d2r(45.0), angles.d2r(45.0),
    angles.d2r(44.0), angles.d2r(45.0)))
-89.64644212193421

Both of these functions are also available as methods of AngularPosition objects.

Angle

>>> a = Angle(sg="12h34m16.592849219")
>>> print a.r, a.d, a.h, a.arcs
3.29115230606 188.569136872 12.5712757914 678848.892738
>>> print a.ounit
hours
>>> print a
+12 34 16.593
>>> print a.pre, a.trunc
3 False
>>> a.pre = 4
>>> print a
+12 34 16.5928
>>> a.pre = 3
>>> a.trunc = True
>>> print a
+12 34 16.592

>>> a.ounit = "degrees"
>>> print a
+188 34 08.8927
>>> a.ounit = "radians"
>>> print a
3.29115230606

>>> a.ounit = "degrees"
>>> a.s1 = "DD "
>>> a.s2 = "MM "
>>> a.s3 = "SS"
>>> print a
+188DD 34MM 08.892SS

Unicode characters can be used. But this will cause problems when converting to string in Python 2.x, i.e., print a will raise UnicodeEncodeError.

>>> a.s1 = u"\u00B0 "
>>> print unicode(a)
+12° 34MM 16.593SS

The default unit is inferred from the input values.

>>> a = Angle("35d24m34.5")
>>> print a
+35 24 34.500
>>> print a
+35 24 34.500
>>> a = Angle("35:24:34.5")
>>> print a
+35 24 34.500
>>> a = Angle("35h24m34.5")
>>> print a
+35 24 34.500
>>> a.ounit
'hours'

Angle objects can be added to and subtracted from each other.

>>> a = Angle(h=12.5)
>>> b = Angle(h=13.0)
>>> c = a - b
>>> c.h
-0.5000000000000011
>>> c = a + b
>>> c.h
25.5

AlphaAngle

>>> a = AlphaAngle(d=180.5)
>>> print a
+12HH 02MM 00.000SS
>>> a = AlphaAngle(h=12.0)
>>> print a
+12HH 00MM 00.000SS
>>> a = AlphaAngle(h=-12.0)

The attribute ounit is read-only.

>>> a.ounit
"hours"
>>> print a
+12HH 00MM 00.000SS

If no keyword is provided then the input is taken to a sexagesimal string and the units will be determined from it. The numerical value of the angle in radians, hours, degrees and arc-seconds can be extracted from appropriate attributes.

>>> a = angles.AlphaAngle("12h14m23.4s")
>>> print a
+12HH 14MM 23.400SS
>>> print a.r, a.d, a.h, a.arcs
3.20438087343 183.5975 12.2398333333 660951.0

The hms attribute contains the sexagesimal represenation. These are also accessible as a.sign, a.hh`, a.mm and a.ss. The pre and trunc attributes are taken into account while generating the hms attribute.

>>> a.hms
(1, 12, 0, 0.0)
>>> a = AlphaAngle(h=12.54678345)
>>> a.hms
(1, 12, 32, 48.42)
>>> a.sign, a.hh, a.mm, a.ss
(1, 12, 32, 48.42)
>>> print a
+12HH 32MM 48.420SS
>>> a.pre = 5
>>> a.hms
(1, 12, 32, 48.42042)
>>> print a
+12HH 32MM 48.42042SS

Separators can be changed.

>>> a.s1 = " : "
>>> a.s2 = " : "
>>> a.s3 = ""
>>> print a
+12 : 32 : 48.420

Angles are properly normalized.

>>> a = AlphaAngle(h=25.0)
>>> print a
+01HH 00MM 00.000SS
>>> a = AlphaAngle(h=-1.0)
>>> print a
+23HH 00MM 00.000SS

The sexagesimal parts are properly converted into their respective ranges.

>>> a.hh = 23
>>> a.mm = 59
>>> a.ss = 59.99999
>>> a.hms
(1, 0, 0, 0.0)
>>> print a
+00HH 00MM 00.000SS
>>> a.pre = 5
>>> a.hms
(1, 23, 59, 59.99999)
>>> print a
+23HH 59MM 59.99999SS

Angles can be added to and subtracted from each other.

>>> a = AlphaAngle(h=12.0)
>>> b = AlphaAngle(h=13.0)
>>> c = a - b
>>> c.h
-1.0000000000000007
>>> c = a + b
>>> c.h
25.0

DeltaAngle

>>> a = DeltaAngle(d=-45.0)
>>> print a
-45DD 00MM 00.000SS
>>> a = DeltaAngle(d=180.0)
>>> print a
+00DD 00MM 00.000SS
>>> a = DeltaAngle(h=12.0)
>>> print a
+00DD 00MM 00.000SS
>>> a = DeltaAngle(sg="91d")
>>> print a
+89DD 00MM 00.000SS

Attribute ounit is always "degrees".

>>> a.ounit
'degrees'

If no keyword is provided then the input is taken to a sexagesimal string and the units will be determined from it. The numerical value of the angle in radians, hours, degrees and arc-seconds can be extracted from appropriate attributes.

>>> a = DeltaAngle("12d23m14.2s")
>>> print a
+12DD 23MM 14.200SS
>>> print a.r, a.d, a.h, a.arcs
0.216198782581 12.3872777778 0.825818518519 44594.2

The dms attribute contains the sexagesimal represenation. These are also accessible as a.sign, a.dd`, a.mm and a.ss. The pre and trunc attributes are taken into account.

>>> a = DeltaAngle(d=12.1987546)
>>> a.dms
(1, 12, 11, 55.517)
>>> a.pre = 5
>>> a.dms
(1, 12, 11, 55.51656)
>>> a.dd, a.mm, a.ss
(12, 11, 55.51656)
>>> a.pre = 0
>>> a.dms
(1, 12, 11, 56.0)

The separators can be changed.

>>> a = DeltaAngle(d=12.3459876)
>>> a.s1 = " : "
>>> a.s2 = " : "
>>> a.s3 = ""
>>> print a
+12 : 20 : 45.555

Angles are properly normalized.

>>> a = DeltaAngle(d=-91.0)
>>> print a
-89DD 00MM 00.000SS
>>> a = DeltaAngle(d=91.0)
>>> print a
+89DD 00MM 00.000SS

The sexagesimal parts are properly normalized into their respective ranges.

>>> a.dd = 89
>>> a.mm = 59
>>> a.ss = 59.9999
>>> print a
+90DD 00MM 00.000SS
>>> a.pre = 5
>>> print a
+89DD 59MM 59.99990SS
>>> a.dd = 89
>>> a.mm = 60
>>> a.ss = 60
>>> print a
+89DD 59MM 00.000SS

Angles can be added to and subtracted from each other.

>>> a = DeltaAngle(d=12.0)
>>> b = DeltaAngle(d=13.0)
>>> c = a - b
>>> c.d
-0.9999999999999998
>>> c = a + b
>>> c.d
25.000000000000004
>>> print c
+25DD 00MM 00.000SS
>>> c = a - b
>>> print c
-01DD 00MM 00.000SS

AngularPosition

This class represent a point on a sphere.

>>> a = angles.AngularPosition(hd="12 22 54.899 +15 49 20.57")
>>> print a
+12HH 22MM 54.899SS +15DD 49MM 20.570SS
>>> a = angles.AngularPosition(hd="12dd 22 54.899 +15 49 20.57")
>>> print a
+00HH 49MM 31.660SS +15DD 49MM 20.570SS
>>> a = angles.AngularPosition(hd="12d 22 54.899 +15 49 20.57")
>>> print a
+00HH 49MM 31.660SS +15DD 49MM 20.570SS

Note that in the above examples, the "alpha" angle is assumed to be in hours if unit cannot be inferred from the string.

>>> pos1 = AngularPosition(alpha=12.0, delta=90.0)
>>> pos2 = AngularPosition(alpha=12.0, delta=0.0)
>>> angles.r2d(pos2.bear(pos1))
0.0
>>> angles.r2d(pos1.bear(pos2))
0.0
>>> angles.r2d(pos1.sep(pos2))
90.0
>>> pos1.alpha.h = 0.0
>>> pos2.alpha.h = 0.0
>>> angles.r2d(pos1.sep(pos2))
90.0
>>> angles.r2d(pos2.bear(pos1))
0.0
>>> angles.r2d(pos1.bear(pos2))
0.0

>>> pos2.delta.d = -90
>>> angles.r2d(pos1.bear(pos2))
0.0
>>> angles.r2d(pos1.sep(pos2))
180.0

>>> print pos1
+00HH 00MM 00.000SS +90DD 00MM 00.000SS
>>> print pos2
+00HH 00MM 00.000SS +00DD 00MM 00.000SS
>>> pos1.dlim = " | "
>>> print pos1
+00HH 00MM 00.000SS | +90DD 00MM 00.000SS
This entry was posted in Astronomy, Python and tagged , , , , . Bookmark the permalink.

One Response to Angles – angles and angular positions in Python

  1. anonymous says:

    A quick similar package is the astropysics.coords module (http://packages.python.org/Astropysics/coremods/coords.html), which includes very similar classes that are also integrated with coordinate conversions from/to various astronomical coordinate systems.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s