.. doctest-skip-all

.. _whatsnew-3.1:

************************
What's New in SunPy 3.1?
************************
The SunPy project is pleased to announce the 3.1 release of the sunpy core package.

On this page, you can read about some of the big changes in this release.

.. contents::
    :local:
    :depth: 1

SunPy 3.1 also includes a large number of smaller improvements and bug fixes, which are described in the :ref:`changelog`.

By the numbers:

* 610 commits have been added since 3.0
* 56 issues have been closed since 3.0
* 145 pull requests have been merged since 3.0
* 16 people have contributed since 3.0
* 8 of which are new contributors

Increase in required package versions
=====================================
We have bumped the minimum version of several packages we depend on; these are the new minimum versions for sunpy 3.1:

- astropy >= 4.2
- matplotlib >= 3.2.0
- numpy >= 1.17.0
- pandas >= 1.0.0


Increased in-situ data support
==============================
Two new features have significantly increased support for in-situ data returned by heliospheric missions.
See :ref:`sphx_glr_generated_gallery_acquiring_data_search_cdaweb.py` for a full example of searching for, downloading, and loading a CDF file into sunpy.

New CDAWeb client
-----------------
A new Fido client to search the Coordinated Data Analysis Web (CDAWeb) has been added to `sunpy.net`.
This allows one to search for and download data from many space physics missions that take in-situ data (including Parker Solar Probe and Solar Orbiter).
In combination with the new CDF reading abilities of `sunpy.timeseries.TimeSeries`, this provides a full workflow for searching for, downloading, and analysing in-situ data contained within CDF files.

Support for .cdf files
----------------------
`sunpy.timeseries.TimeSeries` now supports loading CDF files if the external library ``cdflib`` is installed.

New limb drawing function
=========================
The solar limb as seen from an arbitrary observer coordinate can now be drawn on a world coordinate system aware
Axes using the ``sunpy.visualization.draw_limb`` function.

.. minigallery:: sunpy.visualization.draw_limb


New WISPR map source
====================
A new map source for the WISPR instrument on Parker Solar Probe has been added.
This improves the `~sunpy.map.GenericMap.name` of the map and adds correct
information for the `~sunpy.map.GenericMap.processing_level` and
`~sunpy.map.GenericMap.exposure_time`.

Changes to map metadata fixes
=============================
The `~sunpy.map.GenericMap` map sources are primarily used to modify metadata values to either fix known incorrect values in a given data source, or make the metadata comply with the FITS standard.
There are two ways in which the sunpy map sources can do this:

1. Directly edit the values stored in the FITS metadata.
2. Overload properties (e.g. `sunpy.map.GenericMap.unit`) such that they return the correct information without modifying the underlying metadata.

In previous versions of sunpy there has been no consistency in which of these two approaches is taken.

As of sunpy 3.1, the second approach is now consistently taken, and **sunpy no longer edits any FITS metadata values** when constructing a Map.
`~sunpy.map.GenericMap` properties now consistently provide corrected information.
For details of any corrections applied, the docstrings of different map sources (e.g., `~sunpy.map.sources.HMIMap` - see :ref:`map-sources` for a list of map sources) provide information on any assumptions made beyond the original FITS metadata when constructing the map properties.

For all maps, the following fixes are no longer made:

- DATE-OBS is no longer replaced by DATE_OBS as a fallback
- NAXIS, NAXIS1, NAXIS2, BITPIX are no longer populated if not present
- BUNIT is no longer corrected to be a FITS compliant unit string
- WAVEUNIT  is no longer automatically populated from the header comments if it is not present.

For specific map sources, the following keywords are no longer modified or added:

