What’s New in Astropy 7.0?#
Overview#
Astropy 7.0 is a major release that adds significant new functionality since the 6.1 release.
In particular, this release includes:
NumPy constructor functions with a like argument are now supported with Quantity
Change default type for meta attribute to dict and update ECSV writer
In addition to these major changes, Astropy v7.0 includes a large number of smaller improvements and bug fixes, which are described in the Full Changelog. By the numbers:
1440 commits have been added since 6.1
213 issues have been closed since 6.1
466 pull requests have been merged since 6.1
52 people have contributed since 6.1
22 of which are new contributors
Full MaskedQuantity
Support in QTable
#
Masked quantities were already used in many table functions, like reading from
files, and are now fully supported throughout, i.e., MaskedQuantity
are
now always used in QTable
to represent masked quantities (or when the
QTable
is created with masked=True
). This removes the last vestiges of
a work-around where a normal Quantity
was used with a stub of a mask, and
fixes functions like reading of table data from a list of dict that includes
quantities with missing entries, and aggregation of MaskedQuantity
in
table groups.
Coordinate frames can now be stored in tables#
Coordinate frames like ICRS
and AltAz
can now be stored in tables, as
was already the case for SkyCoord
and the underlying representations such
as SphericalRepresentation
.
This includes all frames, also those that do not have associated data, such as
a SkyOffsetFrame
in which the RA, Dec of the origin might represent a
pointing directions for a tiled observation, and the position angle the roll of
a spacecraft.
Table show_in_notebook
is back with ipydatagrid
#
Due to popular demand, the show_in_notebook()
method is revived (instead of deprecated) with a new backend that would
require an optional dependency, ipydatagrid
. As a result, a new module
called astropy.table.notebook_backends
is added to support different
backends for rendering Astropy tables in Jupyter notebooks.
Ordering of table columns constructed from rows#
The column order in a Table
constructed from a list
or rows (dict
or Row
) may change using astropy
version 7.0
if the
first row has missing values.
Before 7.0
, the column ordering was determined from the first row if it contained
values for all the columns, or by sorting the final column names alphabetically if it
did not. Starting with 7.0
, columns are always added in the order they appear
when iterating over the list
of rows.
For example, create a table as shown below:
>>> from astropy.table import Table
>>> data = [{'b': 10, 'c': 7, },
... {'a': 15, 'c': 35, 'b': 20}]
>>> t = Table(data) # or Table(rows=data), which is equivalent
Before 7.0
the table would look like this:
a b c
--- --- ---
-- 10 7
15 20 35
Starting with 7.0
the table would instead look like this:
b c a
--- --- ---
10 7 --
20 35 15
Table.pformat
is now independent of terminal dimensions#
Table.pformat
and Column.pformat
do not truncate their outputs according
to terminal height and width by default any more. The new default behavior is
intended to be less surprising.
Truncating representations to fit the current terminal is still supported but
now requires explicitly passing max_lines=None
and/or max_width=None
.
Table.pformat_all
is deprecated as it is now fully redundant.
Quantity.to_string
supports formatter
for formatting#
The to_string()
method now supports a formatter
parameter.
This feature supports both Python’s format specification mini-language via format strings and
custom formatting through callables. This enables users to have explicit and consistent control
over the numerical representation of quantities, accommodating a wide range of formatting needs.
Previously, the method primarily relied on the precision
parameter for format control, which dictated
the number of significant digits and did not provide much freedom in the latex format.
Example:
>>> from astropy import units as u
>>> q = u.Quantity(123.456, u.m)
>>> custom_format = lambda x: f"\\approx {float(x):.1f}"
>>> q.to_string(formatter=custom_format, format='latex')
'$\\approx 123.5 \\; \\mathrm{m}$'
>>> q.to_string(formatter='.3e', format='latex')
'$1.235 \\times 10^{2} \\; \\mathrm{m}$'
>>> q.to_string(precision=3, format='latex')
'$123 \\; \\mathrm{m}$'
NumPy constructor functions with a like
argument are now supported with Quantity
#
We added support for constructing Quantity
arrays from 21 NumPy functions
via the like
keyword argument.
Example:
>>> import numpy as np
>>> from astropy import units as u
>>> q = u.Quantity(1.0, u.m)
>>> np.arange(0, 10, 1, like=q)
<Quantity [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] m>
>>> np.eye(3, like=q)
<Quantity [[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]] m>
>>> np.full((3, 3), 1*u.s, like=q)
<Quantity [[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]] s>
The unit of the output Quantity
is defined from the first quantity argument
where it is meaningful. Otherwise, and by default, the output unit will be that
of the like
argument itself.
Here’s the entire list of functions affected
Change default type for meta
attribute to dict
and update ECSV writer#
We have changed the default type for the meta
attribute in Table
and Column
(and subclasses) from OrderedDict
to dict
. Since Python 3.8 the dict
class
is ordered by default, so there is no need to use OrderedDict
.
In addition, the ECSV table writer in ASCII Tables (astropy.io.ascii) was updated to consistently
write the meta
attribute as an ordered map using the !!omap
tag. This
convention conforms to the ECSV specification and is supported by
existing ECSV readers. Previously the meta
attribute could be written as an ordinary
YAML map, which is not guaranteed to preserve the order of the keys.
Improve the Contributor Documentation#
The Contributor documentation has been significantly improved. It now includes a Quickstart Guide with concise instructions on setting up a development environment and making a pull request. In addition, the developer documentation was reorganized and simplified where possible to improve readability and accessibility. We welcome continued feedback on how to make contributing to Astropy even easier and more enjoyable.
Typing in astropy.stats#
The astropy.stats
module is now fully typed. This is the first subpackage for
which this the case.
Converting units on dask and other array-like objects#
It is now possible to pass in array-like objects such as dask arrays as the
value in Unit.to
and have those arrays not be converted to Numpy arrays:
>>> from dask import array as da
>>> from astropy import units as u
>>> arr = da.arange(10)
>>> u.m.to(u.km, value=arr)
dask.array<mul, shape=(10,), dtype=float64, chunksize=(10,), chunktype=numpy.ndarray>
Note that it is not yet possible to use Quantity
with dask arrays directly.
Performance improvements in astropy.modeling#
There have been significant improvements to the performance of non-linear fitters in
astropy.modeling
, with typical speedups of 2x for simple models and 4x or
more for compound models.
Fitting models in parallel with N-dimensional data#
A new function, parallel_fit_dask()
, has been
added to the astropy.modeling
module. This function makes it easy to fit
many parts of an N-dimensional array in parallel, such as fitting all the
spectra in a spectral cube. This makes use of the dask package to efficiently parallelize the problem,
running it either on multiple processes of a single machine or in a distributed
environment. A simple example might be:
>>> from astropy.modeling.models import Gaussian1D
>>> from astropy.modeling.fitting import parallel_fit_dask, TRFLSQFitter
>>> model_fit = parallel_fit_dask(model=Gaussian1D(),
... fitter=TRFLSQFitter(),
... data=data,
... world=wcs,
... fitting_axes=0)
where data
is a 3-D array, and wcs
is the WCS
object associated with the data. A full example can be found at
Fitting models in parallel with N-dimensional data.
RGB image visualization enhancements#
The RGB image visualization functionality
in astropy.visualization
has been expanded to support more flexible methods
for creating composite RGB images.
A new function make_rgb()
allows for creating RGB
images with independent scaling on each filter, using arbitrary stretch and
interval functions (instances of subclasses of
BaseStretch
and
BaseInterval
, respectively).
Additionally, the make_lupton_rgb()
function
(which performs interconnected R, G, B image scaling) now also supports
arbitrary stretch and interval functions, in addition to the default Lupton
asihn stretch.
intervals = [ManualInterval(vmin=0, vmax=np.percentile(img,99.95)) for img in [i,r,g]]
rgb_log = make_rgb(i, r, g, interval=intervals, stretch=LogStretch(a=1000))
rgb_log_lupton = make_lupton_rgb(i, r, g, interval=intervals, stretch_object=LogStretch(a=5))
axes[0].imshow(rgb_log, origin='lower')
axes[1].imshow(rgb_log_lupton, origin='lower')
New Lorentz2D
model#
A new 2D Lorentzian model has been added to the astropy.modeling
package.
Faster guessing of formats in astropy.io.ascii
#
The performance of guessing the table format when reading large files with
astropy.io.ascii
has been improved. Now the process uses at most
10000 lines of the file to check if it matches the format. This behavior can
be configured, e.g.:
>>> from astropy.io.ascii import conf
>>> conf.guess_limit_lines = 100000
and the limit can be disabled by setting this value to None
. When reading large tables
you should specify the format of the table explicitly if possible.
Support VOTable version 1.5#
The Astropy VOTable parser
now supports version 1.5 of the VOTable standard. The main new feature is that the
COOSYS
specification now has a refposition
attribute analogous to that for TIMESYS
.
At this writing, version 1.5 is a proposed standard, but it is expected to be approved as an official recommendation soon.
New SimpleNorm
class#
A new convenience class, SimpleNorm
,
has been added to the astropy.visualization
module.
This class provides a simple interface to create
a ImageNormalize
normalization object that can be used with Matplotlib’s
imshow()
method. It also provides
a imshow()
method that
wraps Matplotlib’s matplotlib.axes.Axes.imshow()
method and
automatically sets the normalization.
Here’s an example using the SimpleNorm()
function with its imshow()
method:
import numpy as np
import matplotlib.pyplot as plt
from astropy.visualization import SimpleNorm
# Generate a test image
image = np.arange(65536).reshape((256, 256))
# Create an ImageNormalize object
snorm = SimpleNorm('sqrt', percent=98)
# Display the image
fig, ax = plt.subplots()
axim = snorm.imshow(image, ax=ax, origin='lower')
fig.colorbar(axim)
New SigmaClippedStats
class#
A new convenience class, SigmaClippedStats
, has
been added to the stats
module. This class provides a
convenient way to compute statistics of an array with sigma-clipping. A
simple example might be:
>>> import numpy as np
>>> from astropy.stats import SigmaClippedStats
>>> rng = np.random.default_rng(seed=42)
>>> data = rng.exponential(scale=100, size=500)
>>> stats = SigmaClippedStats(data, sigma=3, maxiters=10)
>>> stats.min(), stats.max(), stats.sum()
(np.float64(0.8129422833034009), np.float64(255.34193997940474), np.float64(36783.895498717866))
>>> stats.mean(), stats.median(), stats.std()
(np.float64(79.61882142579624), np.float64(60.01103363578014), np.float64(65.4457063794851))
>>> stats.mode(), stats.var(), stats.mad_std()
(np.float64(20.79545805574793), np.float64(4283.1404835097765), np.float64(62.608350894722484))
>>> stats.biweight_location(), stats.biweight_scale()
(np.float64(67.98055399699436), np.float64(64.82889460022386))
Automatic placement of axis and tick labels for WCSAxes
#
WCSAxes
now automatically selects which coordinates are displayed on which axes
of a plot, a change from the previous behavior of using the ordering of the
world axes in the WCS object.
The selection is done by first placing the coordinates on the different axes in the order in which they appear in the WCS and then trying different permutations of coordinates on different axes to see if it is possible to increase the number of tick labels. This addresses the situation where ticks are shown along an axis where the world coordinate hardly varies when it varies substantially along the other axis.
This default can be overridden by manually setting the axes to use with
set_ticks_position
,
set_ticklabel_position
, and
set_axislabel_position
. In practice, you should be able
to just call set_ticklabel_position
because axis labels
and ticks will default to being shown on the same axes as tick labels.
Support for masks in coordinates
#
Initial support for masks has been implemented for SkyCoord
, as well as for
coordinate frames and coordinate representations.
Like more generally for Masked
instances, one can access the mask using
mask
and check whether the underlying data are
masked using masked
. Like for all masked
classes, one can access underlying unmasked data using
unmasked
and one can get a
new instance with masked data replaced with a fill value using
filled()
.
By default, the mask combines all masks of the underlying representation
components, including those on possible differentials like radial velocity and
proper motion. It is possible to make other choices using the new
get_mask()
method. For instance,
sc.get_mask("ra", "dec")
would get the combined masks of just the angular
components, which may be useful if dealing with, e.g., a catalogue of stars
where distances are available only for some of the objects.
For concrete examples, see Masks.
Full change log#
To see a detailed list of all changes in version v7.0, including changes in API, please see the Full Changelog.
Contributors to the 7.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.