Units and Quantities (astropy.units
)#
Introduction#
astropy.units
handles defining, converting between, and performing
arithmetic with physical quantities, such as meters, seconds, Hz,
etc. It also handles logarithmic units such as magnitude and decibel.
astropy.units
does not know spherical geometry or sexagesimal
(hours, min, sec): if you want to deal with celestial coordinates,
see the astropy.coordinates
package.
Getting Started#
Most users of the astropy.units
package will work with Quantity objects: the combination of a value and a unit. The most convenient way to
create a Quantity
is to multiply or divide a value by one of the built-in
units. It works with scalars, sequences, and numpy
arrays.
Examples#
To create a Quantity
object:
>>> from astropy import units as u
>>> 42.0 * u.meter
<Quantity 42. m>
>>> [1., 2., 3.] * u.m
<Quantity [1., 2., 3.] m>
>>> import numpy as np
>>> np.array([1., 2., 3.]) * u.m
<Quantity [1., 2., 3.] m>
You can get the unit and value from a Quantity
using the unit and
value members:
>>> q = 42.0 * u.meter
>>> q.value
42.0
>>> q.unit
Unit("m")
From this basic building block, it is possible to start combining quantities with different units:
>>> 15.1 * u.meter / (32.0 * u.second)
<Quantity 0.471875 m / s>
>>> 3.0 * u.kilometer / (130.51 * u.meter / u.second)
<Quantity 0.022986744310780783 km s / m>
>>> (3.0 * u.kilometer / (130.51 * u.meter / u.second)).decompose()
<Quantity 22.986744310780782 s>
Unit conversion is done using the
to()
method, which returns a new
Quantity
in the given unit:
>>> x = 1.0 * u.parsec
>>> x.to(u.km)
<Quantity 30856775814671.914 km>
It is also possible to work directly with units at a lower level, for example, to create custom units:
>>> from astropy.units import imperial
>>> cms = u.cm / u.s
>>> # ...and then use some imperial units
>>> mph = imperial.mile / u.hour
>>> # And do some conversions
>>> q = 42.0 * cms
>>> q.to(mph)
<Quantity 0.939513242662849 mi / h>
Units that “cancel out” become a special unit called the “dimensionless unit”:
>>> u.m / u.m
Unit(dimensionless)
To create a basic dimensionless quantity, multiply a value by the unscaled dimensionless unit:
>>> q = 1.0 * u.dimensionless_unscaled
>>> q.unit
Unit(dimensionless)
astropy.units
is able to match compound units against the units it already
knows about:
>>> (u.s ** -1).compose()
[Unit("Bq"), Unit("Hz"), Unit("2.7027e-11 Ci")]
And it can convert between unit systems, such as SI or CGS:
>>> (1.0 * u.Pa).cgs
<Quantity 10. P / s>
The units mag
, dex
, and dB
are special, being logarithmic
units, for which a value is the logarithm of a physical
quantity in a given unit. These can be used with a physical unit in
parentheses to create a corresponding logarithmic quantity:
>>> -2.5 * u.mag(u.ct / u.s)
<Magnitude -2.5 mag(ct / s)>
>>> from astropy import constants as c
>>> u.Dex((c.G * u.M_sun / u.R_sun**2).cgs)
<Dex 4.438067627303133 dex(cm / s2)>
astropy.units
also handles equivalencies, such as
that between wavelength and frequency. To use that feature, equivalence objects
are passed to the to()
conversion
method. For instance, a conversion from wavelength to frequency does not
normally work:
>>> (1000 * u.nm).to(u.Hz)
Traceback (most recent call last):
...
UnitConversionError: 'nm' (length) and 'Hz' (frequency) are not convertible
But by passing an equivalency list, in this case
spectral()
, it does:
>>> (1000 * u.nm).to(u.Hz, equivalencies=u.spectral())
<Quantity 2.99792458e+14 Hz>
Quantities and units can be printed nicely to strings using the Format String Syntax. Format
specifiers (like 0.03f
) in strings will be used to format the quantity
value:
>>> q = 15.1 * u.meter / (32.0 * u.second)
>>> q
<Quantity 0.471875 m / s>
>>> f"{q:0.03f}"
'0.472 m / s'
The value and unit can also be formatted separately. Format specifiers for units can be used to choose the unit formatter:
>>> q = 15.1 * u.meter / (32.0 * u.second)
>>> q
<Quantity 0.471875 m / s>
>>> f"{q.value:0.03f} {q.unit:FITS}"
'0.472 m s-1'
Using astropy.units
#
- Quantity
- Creating Quantity Instances
- Converting to Different Units
- Comparing Quantities
- Plotting Quantities
- Arithmetic
- NumPy Functions
- Dimensionless Quantities
- Converting to Plain Python Scalars
- Functions that Accept Quantities
- Representing Vectors with Units
- Creating and Converting Quantities without Copies
- The
numpy.dtype
of a Quantity - QTable
- Subclassing Quantity
- Unit-Aware Type Annotations
- Standard Units
- Combining and Defining Units
- Decomposing and Composing Units
- Magnitudes and Other Logarithmic Units
- Structured Units
- String Representations of Units and Quantities
- Equivalencies
- Physical Types
- Using Prior Versions of Constants
- Low-Level Unit Conversion
Acknowledgments#
This code was originally based on the pynbody units module written by Andrew Pontzen, who has granted the Astropy Project permission to use the code under a BSD license.
See Also#
FITS Standard for units in FITS.
The Units in the VO 1.0 Standard for representing units in the VO.
OGIP Units: A standard for storing units in OGIP FITS files.
Performance Tips#
If you are attaching units to arrays to make Quantity
objects, multiplying
arrays by units will result in the array being copied in memory, which will slow
things down. Furthermore, if you are multiplying an array by a composite unit,
the array will be copied for each individual multiplication. Thus, in the
following case, the array is copied four successive times:
In [1]: import numpy as np
In [2]: from astropy import units as u
In [3]: rng = np.random.default_rng()
In [4]: array = rng.random(10000000)
In [5]: %timeit array * u.m / u.s / u.kg / u.sr
92.5 ms ± 2.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
There are several ways to speed this up. First, when you are using composite units, ensure that the entire unit gets evaluated first, then attached to the array. You can do this by using parentheses as for any other operation:
In [6]: %timeit array * (u.m / u.s / u.kg / u.sr)
21.5 ms ± 886 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In this case, this has sped things up by a factor of 4. If you use a composite unit several times in your code then you can define a variable for it:
In [7]: UNIT_MSKGSR = u.m / u.s / u.kg / u.sr
In [8]: %timeit array * UNIT_MSKGSR
22.2 ms ± 551 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In this case and the case with brackets, the array is still copied once when
creating the Quantity
. If you want to avoid any copies altogether, you can
make use of the <<
operator to attach the unit to the array:
In [9]: %timeit array << u.m / u.s / u.kg / u.sr
47.1 µs ± 5.77 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Note that these are now microseconds, so this is 2000x faster than the
original case with no brackets. Note that brackets are not needed when using
<<
since *
and /
have a higher precedence, so the unit will be
evaluated first. When using <<
, be aware that because the data is not being
copied, changing the original array will also change the Quantity
object.
Note that for composite units, you will definitely see an impact if you can pre-compute the composite unit:
In [10]: %timeit array << UNIT_MSKGSR
6.51 µs ± 112 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Which is over 10000x faster than the original example. See
Creating and Converting Quantities without Copies for more details about the <<
operator.
Reference/API#
- Reference/API
- astropy.units.quantity Module
- astropy.units Package
- astropy.units.format Package
- astropy.units.si Module
- astropy.units.cgs Module
- astropy.units.astrophys Module
- astropy.units.misc Module
- astropy.units.function.units Module
- astropy.units.photometric Module
- astropy.units.imperial Module
- astropy.units.cds Module
- astropy.units.physical Module
- astropy.units.equivalencies Module
- astropy.units.function.core Module
- astropy.units.function.logarithmic Module
- astropy.units.deprecated Module
- astropy.units.required_by_vounit Module