What’s New in Astropy 6.0?#
Overview#
Astropy 6.0 is a major release that adds significant new functionality since the 5.3 release.
In particular, this release includes:
Define Geodetic and Bodycentric Representations via their geometric parameters
Body-fixed planetary reference frames and their WCS description
Support for Numpy broadcasting over frame data and attributes
In addition to these major changes, Astropy v6.0 includes a large number of smaller improvements and bug fixes, which are described in the Full Changelog. By the numbers:
1044 commits have been added since 5.3
157 issues have been closed since 5.3
313 pull requests have been merged since 5.3
57 people have contributed since 5.3
24 of which are new contributors
Define Geodetic and Bodycentric Representations via their geometric parameters#
The user may now define custom spheroidal models for the Earth or other planetary
bodies by subclassing BaseGeodeticRepresentation
or
BaseBodycentricRepresentation
and defining
_equatorial_radius
and _flattening
attributes:
>>> from astropy.coordinates import (BaseGeodeticRepresentation,
... WGS84GeodeticRepresentation, BaseBodycentricRepresentation)
>>> from astropy import units as u
>>> class IAU1976EarthGeodeticRepresentation(BaseGeodeticRepresentation):
... _equatorial_radius = 6378140 * u.m
... _flattening = 0.3352805 * u.percent
>>> representation = IAU1976EarthGeodeticRepresentation(lon=45.8366*u.deg,
... lat=56.1499*u.deg, height=367*u.m)
>>> representation.to_cartesian()
<CartesianRepresentation (x, y, z) in m
(2481112.60371134, 2554647.09482601, 5274064.55958489)>
>>> representation.represent_as(WGS84GeodeticRepresentation)
<WGS84GeodeticRepresentation (lon, lat, height) in (rad, rad, m)
(0.79999959, 0.98000063, 370.01796023)>
>>> class IAU1976EarthBodycentricRepresentation(BaseBodycentricRepresentation):
... _equatorial_radius = 6378140 * u.m
... _flattening = 0.3352805 * u.percent
>>> representation.represent_as(IAU1976EarthBodycentricRepresentation)
<IAU1976EarthBodycentricRepresentation (lon, lat, height) in (rad, rad, m)
(0.79999959, 0.9768896, 336.12620429)>
See Creating Your Own Geodetic and Bodycentric Representations for more details.
Body-fixed planetary reference frames and their WCS description#
Body-fixed planetary reference frames for Solar System planetary bodies can be read and written via WCS structures in FITS images, following Definitions, Applications, and Best Practices for Planetary FITS.
See Creating a planetary WCS structure for an example.
Planetary images or spectral cube WCS description can be manipulated using the
wcs
module.
Support for Numpy broadcasting over frame data and attributes#
Frames in astropy.coordinates
now support
Numpy broadcasting rules over both
frame data and frame attributes. Previously, broadcasting was only supported
over framed data. This makes it much easier and faster to do positional
astronomy calculations and transformations on sweeps of parameters.
For example, the user can now create frame objects with scalar data but vector frame attributes, such as:
from astropy.coordinates import FK4
from astropy import units as u
FK4(1 * u.deg, 2 * u.deg, obstime=["J2000", "J2001"])
Where this really shines is doing fast observability calculations over arrays.
The following example constructs an EarthLocation
array
of length L
, a SkyCoord
array of length
M
, and a Time
array of length N
. It uses
Numpy broadcasting rules to evaluate a boolean array of shape
(L, M, N)
that is True
for those observing locations, times,
and sky coordinates, for which the target is above an altitude limit:
>>> from astropy.coordinates import EarthLocation, AltAz, SkyCoord
>>> from astropy.coordinates.angles import uniform_spherical_random_surface
>>> from astropy.time import Time
>>> from astropy import units as u
>>> import numpy as np
>>> L = 25
>>> M = 100
>>> N = 50
>>> # Earth locations of length L
>>> c = uniform_spherical_random_surface(L)
>>> locations = EarthLocation.from_geodetic(c.lon, c.lat)
>>> # Celestial coordinates of length M
>>> coords = SkyCoord(uniform_spherical_random_surface(M))
>>> # Observation times of length N
>>> obstimes = Time('2023-08-04') + np.linspace(0, 24, N) * u.hour
>>> # AltAz coordinates of shape (L, M, N)
>>> frame = AltAz(
... location=locations[:, np.newaxis, np.newaxis],
... obstime=obstimes[np.newaxis, np.newaxis, :])
>>> altaz = coords[np.newaxis, :, np.newaxis].transform_to(frame)
>>> min_altitude = 30 * u.deg
>>> is_above_altitude_limit = (altaz.alt > min_altitude)
>>> is_above_altitude_limit.shape
(25, 100, 50)
Updates to cosmology
#
Writing to LaTeX#
The Cosmology
class in cosmology
now
supports the latex format in its write()
method, allowing users to export a cosmology object to a LaTeX table.:
>>> from astropy.cosmology import Planck18
>>> Planck18.write("example_cosmology.tex", format="ascii.latex")
This will write the cosmology object to a file in LaTeX format, with appropriate formatting of units and table alignment.
Renaming fields in I/O#
Most I/O methods in cosmology
(accessed by
read()
,
write()
,
from_format()
,
to_format()
) now support
renaming fields.
For example, to rename the H0
field to Hubble
when converting to a table
format:
>>> from astropy.cosmology import Planck18
>>> Planck18.to_format("astropy.table") # No renaming
<QTable length=1>
name H0 Om0 Tcmb0 Neff m_nu Ob0
km / (Mpc s) K eV
str8 float64 float64 float64 float64 float64[3] float64
-------- ------------ ------- ------- ------- ----------- -------
Planck18 67.66 0.30966 2.7255 3.046 0.0 .. 0.06 0.04897
>>> Planck18.to_format("astropy.table", rename={"H0": "Hubble"})
<QTable length=1>
name Hubble Om0 Tcmb0 Neff m_nu Ob0
km / (Mpc s) K eV
str8 float64 float64 float64 float64 float64[3] float64
-------- ------------ ------- ------- ------- ----------- -------
Planck18 67.66 0.30966 2.7255 3.046 0.0 .. 0.06 0.04897
New properties to access Cosmology
parameters#
The Cosmology
class now has a new property to access the parameters of the cosmology:
parameters
. This property return a
MappingProxyType
object, which is a read-only dictionary of all the
non-derived parameter values on the Cosmology
instance. For example:
>>> from astropy.cosmology import Planck18
>>> Planck18.parameters["H0"]
<Quantity 67.66 km / (Mpc s)>
When accessed from the cosmology class itself, the returned dictionary is
not the parameter values but Parameter
objects
with information about the parameter used when setting up the cosmology:
>>> from astropy.cosmology import FlatLambdaCDM
>>> FlatLambdaCDM.parameters["H0"]
Parameter(derived=False, unit=Unit("km / (Mpc s)"), equivalencies=[], ...)
Parameter
as a dataclass()
#
The Parameter
class is now a dataclass()
.
This means that the dataclasses
machinery can be used to work with
Parameter
objects. For example:
>>> from dataclasses import replace
>>> from astropy.cosmology import FlatLambdaCDM
>>> m_nu = FlatLambdaCDM.parameters["m_nu"]
>>> m_nu
Parameter(default=<Quantity 0. eV>, derived=False, unit=Unit("eV"), ...)
>>> replace(m_nu, derived=True)
Parameter(default=<Quantity 0. eV>, derived=True, unit=Unit("eV"), ...)
>>> from dataclasses import asdict
>>> asdict(m_nu)
{'default': <Quantity 0. eV>, 'derived': False, 'unit': Unit("eV"), ...}
It’s also much easier to create new Parameter
subclasses
>>> from dataclasses import make_dataclass, field, fields
>>> from astropy.cosmology import Parameter
>>> NewP = make_dataclass("NewP", [("newfield", float, field(default=None))], bases=(Parameter,), frozen=True)
>>> tuple(f.name for f in fields(NewP))
(..., 'newfield')
Updates to how IERS data are handled#
Some parts of astropy, such as coordinate and time transformations, rely on tables from the International Earth Rotation and Reference Systems (IERS) service (these are the IERS-A, IERS-B, and leap second tables). IERS-A used to always be automatically downloaded, whereas the IERS-B and leap second tables were bundled with astropy. All tables are now bundled in the standalone astropy-iers-data package which is regularly updated and installed automatically when astropy is installed.
The main benefit of moving the files to this package is to make it easier to
use astropy without an internet connection, and to facilitate updating the
tables if needed. Users that want to ensure they have the latest available
IERS data can now install the latest version of the
astropy-iers-data package using pip
or conda
, or alternatively
download the package manually and transfer it to a computer that has no
public internet connection.
Masked Time values now use Masked arrays internally#
Time
can now be initialized with masked input that either uses Masked
, from
astropy’s astropy.utils.masked
package, or numpy.ma.MaskedArray
, from numpy,
and will now use Masked
jd1
and jd2
internally to represent
the mask. As a result, all output from masked Time
instances will now be
masked as well. For instance, converting a TimeDelta
to a Quantity
will
give a masked quantity (instead of a regular quantity with masked entries set
to np.nan
).
Small example:
>>> from astropy.time import Time
>>> from astropy.utils.masked import Masked
>>> t = Time(Masked([52000., 52001, 52002], mask=[False, True, False]), format='mjd')
>>> t
<Time object: scale='utc' format='mjd' value=[52000. ——— 52002. ]>
>>> t.isot
MaskedNDArray(['2001-04-01T00:00:00.000', ———,
'2001-04-03T00:00:00.000'], dtype='<U23')
>>> (t-t[0]).to('s')
<MaskedQuantity [ 0., ———, 172800.] s>
Note
The type of masked output will now be astropy’s Masked
. For
backward compatibility, a configuration item,
masked_array_type
, allows one to choose the
type of masked array, with “astropy” (default) to always use
Masked
, and “numpy” to use MaskedArray
when possible.
Reading and writing VO model annotations#
Model Instances in VOTables (MIVOT) defines a syntax to map VOTable data to any model serialised in VO-DML (Virtual Observatory Data Modeling Language). The data model elements are grouped in an independent annotation block complying with the MIVOT XML schema which is added as an extra resource above the table element. In Astropy, the MIVOT block is implemented as a new component of the Resource element (MivotBlock class). MivotBlock instances can only be held by resources with “type=meta”. In this new feature, Astropy is able to read and write MIVOT annotations from and within VOTables. There is no function processing data models, they will be delegated to affiliated packages such as PyVO.
See Reading and writing VO model annotations for more details.
TimeDelta string format “quantity_str”#
A new TimeDelta format "quantity_str"
is now available that
represents the time delta as a string with one or more Quantity components. This format
provides a human-readable multi-scale string representation of a time delta. It is
convenient for applications like a configuration file or a command line option.
Warning
The default output format is not yet finalized and may change in version 6.1 of astropy. The input format is stable. Please see issue 15485 for more details.
The format is a string with one or more time Quantity components separated by optional
whitespace, for example "1yr 2d 3hr 4min 5.6s"
. In more detail:
The string is a sequence of one or more components.
Each component is a number followed by an astropy unit of time.
For input, whitespace within the string is allowed but optional.
For output, there is a single space between components.
The order (yr, d, hr, min, s) is fixed but individual components are optional.
The allowed component units are shown below and correspond to scaling relations defined by the astropy units:
“yr”: years (365.25 days)
“d”: days (24 hours)
“hr”: hours (60 minutes)
“min”: minutes (60 seconds)
“s”: seconds
Note
These definitions correspond to physical units of time and are NOT calendar date intervals. Thus adding “1yr” to “2000-01-01 00:00:00” will give “2000-12-31 06:00:00” instead of “2001-01-01 00:00:00”.
See TimeDeltaQuantityString
for more details.
VOTable now supports PARQUET serialization#
The PARQUET file format allows a more efficient handling of large data amounts. However, one problem of PARQUET is that it only provides a limited number of column metadata keywords. A way to make it consistent with VO standards is to embed it into a VOTable file.
This serialization works similar to the VOTable FITS serialization that already existed. It basically creates two files, on VOTable file and one PARQUET file, which are linked together. The advantage of this method is that any column metadata can be saved along with the PARQUET file, following VO standards.
Reading and writing of the VOTable PARQUET serialization is fully supported by
astropy.io.votable
and the unified Table
read/write interface.
This serialization can be used by setting the format
argument to
'votable.parquet'
, while 'votable'
can be used for reading in such a file.
The method works for both absolute and relative parquet file paths.
Example for writing:
>>> import numpy as np
>>> from astropy.table import Table
>>>
>>> # Create some fake data
>>> number_of_objects = 10
>>> ids = [f"COSMOS_{ii:03g}" for ii in range(number_of_objects)]
>>> redshift = np.random.uniform(low=0, high=3, size=number_of_objects)
>>> mass = np.random.uniform(low=1e8, high=1e10, size=number_of_objects)
>>> sfr = np.random.uniform(low=1, high=100, size=number_of_objects)
>>> cosmos = Table([ids, redshift, mass, sfr], names=["id", "z", "mass", "sfr"])
>>>
>>> # Create Column metadata
>>> column_metadata = {
... "id": {"unit": "", "ucd": "meta.id", "utype": "none"},
... "z": {"unit": "", "ucd": "src.redshift", "utype": "none"},
... "mass": {"unit": "solMass", "ucd": "phys.mass", "utype": "none"},
... "sfr": {"unit": "solMass / yr", "ucd": "phys.SFR", "utype": "none"},
... }
>>>
>>> # Write VOTable with Parquet serialization
>>> filename = "votable_with_parquet.vot"
>>> cosmos.write(filename, column_metadata=column_metadata, format="votable.parquet")
Example for reading a votable with a separate parquet file. Note the metadata is accessible on the column level:
>>> from astropy.table import Table
>>>
>>> # Open VOTable with PARQUET serialization
>>> cosmos_table = Table.read("votable_with_parquet.vot", format='votable')
>>>
>>> cosmos_table
<Table length=10>
id z mass sfr
--- --- solMass solMass / yr
str10 float64 float64 float64
---------- ------------------ ------------------ ------------------
COSMOS_000 0.2399334343209477 3777315779.8348713 31.82322447540133
COSMOS_001 0.0647935880275512 9392519748.07293 4.532295061239315
COSMOS_002 2.738748364941223 4411572229.2340555 86.54423711854747
COSMOS_003 2.013180712201346 2813958500.958293 11.142967938935586
COSMOS_004 2.5044578163101794 1533373563.21987 48.320129287388
COSMOS_005 2.1113936608027988 7431616021.640879 29.67334486542601
COSMOS_006 1.5525290310888193 8700624063.99011 36.19567476784732
COSMOS_007 2.5879551130469074 6501853315.057587 54.19908247198407
COSMOS_008 0.3978276727610941 1865149084.3401675 76.53909767648796
COSMOS_009 1.5021072916190177 4394424029.923725 91.68600618578257
>>>
>>> # Check out fields and column metadata
>>> cosmos_table['sfr'].meta
OrderedDict([('ucd', 'phys.SFR'), ('utype', 'none')])
Faster FITS file decompression#
By default compressed FITS files (with gzip, bzip2 or zip) are decompressed
progressively depending on what data is needed. This allows to limit the memory
usage when accessing only some part of a file but it can be much slower than
decompressing the whole file at once. With the new keyword fits.open(...,
decompress_in_memory=True)
it is now possible to decompress the whole file in
memory, which will be faster in some cases.
New GeneralSersic2D
model#
A new GeneralSersic2D
model
has been added to the modeling package. This model is a generalized two
dimensional Sersic surface brightness profile that allows for “boxy” or
“disky” (kite-like) isophote shapes.
Full change log#
To see a detailed list of all changes in version v6.0, including changes in API, please see the Full Changelog.
Contributors to the v6.0 release#
The people who have contributed to the code for this release are:
|
|
|
|
Where a * indicates that this release contains their first contribution to astropy.