- `~sunpy.map.sources.KCorMap`: OBSERVATORY, DETECTOR, WAVEUNIT, DSUN_OBS, HGLN_OBS
- `~sunpy.map.sources.SWAPMap`: OBSRVTRY, DETECTOR
- `~sunpy.map.sources.RHESSIMap`: CUNIT1, CUNIT2, CTYPE1, CTYPE2, WAVEUNIT, WAVELNTH
- `~sunpy.map.sources.AIAMap`: BUNIT, DETECTOR
- `~sunpy.map.sources.HMIMap`: DETECTOR, CRDER1, CRDER2
- `~sunpy.map.sources.HMISynopticMap`: CUNIT1, CUNIT2, CDELT1, CDELT2, DATE-OBS
- `~sunpy.map.sources.EITMap`: WAVEUNIT, CUNIT1, CUNIT2
- `~sunpy.map.sources.LASCOMap`: DATE-OBS, DATE_OBS, CROTA, CROTA1, CROTA2, CUNIT1, CUNIT2
- `~sunpy.map.sources.MDIMap`: CUNIT1, CUNIT2
- `~sunpy.map.sources.MDISynopticMap`: CUNIT1, CUNIT2, CDELT2, DATE-OBS, CRDER1, CRDER2
- `~sunpy.map.sources.EUVIMap`: WAVEUNIT, DATE-OBS, CROTA, CROTA2
- `~sunpy.map.sources.CORMap`: DATE-OBS
- `~sunpy.map.sources.HIMap`: DATE-OBS
- `~sunpy.map.sources.SUVIMap`: DETECTOR, TELESCOP
- `~sunpy.map.sources.TRACEMap`: DETECTOR, OBSRVTRY, CUNIT1, CUNIT2
- `~sunpy.map.sources.SXTMap`: DETECTOR, TELESCOP, DSUN_APPARENT
- `~sunpy.map.sources.XRTMap`: DETECTOR, TELESCOP, TIMESYS
- `~sunpy.map.sources.SOTMap`: DETECTOR, TELESCOP
- `~sunpy.map.sources.SJIMap`: DETECTOR, WAVEUNIT, WAVELNTH, CUNIT1, CUNIT2
- `~sunpy.map.sources.EUIMap`: CROTA, CROTA2

Changes to map date/time handling
=================================

New date properties
-------------------
The properties `~sunpy.map.GenericMap.date_start`,
`~sunpy.map.GenericMap.date_end`, and `~sunpy.map.GenericMap.date_average` have
been added to be drawn from the relevant FITS metadata, if present in the map
header. These are from new keywords defined in version 4 of the FITS standard,
which have precise meanings compared to the previously ill-defined DATE-OBS.

Changes to `~sunpy.map.GenericMap.date`
---------------------------------------
`sunpy.map.GenericMap.date` now looks for more metadata than just DATE-OBS.
This property can return any one of the new properties (see above) depending
on the metadata present in the map. It now draws from, in order of preference:

1. The DATE-OBS FITS keyword
2. `~sunpy.map.GenericMap.date_average`
3. `~sunpy.map.GenericMap.date_start`
4. `~sunpy.map.GenericMap.date_end`
5. The current time.

If DATE-OBS is present alongside DATE-AVG or DATE-BEG and DATE-END, this results
in a behaviour change to favour the new (more precisely defined) keywords.
It is recommended
to use `~sunpy.map.GenericMap.date_average`,
`~sunpy.map.GenericMap.date_start`, or `~sunpy.map.GenericMap.date_end`
instead if you need one of these specific times.

Addition of new time format `~sunpy.time.TimeTaiSeconds`
--------------------------------------------------------
The new `~sunpy.time.TimeTaiSeconds` format is the number of
SI seconds from 1958-01-01 00:00:00, which includes UTC leap seconds.
1958-01-01 00:00:00 is the defined time when International Atomic Time (TAI)
and Universal Time (UT) are synchronized.

This format is equivalent to the output of the SSW ``anytim2tai`` routine, and
related routines, for times after 1972-01-01.  Be aware that the SSW routines
are not written to provide valid results for times before 1972-01-01.

This format is equivalent to `~astropy.time.TimeUnixTai`, except that the epoch
is 12 years earlier.

