astro py:docs

- Index
- Modules

### Navigation

- next »
- « previous |
- Astropy v1.1.1 »
- Units and Quantities (`astropy.units`) »
- Quantity

# Quantity

The `Quantity` object is meant to represent a value that has some unit associated with the number.

## Creating Quantity instances

`Quantity` objects are created through multiplication or division with `Unit` objects. For example, to create a `Quantity` to represent 15 m/s:

    >>> import astropy.units as u
    >>> 15 * u.m / u.s
    <Quantity 15.0 m / s>

Note

`Quantity` objects are converted to float by default.

As another example:

    >>> 1.25 / u.s
    <Quantity 1.25 1 / s>

You can also create instances using the `Quantity` constructor directly, by specifying a value and unit:

    >>> u.Quantity(15, u.m / u.s)
    <Quantity 15.0 m / s>

`Quantity` objects can also be created automatically from Numpy arrays or Python sequences:

    >>> [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>

`Quantity` objects can also be created from sequences of `Quantity` objects, as long as all of their units are equivalent, and will automatically convert to Numpy arrays:

    >>> qlst = [60 * u.s, 1 * u.min]
    >>> u.Quantity(qlst, u.minute)
    <Quantity [ 1.,  1.] min>

Finally, the current unit and value can be accessed via the `unit` and `value` attributes:

    >>> q = 2.5 * u.m / u.s
    >>> q.unit
    Unit("m / s")
    >>> q.value
    2.5

## Converting to different units

`Quantity` objects can be converted to different units using the `to()` method:

    >>> q = 2.3 * u.m / u.s
    >>> q.to(u.km / u.h)
    <Quantity 8.28 km / h>

For convenience, the `si` and `cgs` attributes can be used to convert the `Quantity` to base S.I. or c.g.s units:

    >>> q = 2.4 * u.m / u.s
    >>> q.si
    <Quantity 2.4 m / s>
    >>> q.cgs
    <Quantity 240.0 cm / s>

## Plotting quantities

`Quantity` objects can be conveniently plotted using matplotlib. This feature needs to be explicitly turned on:

    >>> from astropy.visualization import quantity_support
    >>> quantity_support()
    <astropy.visualization.units.MplQuantityConverter ...>

Then `Quantity` objects can be passed to matplotlib plotting functions. The axis labels are automatically labeled with the unit of the quantity:

    >>> from matplotlib import pyplot as plt
    >>> plt.figure()
    <...>
    >>> plt.plot([1, 2, 3] * u.m)
    [...]

Quantities are automatically converted to the first unit set on a particular axis, so in the following, the y-axis remains in `m` even though the second line is given in `cm`:

    .. doctest-requires:: matplotlib

    >>> plt.plot([1, 2, 3] * u.cm)
    [...]

Plotting a quantity with an incompatible unit will raise an exception:

    .. doctest-requires:: matplotlib

    >>> plt.plot([1, 2, 3] * u.kg)
    Traceback (most recent call last):
    ...
    UnitConversionError: 'kg' (mass) and 'm' (length) are not convertible
    >>> plt.clf()

To make sure unit support is turned off afterward, you can use `quantity_support` with a `with` statement:

    .. doctest-requires:: matplotlib

    >>> from astropy.visualization import quantity_support
    >>> from matplotlib import pyplot as plt
    >>> with quantity_support():
    ...     plt.figure()
    ...     plt.plot([1, 2, 3] * u.m)
    <...>
    [...]

## Arithmetic

### Addition and Subtraction

Addition or subtraction between `Quantity` objects is supported when their units are equivalent. When the units are equal, the resulting object has the same unit:

    >>> 11 * u.s + 30 * u.s
    <Quantity 41.0 s>
    >>> 30 * u.s - 11 * u.s
    <Quantity 19.0 s>

If the units are equivalent, but not equal (e.g. kilometer and meter), the resulting object has units of the object on the left:

    >>> 1100.1 * u.m + 13.5 * u.km
    <Quantity 14600.1 m>
    >>> 13.5 * u.km + 1100.1 * u.m
    <Quantity 14.6001 km>
    >>> 1100.1 * u.m - 13.5 * u.km
    <Quantity -12399.9 m>
    >>> 13.5 * u.km - 1100.1 * u.m
    <Quantity 12.3999 km>

Addition and subtraction is not supported between `Quantity` objects and basic numeric types:

    >>> 13.5 * u.km + 19.412
    Traceback (most recent call last):
      ...
    UnitsError: Can only apply 'add' function to dimensionless
    quantities when other argument is not a quantity (unless the
    latter is all zero/infinity/nan)

except for dimensionless quantities (see Dimensionless quantities).

### Multiplication and Division

Multiplication and division is supported between `Quantity` objects with any units, and with numeric types. For these operations between objects with equivalent units, the resulting object has composite units:

    >>> 1.1 * u.m * 140.3 * u.cm
    <Quantity 154.33 cm m>
    >>> 140.3 * u.cm * 1.1 * u.m
    <Quantity 154.33 cm m>
    >>> 1. * u.m / (20. * u.cm)
    <Quantity 0.05 m / cm>
    >>> 20. * u.cm / (1. * u.m)
    <Quantity 20.0 cm / m>

For multiplication, you can change how to represent the resulting object by using the `to()` method:

    >>> (1.1 * u.m * 140.3 * u.cm).to(u.m**2)
    <Quantity 1.5433000000000001 m2>
    >>> (1.1 * u.m * 140.3 * u.cm).to(u.cm**2)
    <Quantity 15433.000000000002 cm2>

For division, if the units are equivalent, you may want to make the resulting object dimensionless by reducing the units. To do this, use the `decompose()` method:

    >>> (20. * u.cm / (1. * u.m)).decompose()
    <Quantity 0.2>

This method is also useful for more complicated arithmetic:

    >>> 15. * u.kg * 32. * u.cm * 15 * u.m / (11. * u.s * 1914.15 * u.ms)
    <Quantity 0.3419509727792778 cm kg m / (ms s)>
    >>> (15. * u.kg * 32. * u.cm * 15 * u.m / (11. * u.s * 1914.15 * u.ms)).decompose()
    <Quantity 3.4195097277927777 kg m2 / s2>

## Numpy functions

`Quantity` objects are actually full Numpy arrays (the `Quantity` object class inherits from and extends the `numpy.ndarray` class), and we have tried to ensure that most Numpy functions behave properly with quantities:

    >>> q = np.array([1., 2., 3., 4.]) * u.m / u.s
    >>> np.mean(q)
    <Quantity 2.5 m / s>
    >>> np.std(q)
    <Quantity 1.118033988749895 m / s>

including functions that only accept specific units such as angles:

    >>> q = 30. * u.deg
    >>> np.sin(q)
    <Quantity 0.49999999999999994>

or dimensionless quantities:

    >>> from astropy.constants import h, k_B
    >>> nu = 3 * u.GHz
    >>> T = 30 * u.K
    >>> np.exp(-h * nu / (k_B * T))
    <Quantity 0.995212254618668>

(see Dimensionless quantities for more details).

## Dimensionless quantities

Dimensionless quantities have the characteristic that if they are added or subtracted from a Python scalar or unitless `ndarray`, or if they are passed to a Numpy function that takes dimensionless quantities, the units are simplified so that the quantity is dimensionless and scale-free. For example:

    >>> 1. + 1. * u.m / u.km
    <Quantity 1.001>

which is different from:

    >>> 1. + (1. * u.m / u.km).value
    2.0

In the latter case, the result is `2.0` because the unit of `(1. * u.m / u.km)` is not scale-free by default:

    >>> q = (1. * u.m / u.km)
    >>> q.unit
    Unit("m / km")
    >>> q.unit.decompose()
    Unit(dimensionless with a scale of 0.001)

However, when combining with a non-quantity object, the unit is automatically decomposed to be scale-free, giving the expected result.

This also occurs when passing dimensionless quantities to functions that take dimensionless quantities:

    >>> nu = 3 * u.GHz
    >>> T = 30 * u.K
    >>> np.exp(- h * nu / (k_B * T))
    <Quantity 0.995212254618668>

The result is independent from the units the different quantities were specified in:

    >>> nu = 3.e9 * u.Hz
    >>> T = 30 * u.K
    >>> np.exp(- h * nu / (k_B * T))
    <Quantity 0.995212254618668>

## Converting to plain Python scalars

Converting `Quantity` objects does not work for non-dimensionless quantities:

    >>> float(3. * u.m)
    Traceback (most recent call last):
      ...
    TypeError: Only dimensionless scalar quantities can be converted
    to Python scalars

Instead, only dimensionless values can be converted to plain Python scalars:

    >>> float(3. * u.m / (4. * u.m))
    0.75
    >>> float(3. * u.km / (4. * u.m))
    750.0
    >>> int(6. * u.km / (2. * u.m))
    3000

## Functions Accepting Quantities

Validation of quantity arguments to functions can lead to many repetitions of the same checking code. A decorator is provided which verifies that certain arguments to a function are `Quantity` objects and that the units are compatible with a desired unit.

The decorator does not convert the unit to the desired unit, say arcseconds to degrees, it merely checks that such a conversion is possible, thus verifying that the `Quantity` argument can be used in calculations.

The decorator `quantity_input` accepts keyword arguments to specify which arguments should be validated and what unit they are expected to be compatible with:

    >>> @u.quantity_input(myarg=u.deg)
    ... def myfunction(myarg):
    ...     return myarg.unit

    >>> myfunction(100*u.arcsec)
    Unit("arcsec")

Under Python 3 you can use the annotations syntax to provide the units:

    >>> @u.quantity_input
    ... def myfunction(myarg: u.arcsec):
    ...     return myarg.unit

    >>> myfunction(100*u.arcsec)
    Unit("arcsec")

## Known issues with conversion to numpy arrays

Since `Quantity` objects are Numpy arrays, we are not able to ensure that only dimensionless quantities are converted to Numpy arrays:

    >>> np.array([1, 2, 3] * u.m)
    array([ 1., 2., 3.])

Similarly, while most numpy functions work properly, a few have known issues, either ignoring the unit (e.g., `np.dot`) or not reinitializing it properly (e.g., `np.hstack`). This propagates to more complex functions such as `np.linalg.norm` and `scipy.integrate.odeint`.

## Subclassing Quantity

To subclass `Quantity`, one generally proceeds as one would when subclassing `ndarray`, i.e., one typically needs to override `__new__` (rather than `__init__`) and uses the `numpy.ndarray.__array_finalize__` method to update attributes. For details, see the numpy documentation on subclassing. For examples, one can look at `Quantity` itself, where, e.g., the `astropy.units.Quantity.__array_finalize__` method is used to pass on the `unit`, at `Angle`, where strings are parsed as angles in the `astropy.coordinates.Angle.__new__` method and at `Longitude`, where the `astropy.coordinates.Longitude.__array_finalize__` method is used to pass on the angle at which longitudes wrap.

Another method that is meant to be overridden by subclasses, one specific to `Quantity`, is `astropy.units.Quantity.__quantity_subclass__`. This is called to decide which type of subclass to return, based on the unit of the quantity that is to be created. It is used, e.g., in `Angle` to return a `Quantity` if a calculation returns a unit other than an angular one.