<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://sunpy.org/</id>
  <title>Blog - Posts by David Stansby</title>
  <updated>2026-04-16T16:25:22.133692+00:00</updated>
  <link href="https://sunpy.org/"/>
  <link href="https://sunpy.org/blog/author/david-stansby/atom.xml" rel="self"/>
  <generator uri="https://ablog.readthedocs.io/" version="0.11.13">ABlog</generator>
  <entry>
    <id>https://sunpy.org/posts/2023/2023-05-10-timeseries_sdg/</id>
    <title>The future of time series data in sunpy</title>
    <updated>2023-05-10T00:00:00+00:00</updated>
    <author>
      <name>David Stansby</name>
    </author>
    <content type="html">&lt;section id="the-future-of-time-series-data-in-sunpy"&gt;

&lt;p&gt;In late 2022 I got a &lt;a class="reference external" href="https://numfocus.org/programs/small-development-grants"&gt;small development grant&lt;/a&gt; from &lt;a class="reference external" href="https://numfocus.org/"&gt;NumFocus&lt;/a&gt; to scope the future of time series data in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;sunpy&lt;/span&gt;&lt;/code&gt;.
The successful application &lt;a class="reference external" href="https://github.com/sunpy/sunpy/wiki/2022-Timeseries-Small-Development-Grant"&gt;can be read on the sunpy wiki&lt;/a&gt;.
The application contains context that I won’t repeat here.
This blog post is the key outcome of this grant, with a record of what I did, the recommendations I made, and any decisions we came to as a community.&lt;/p&gt;
&lt;section id="user-requirements"&gt;
&lt;h2&gt;User requirements&lt;/h2&gt;
&lt;p&gt;The first stage of my work investigated what the user requirements are for a sunpy data container for time series data. As part of this I used my own experience and the following community engagement:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Discussion at one of the weekly sunpy community meetings in December 2022&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://groups.google.com/g/pyhc-list/c/ujnZEZcsI_k/m/gNfYrIJdBgAJ"&gt;Discussion on the Python in Heliophysics mailing list&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://community.openastronomy.org/t/choosing-a-future-data-container-for-timeseries-data/556?u=dstansby"&gt;Discussion on the SunPy forum&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From these discsusions came the following list of requirements:&lt;/p&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;Requirement&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Notes&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Store data that is a function of time&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;This means the time column should be treated as the index or coordinates to the data, and be stored as a time-like type.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Handle different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Data can have times defined in a variety of different time scales (e.g. UTC, TAI)&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Store multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Although time is a common index to timeseries data, it isn’t always the only one. As an example, velocity distribution functions measured in the solar wind are 4D datasets, with data as a function of time and three dimensions in velocity space.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Handle time scales with leapseconds&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Some timescales can contain timestamps that occur within a leapsecond.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Store and use physical units with the data and any non-time indices&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Store data in a format that can be used with scientific Python libraries&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Support for storing out-of memory datasets&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Store metadata alongside actual data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Have a way to store an observer coordinate alongside the time index&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Have an easy way to do common data manipulation tasks&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;e.g. interpolating, resampling, rebinning&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Have a way to combine multiple timeseries objects, and keep track of metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Ability to convert to other common time series objects (e.g. &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt;)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Functionality for loading and saving out to common file formats&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="existing-options-for-a-data-container"&gt;
&lt;h2&gt;Existing options for a data container&lt;/h2&gt;
&lt;p&gt;The next step was to identify a set of possible data containers that could be used to store time- series data in sunpy.
The identified options were:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.timeseries.TimeSeries&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt; (or &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataSet&lt;/span&gt;&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;numpy.ndarray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ndcube&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id="what-do-other-projects-use"&gt;
&lt;h3&gt;What do other projects use?&lt;/h3&gt;
&lt;p&gt;I also looked at what &lt;a class="reference external" href="https://heliopython.org/projects/"&gt;Python in Heliophysics projects&lt;/a&gt; use (as of writing, in Jan 2023):&lt;/p&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;Package&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Container&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/sunpy/sunpy/"&gt;sunpy&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Custom &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;TimeSeries&lt;/span&gt;&lt;/code&gt; object, backed by &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/hapi-server/client-python"&gt;HAPI Client&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;numpy.ndarray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/spedas/pyspedas"&gt;pySPEDAS&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Not clear if users can access the data itself&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/spacepy/spacepy"&gt;spacepy&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Unclear if there is any specific timeseries container object&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://gitlab.com/aidaspace/aidapy"&gt;aidapy&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/MAVENSDC/cdflib"&gt;cdflib&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;numpy.ndarray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/sunpy/ndcube"&gt;NDCube&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NDCube&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/MAVENSDC/pytplot"&gt;pytplot&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/jgieseler/solo-epd-loader"&gt;solo-epd-loader&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/SciQLop/speasy"&gt;speasy&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Custom &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DataContainer&lt;/span&gt;&lt;/code&gt; object, backed by &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;numpy.ndarray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;There is no common container used, with only &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.TimeSeries&lt;/span&gt;&lt;/code&gt; not represented out of the possible options above.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="what-datasets-does-sunpy-currently-support"&gt;
&lt;h3&gt;What datasets does sunpy currently support?&lt;/h3&gt;
&lt;p&gt;sunpy currently has built in support for reading CDF files that conform to the &lt;a class="reference external" href="https://spdf.gsfc.nasa.gov/sp_use_of_cdf.html"&gt;Space Physics Guidelines for CDF&lt;/a&gt;, as long as the dataset is one- or two- dimensional.
Alongside this several custom data readers have been written to support different data sources:&lt;/p&gt;
&lt;p&gt;(links point to the data source information web page)&lt;/p&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;Data product(s)&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;File format&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://lasp.colorado.edu/eve/data_access/eve_data/products/level1/esp/2020/"&gt;SDO EVE/ESP L1&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;FITS&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://lasp.colorado.edu/home/eve/data/"&gt;SDO EVE/ESP L0CS&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Text file&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://fermi.gsfc.nasa.gov/ssc/data/access/"&gt;FERMI GBM summary&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;FITS&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;GOES XRS&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;FITS, netCDF&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;PROBA-2 LYRA ligthcurve&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;FITS&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.swpc.noaa.gov/products/solar-cycle-progression"&gt;NOAA solar cycle monthly indices&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;JSON&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.swpc.noaa.gov/products/solar-cycle-progression"&gt;NOAA solar cycle predicted indices&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;JSON&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://solar.nro.nao.ac.jp/norh/archive.html"&gt;NoRH radio&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;FITS&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;RHESSI x-ray summary&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;FITS&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="evaluating-options"&gt;
&lt;h2&gt;Evaluating options&lt;/h2&gt;
&lt;p&gt;Having found possible options, in this section I’ve evaluated them against the criteria set out above.&lt;/p&gt;
&lt;section id="numpy-ndarray"&gt;
&lt;h3&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;numpy.ndarray&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Time-like index data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Can store datetime64 data, but no support for indexes&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Physical units&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Interop with scientific Python&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Out of memory&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;numpy arrays are always in memory&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Observer coordinates&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Easy data manipulation&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;I/O&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Can save to binary .npy format or text file&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="pandas-dataframe"&gt;
&lt;h3&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Time-like index data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Possible, but &lt;a class="reference external" href="https://pandas.pydata.org/docs/getting_started/install.html#computation"&gt;recommended to use xarray instead&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Physical units&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No native support (&lt;a class="reference external" href="https://github.com/pandas-dev/pandas/issues/10349"&gt;tracking issue&lt;/a&gt;), could be possible with &lt;a class="reference external" href="https://github.com/hgrecco/pint-pandas"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pint-pands&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Interop with scientific Python&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Out of memory&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;pandas DataFrames are always in memory&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Possible to &lt;a class="reference external" href="https://pandas.pydata.org/pandas-docs/stable/development/extending.html#define-original-properties"&gt;add additional properties&lt;/a&gt; to a DataFrame&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Observer coordinates&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Easy data manipulation&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Many built in methods for manipulating time-like data&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;I/O&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html"&gt;Lots of I/O options&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="xarray-dataarray"&gt;
&lt;h3&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Time-like index data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Physical units&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No native support (&lt;a class="reference external" href="https://github.com/pydata/xarray/issues/525"&gt;tracking issue&lt;/a&gt;), could be possible with &lt;a class="reference external" href="https://pint-xarray.readthedocs.io/en/stable/"&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pint-xarray&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Interop with scientific Python&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Out of memory&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Support for &lt;a class="reference external" href="https://docs.xarray.dev/en/stable/user-guide/dask.html"&gt;computing using &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;dask&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Possible to &lt;a class="reference external" href="https://docs.xarray.dev/en/stable/get-help/faq.html#what-is-your-approach-to-metadata"&gt;add metadata&lt;/a&gt; to a DataArray&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Observer coordinates&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Support for adding &lt;a class="reference external" href="https://docs.xarray.dev/en/stable/user-guide/data-structures.html#coordinates"&gt;“non-dimensional” coordinates&lt;/a&gt; (e.g. longitude/latitude), but not clear if storing astropy SkyCoord would work&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Easy data manipulation&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Many built in methods for manipulating time-like data&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;I/O&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;a class="reference external" href="https://docs.xarray.dev/en/stable/user-guide/io.html"&gt;Lots of I/O options&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="astropy-timeseries-timeseries"&gt;
&lt;h3&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.timeseries.TimeSeries&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Time-like index data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Physical units&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Interop with scientific Python&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Out of memory&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Apparently there is some support, but this is undocumented.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Can store on the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;.meta&lt;/span&gt;&lt;/code&gt; attribute&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Observer coordinates&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Easy data manipulation&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;I/O&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;I/O is done via &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.table.Table&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="ndcube"&gt;
&lt;h3&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NDCube&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Time-like index data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Physical units&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Interop with scientific Python&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Out of memory&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Seems to be supported in theory, but little docs&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Can store arbitrary FITS metadata&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Observer coordinates&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;No support for extra coordinates&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Easy data manipulation&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;Very few manipulation methods implemented&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;I/O&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="initial-recommendations"&gt;
&lt;h2&gt;Initial recommendations&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;numpy.ndarray&lt;/span&gt;&lt;/code&gt; doesn’t implement several key features, and these are almost certainly out of scope for future &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ndarray&lt;/span&gt;&lt;/code&gt; development, so I suggest &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ndarray&lt;/span&gt;&lt;/code&gt; is discounted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt; builds on top of &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt; with additional features that would be useful to us, I suggest &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pandas.DataFrame&lt;/span&gt;&lt;/code&gt; is discounted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NDCube&lt;/span&gt;&lt;/code&gt; is designed specifically to store data that is associated with a FITS world coordinate system (WCS). While some solar timeseries data is already in the FITS format, a large portion is in CDF format which is tabular, which FITS is not primarily designed to represent. So I suggest &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NDCube&lt;/span&gt;&lt;/code&gt; is discounted.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At a SunPy community meeting there was a consensus agreement that going forward we should consider &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.TimeSeries&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt; as the two options to consider.&lt;/p&gt;
&lt;p&gt;These two options have the following comparison:&lt;/p&gt;
&lt;div class="pst-scrollable-table-container"&gt;&lt;table class="table"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.TimeSeries&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Time-like index data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Different time scales&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Multi-dimensional data&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Physical units&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🛑&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Interop with scientific Python&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Out of memory&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Metadata&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Observer coordinates&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Easy data manipulation&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟠&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;I/O&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;🟩&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;My initial recommendation would be to adopt &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt;, as the two red items have a strong possibility of being solved with &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DataArray&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;It &lt;em&gt;should&lt;/em&gt; (I haven’t confirmed this) be possible to convert times in different time scales (including ones with leap seconds) to a single timescale that doesn’t have leap seconds, and store this in an &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray.DataArray&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Although there is not native support for units in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DataArray&lt;/span&gt;&lt;/code&gt; currently, there is interest and ongoing development to support them.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is unclear to me (because I did not have time to investigate) how hard it would be to implement support for storing rich coordinates (ie. &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.SkyCoord&lt;/span&gt;&lt;/code&gt;) in the extra_coords part of xarray data structures.&lt;/p&gt;
&lt;p&gt;In contrast I think implementing multi-dimensional data in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.TimeSeries&lt;/span&gt;&lt;/code&gt;, adding documentation for out of memory datasets, and implementing easy data manipulation methods would take significantly more effor than this.
Finally, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; has a much bigger development community than &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.TimeSeries&lt;/span&gt;&lt;/code&gt;, so implementing bug fixes and new features would probably be much easier with &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="putting-astropy-objects-in-xarray-structures"&gt;
&lt;h2&gt;Putting &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy&lt;/span&gt;&lt;/code&gt; objects in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; structures&lt;/h2&gt;
&lt;p&gt;For the final part of the small development grant, I investigated the changes needed to put &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy&lt;/span&gt;&lt;/code&gt; objects in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; structures.&lt;/p&gt;
&lt;p&gt;As a model for doing this, it is currently possible to store unitful data created with &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pint&lt;/span&gt;&lt;/code&gt; in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; structures.
Support for doing this has two components:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; &lt;a class="reference external" href="https://docs.xarray.dev/en/stable/internals/duck-arrays-integration.html"&gt;natively supports storing duck arrays&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray-pint&lt;/span&gt;&lt;/code&gt; provides a set of accessors that can be used to serialise and deserialise unitful data so that it can be saved to a file and loaded again.
It does this by converting the unit data into metadata, with strings representing units.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is not currently possible to store &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.Quantity&lt;/span&gt;&lt;/code&gt; objects in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; structures, as they inherit directly from &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ndarray&lt;/span&gt;&lt;/code&gt;, and get coerced from &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Quantity&lt;/span&gt;&lt;/code&gt; to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ndarray&lt;/span&gt;&lt;/code&gt; during the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xarray&lt;/span&gt;&lt;/code&gt; structure initialisation. I think fixing this is (at least initially) a one line change, changing (what was xarray/core/variable.py#L288 on commit hash 51554f2638bc9e4a527492136fe6f54584ffa75d) from&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Before moving forward with this it needs to be possible to run the full unit tests in xarray with &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;astropy.Quantity&lt;/span&gt;&lt;/code&gt;.
I started work on this in these two PRs:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/pydata/xarray/pull/7799"&gt;https://github.com/pydata/xarray/pull/7799&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/pydata/xarray/pull/7800"&gt;https://github.com/pydata/xarray/pull/7800&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://sunpy.org/posts/2023/2023-05-10-timeseries_sdg/"/>
    <summary>In late 2022 I got a small development grant from NumFocus to scope the future of time series data in sunpy.
The successful application can be read on the sunpy wiki.
The application contains context that I won’t repeat here.
This blog post is the key outcome of this grant, with a record of what I did, the recommendations I made, and any decisions we came to as a community.</summary>
    <published>2023-05-10T00:00:00+00:00</published>
  </entry>
</feed>