Propagating solar-surface coordinates in time
=============================================
There is now an easy-to-use context manager (:func:`~sunpy.coordinates.propagate_with_solar_surface`) to enable coordinate transformations to take solar rotation into account.
Normally, a coordinate refers to a point in inertial space, so transforming it to a different observation time does not move the point at all.
Under this context manager, a coordinate will be treated as if it were referring to a point on the solar surface.
Coordinate transformations with a change in observation time will automatically rotate the point in heliographic longitude for the time difference, with the amount of rotation depending on the specified differential-rotation model.

.. minigallery:: sunpy.coordinates.propagate_with_solar_surface


Convenient reprojection of maps
===============================
`~sunpy.map.Map` objects now have the :meth:`~sunpy.map.GenericMap.reproject_to` method to easily reproject the map to a new WCS.
The returned map will be of type `~sunpy.map.GenericMap`, with no metadata preserved from the original map, so copy over any desired metadata from the original map.
This method requires the optional package `reproject` to be installed.

.. minigallery:: sunpy.map.GenericMap.reproject_to

JSOC keyword filtering with Fido
================================
Support for filtering searches with JSOC keywords has been added to ``Fido.search``::

    >>> from sunpy.net import Fido, attrs as a
    >>> import astropy.units as u
    >>> Fido.search(a.Time('2014-01-01T00:00:00', '2014-01-01T01:00:00'),
        a.jsoc.Series('aia.lev1_euv_12s'), a.Wavelength(304*u.AA), a.jsoc.Keyword("EXPTIME") > 1)
    <sunpy.net.fido_factory.UnifiedResponse object at 0x7fe16a5d20d0>
    Results from 1 Provider:

    301 Results from the JSOCClient:
    Source: http://jsoc.stanford.edu

        T_REC         TELESCOP INSTRUME WAVELNTH CAR_ROT
    -------------------- -------- -------- -------- -------
    2014-01-01T00:00:01Z  SDO/AIA    AIA_4      304    2145
    2014-01-01T00:00:13Z  SDO/AIA    AIA_4      304    2145
    2014-01-01T00:00:25Z  SDO/AIA    AIA_4      304    2145
    2014-01-01T00:00:37Z  SDO/AIA    AIA_4      304    2145
                    ...      ...      ...      ...     ...
    2014-01-01T00:59:25Z  SDO/AIA    AIA_4      304    2145
    2014-01-01T00:59:37Z  SDO/AIA    AIA_4      304    2145
    2014-01-01T00:59:49Z  SDO/AIA    AIA_4      304    2145
    2014-01-01T01:00:01Z  SDO/AIA    AIA_4      304    2145
    Length = 301 rows
    >>> Fido.search(a.Time('2014-01-01T00:00:00', '2014-01-01T01:00:00'),
        a.jsoc.Series('aia.lev1_euv_12s'), a.Wavelength(304*u.AA), a.jsoc.Keyword("EXPTIME") == 1)
    <sunpy.net.fido_factory.UnifiedResponse object at 0x7fe16a5d20d0>
    Results from 1 Provider:

    0 Results from the JSOCClient:
    Source: http://jsoc.stanford.edu

Please be aware of two caveats:

- We do not validate the value used for comparison.
- Passing in a keyword without comparison to a value (e.g. ``==0``, ``< 10``) will error.


Arithmetic operations with maps
===============================

`~sunpy.map.GenericMap` objects now support arithmetic operations (i.e. addition, subtraction, multiplication, division) with array-like quantities.
This includes scalar quantities as well as Numpy arrays.
Notably, arithmetic operations between two `~sunpy.map.GenericMap` objects are not supported.

Contributors to this Release
============================

The people who have contributed to the code for this release are:

-  Alasdair Wilson  *
-  Albert Y. Shih
-  Anubhav Sinha  *
-  Conor MacBride
-  David Stansby
-  Devansh Shukla  *
-  Jeffrey Aaron Paul
-  Nabil Freij
-  Noah Altunian  *
-  Rohan Sharma  *
-  Samriddhi Agarwal
-  Stuart Mumford
-  Thomas Braccia  *
-  Tim Gates  *
-  Will Barnes

Where a * indicates that this release contains their first contribution to SunPy.
