{ "cells": [ { "cell_type": "markdown", "id": "2de8612e", "metadata": {}, "source": [ "# Downloading and inspecting data from the KIS SDC" ] }, { "cell_type": "markdown", "id": "72bc3557", "metadata": {}, "source": [ "Programmatic access to the SDC data will be provided by a custom client for `Fido`, SunPy's search and download interface. This approach will allow the user to query and download data using SunPy, which will provide consistency with users' experiences working with other solar data in Python, and compatibility with the large and growing number of available scientific Python packages." ] }, { "cell_type": "markdown", "id": "6a561de5", "metadata": {}, "source": [ "## A brief introduction to SunPy" ] }, { "cell_type": "markdown", "id": "4c909d72", "metadata": {}, "source": [ "SunPy is an open-source, community-developed package which provides a wide range of general tools for research in solar physics. It is written in Python, which also allows easy integration with the large and growing ecosystem of scientific Python packages.\n", "\n", "The main features of SunPy are:\n", "- the `Map` object which provides a single, coordinate-aware interface for loading and plotting solar image data;\n", "- `TimeSeries`, a similar interface for time-series data;\n", "- solar physical constants;\n", "- use of Astropy's `units` submodule for physical quantities;\n", "- tools for parsing time strings and dealing with time ranges;\n", "- `Fido`, a unified search and download interface for obtaining solar data from a variety of different sources;\n", "- a `database` submodule for tracking locally downloaded files.\n", "\n", "A full tutorial on any of these topics would be beyond the scope of this document, but for a quick primer you can check out [this tutorial](https://github.com/aperiosoftware/stfc_sunpy_intro_2021) which was run by Aperio Software for an STFC summer school in Durham. It demonstrates some basic analysis using several of the tools listed above. An introduction to all of these features can be found on the [SunPy website](https://docs.sunpy.org/en/stable/guide/tour.html), and the [documentation](https://docs.sunpy.org/en/stable/) provides more detailed explanations and examples. Some of you may also be interested in the [SSWIDL/sunpy Cheat Sheet](https://docs.sunpy.org/en/stable/guide/ssw.html).\n", "\n", "For the purposes of this tutorial, the feature that will interest us most is `Fido`." ] }, { "cell_type": "markdown", "id": "df4f0c40", "metadata": {}, "source": [ "### Getting help or helping out\n", "\n", "SunPy is a community-driven project, and the developers are always willing to welcome new users and provide help where needed. The best place to start if you want help with anything in SunPy is the [SunPy matrix room](https://matrix.to/#/#sunpy:openastronomy.org).\n", "\n", "As well as being open-source, SunPy has a philosophy of being open development. This means that anyone can get involved, either by contributing to the package itself (adding features, fixing bugs, writing documentation, etc) or by supporting the project more broadly (giving the developers feedback, helping other users, and so on). Again, the best place to start with this is [matrix](https://matrix.to/#/#sunpy:openastronomy.org), and you can find repositories for the code base, documentation, website and more at [SunPy's GitHub page](https://github.com/sunpy)." ] }, { "cell_type": "markdown", "id": "41ee2518", "metadata": {}, "source": [ "## A brief introduction to Fido" ] }, { "cell_type": "markdown", "id": "76d7b729", "metadata": {}, "source": [ "`Fido` is SunPy's unified search and download interface. It allows users to query many different data sources at once using a system of attributes to specify the particular data the user is looking for. A query returns a table of results which can be inspected and sliced, such that the user can either download all of those results or a subset of them." ] }, { "cell_type": "markdown", "id": "71fce49e", "metadata": {}, "source": [ "The below is adapted from the [documentation on the SunPy website](https://docs.sunpy.org/en/stable/guide/acquiring_data/fido.html#fido-guide)." ] }, { "cell_type": "markdown", "id": "3dec202f", "metadata": {}, "source": [ "`Fido` and `attrs` can both be imported from `sunpy.net`." ] }, { "cell_type": "code", "execution_count": 1, "id": "2179db02", "metadata": {}, "outputs": [], "source": [ "from sunpy.net import Fido, attrs as a" ] }, { "cell_type": "markdown", "id": "44bb4a5c", "metadata": {}, "source": [ "Attributes are used to specify particular aspects of the data, such as instrument, time range or wavelength." ] }, { "cell_type": "code", "execution_count": 2, "id": "65c205bb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.Time('2012/03/04', '2012/03/06')" ] }, { "cell_type": "code", "execution_count": 3, "id": "50872d8c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.Instrument('aia')" ] }, { "cell_type": "markdown", "id": "1aa34322", "metadata": {}, "source": [ "To query data we pass one or more attributes to `Fido.search()`, which returns data that match those attributes. So to find level one AIA data in a particular two-day period we can do:" ] }, { "cell_type": "code", "execution_count": 4, "id": "fcc9573a", "metadata": {}, "outputs": [], "source": [ "result = Fido.search(a.Time('2012/3/4', '2012/3/6'), a.Instrument.aia, a.Level.one)" ] }, { "cell_type": "code", "execution_count": 5, "id": "99307ae6", "metadata": {}, "outputs": [ { "data": { "text/html": [ "Results from 1 Provider:

2647 Results from the VSOClient:
VSOQueryResponseTable length=2647\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Start TimeEnd TimeSourceInstrumentWavelength [2]ProviderPhysobsWavetypeExtent WidthExtent LengthExtent TypeSizeExtra FlagsInfo
AngstromMibyte
objectobjectstr3str3float64str4str9str6str4str4str8float64str1str106
2012-03-04 00:00:00.0002012-03-04 00:09:25.000SDOAIA171.0 .. 171.0JSOCintensityNARROW40964096FULLDISK3103.125SAIA level 1, 4096x4096 [48 records] [0 eclipse] [0 darks] [1.999 to 1.999 exposure] [100.00 avg. percentd]
2012-03-04 00:00:00.0002012-03-04 00:09:13.000SDOAIA211.0 .. 211.0JSOCintensityNARROW40964096FULLDISK3038.47656SAIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:00:02.0002012-03-04 00:09:15.000SDOAIA94.0 .. 94.0JSOCintensityNARROW40964096FULLDISK3038.47656SAIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:00:03.0002012-03-04 00:09:16.000SDOAIA335.0 .. 335.0JSOCintensityNARROW40964096FULLDISK3038.47656SAIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:00:07.0002012-03-04 00:09:20.000SDOAIA193.0 .. 193.0JSOCintensityNARROW40964096FULLDISK3038.47656SAIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.000 to 2.000 exposure] [100.00 avg. percentd]
2012-03-04 00:00:08.0002012-03-04 00:09:21.000SDOAIA304.0 .. 304.0JSOCintensityNARROW40964096FULLDISK3038.47656SAIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]
2012-03-04 00:00:08.0002012-03-04 00:00:09.000SDOAIA4500.0 .. 4500.0JSOCintensityNARROW40964096FULLDISK64.64844SAIA level 1, 4096x4096 [0.501 exposure] [100.00 percentd]
2012-03-04 00:00:09.0002012-03-04 00:09:22.000SDOAIA131.0 .. 131.0JSOCintensityNARROW40964096FULLDISK3038.47656SAIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:00:17.0002012-03-04 00:09:06.000SDOAIA1600.0 .. 1600.0JSOCintensityNARROW40964096FULLDISK1486.91406SAIA level 1, 4096x4096 [23 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:00:31.0002012-03-04 00:09:20.000SDOAIA1700.0 .. 1700.0JSOCintensityNARROW40964096FULLDISK1486.91406SAIA level 1, 4096x4096 [23 records] [0 eclipse] [0 darks] [1.000 to 1.000 exposure] [100.00 avg. percentd]
2012-03-04 00:09:24.0002012-03-04 00:19:13.000SDOAIA211.0 .. 211.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:09:26.0002012-03-04 00:19:15.000SDOAIA94.0 .. 94.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:09:27.0002012-03-04 00:19:16.000SDOAIA335.0 .. 335.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:09:29.0002012-03-04 00:19:06.000SDOAIA1600.0 .. 1600.0JSOCintensityNARROW40964096FULLDISK1616.21094SAIA level 1, 4096x4096 [25 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-04 00:09:31.0002012-03-04 00:19:20.000SDOAIA193.0 .. 193.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.000 to 2.000 exposure] [100.00 avg. percentd]
2012-03-04 00:09:32.0002012-03-04 00:19:21.000SDOAIA304.0 .. 304.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]
..........................................
2012-03-05 23:49:27.0002012-03-05 23:59:16.000SDOAIA335.0 .. 335.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:49:29.0002012-03-05 23:59:06.000SDOAIA1600.0 .. 1600.0JSOCintensityNARROW40964096FULLDISK1616.21094SAIA level 1, 4096x4096 [25 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:49:31.0002012-03-05 23:59:21.000SDOAIA193.0 .. 193.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [0.398 to 2.000 exposure] [100.00 avg. percentd]
2012-03-05 23:49:32.0002012-03-05 23:59:21.000SDOAIA304.0 .. 304.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]
2012-03-05 23:49:33.0002012-03-05 23:59:22.000SDOAIA131.0 .. 131.0JSOCintensityNARROW40964096FULLDISK3232.42188SAIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:49:36.0002012-03-05 23:59:13.000SDOAIA171.0 .. 171.0JSOCintensityNARROW40964096FULLDISK3167.77344SAIA level 1, 4096x4096 [49 records] [0 eclipse] [0 darks] [0.398 to 2.000 exposure] [100.00 avg. percentd]
2012-03-05 23:49:43.0002012-03-05 23:59:20.000SDOAIA1700.0 .. 1700.0JSOCintensityNARROW40964096FULLDISK1616.21094SAIA level 1, 4096x4096 [25 records] [0 eclipse] [0 darks] [1.000 to 1.001 exposure] [100.00 avg. percentd]
2012-03-05 23:59:24.0002012-03-06 00:00:01.000SDOAIA171.0 .. 171.0JSOCintensityNARROW40964096FULLDISK258.59375SAIA level 1, 4096x4096 [4 records] [0 eclipse] [0 darks] [1.713 to 1.999 exposure] [100.00 avg. percentd]
2012-03-05 23:59:24.0002012-03-06 00:00:01.000SDOAIA211.0 .. 211.0JSOCintensityNARROW40964096FULLDISK258.59375SAIA level 1, 4096x4096 [4 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:59:26.0002012-03-05 23:59:51.000SDOAIA94.0 .. 94.0JSOCintensityNARROW40964096FULLDISK193.94531SAIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:59:27.0002012-03-05 23:59:52.000SDOAIA335.0 .. 335.0JSOCintensityNARROW40964096FULLDISK193.94531SAIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:59:29.0002012-03-05 23:59:54.000SDOAIA1600.0 .. 1600.0JSOCintensityNARROW40964096FULLDISK129.29688SAIA level 1, 4096x4096 [2 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:59:31.0002012-03-05 23:59:56.000SDOAIA193.0 .. 193.0JSOCintensityNARROW40964096FULLDISK193.94531SAIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.000 to 2.000 exposure] [100.00 avg. percentd]
2012-03-05 23:59:32.0002012-03-05 23:59:57.000SDOAIA304.0 .. 304.0JSOCintensityNARROW40964096FULLDISK193.94531SAIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]
2012-03-05 23:59:33.0002012-03-05 23:59:58.000SDOAIA131.0 .. 131.0JSOCintensityNARROW40964096FULLDISK193.94531SAIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]
2012-03-05 23:59:43.0002012-03-05 23:59:44.000SDOAIA1700.0 .. 1700.0JSOCintensityNARROW40964096FULLDISK64.64844SAIA level 1, 4096x4096 [1.001 exposure] [100.00 percentd]

" ], "text/plain": [ "\n", "Results from 1 Provider:\n", "\n", "2647 Results from the VSOClient:\n", " Start Time End Time Source ... Extra Flags Info \n", " ... \n", "----------------------- ----------------------- ------ ... ----------- ----------------------------------------------------------------------------------------------------------\n", "2012-03-04 00:00:00.000 2012-03-04 00:09:25.000 SDO ... S AIA level 1, 4096x4096 [48 records] [0 eclipse] [0 darks] [1.999 to 1.999 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:00.000 2012-03-04 00:09:13.000 SDO ... S AIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:02.000 2012-03-04 00:09:15.000 SDO ... S AIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:03.000 2012-03-04 00:09:16.000 SDO ... S AIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:07.000 2012-03-04 00:09:20.000 SDO ... S AIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.000 to 2.000 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:08.000 2012-03-04 00:09:21.000 SDO ... S AIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:08.000 2012-03-04 00:00:09.000 SDO ... S AIA level 1, 4096x4096 [0.501 exposure] [100.00 percentd]\n", "2012-03-04 00:00:09.000 2012-03-04 00:09:22.000 SDO ... S AIA level 1, 4096x4096 [47 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:17.000 2012-03-04 00:09:06.000 SDO ... S AIA level 1, 4096x4096 [23 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:00:31.000 2012-03-04 00:09:20.000 SDO ... S AIA level 1, 4096x4096 [23 records] [0 eclipse] [0 darks] [1.000 to 1.000 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:09:24.000 2012-03-04 00:19:13.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:09:26.000 2012-03-04 00:19:15.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:09:27.000 2012-03-04 00:19:16.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:09:29.000 2012-03-04 00:19:06.000 SDO ... S AIA level 1, 4096x4096 [25 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:09:31.000 2012-03-04 00:19:20.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.000 to 2.000 exposure] [100.00 avg. percentd]\n", "2012-03-04 00:09:32.000 2012-03-04 00:19:21.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]\n", " ... ... ... ... ... ...\n", "2012-03-05 23:49:26.000 2012-03-05 23:59:15.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:27.000 2012-03-05 23:59:16.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:29.000 2012-03-05 23:59:06.000 SDO ... S AIA level 1, 4096x4096 [25 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:31.000 2012-03-05 23:59:21.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [0.398 to 2.000 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:32.000 2012-03-05 23:59:21.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:33.000 2012-03-05 23:59:22.000 SDO ... S AIA level 1, 4096x4096 [50 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:36.000 2012-03-05 23:59:13.000 SDO ... S AIA level 1, 4096x4096 [49 records] [0 eclipse] [0 darks] [0.398 to 2.000 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:49:43.000 2012-03-05 23:59:20.000 SDO ... S AIA level 1, 4096x4096 [25 records] [0 eclipse] [0 darks] [1.000 to 1.001 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:24.000 2012-03-06 00:00:01.000 SDO ... S AIA level 1, 4096x4096 [4 records] [0 eclipse] [0 darks] [1.713 to 1.999 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:24.000 2012-03-06 00:00:01.000 SDO ... S AIA level 1, 4096x4096 [4 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:26.000 2012-03-05 23:59:51.000 SDO ... S AIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:27.000 2012-03-05 23:59:52.000 SDO ... S AIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:29.000 2012-03-05 23:59:54.000 SDO ... S AIA level 1, 4096x4096 [2 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:31.000 2012-03-05 23:59:56.000 SDO ... S AIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.000 to 2.000 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:32.000 2012-03-05 23:59:57.000 SDO ... S AIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.902 to 2.902 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:33.000 2012-03-05 23:59:58.000 SDO ... S AIA level 1, 4096x4096 [3 records] [0 eclipse] [0 darks] [2.901 to 2.901 exposure] [100.00 avg. percentd]\n", "2012-03-05 23:59:43.000 2012-03-05 23:59:44.000 SDO ... S AIA level 1, 4096x4096 [1.001 exposure] [100.00 percentd]\n", "Length = 2647 rows\n" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result" ] }, { "cell_type": "markdown", "id": "77b479da", "metadata": {}, "source": [ "Searches can be made arbitrarily complex by including many different attributes, and also by using the `|` (OR) operator. So for example we can search for data from either of two different instruments:" ] }, { "cell_type": "code", "execution_count": 6, "id": "d4370288", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/scratch/anaconda3/envs/sdc-api/lib/python3.10/site-packages/astropy/table/table.py:3409: FutureWarning: elementwise == comparison failed and returning scalar instead; this will raise an error or perform elementwise comparison in the future.\n", " result = self.as_array() == other\n" ] } ], "source": [ "result = Fido.search(a.Time('2012/3/4', '2012/3/4 02:00'), a.Instrument.lyra | a.Instrument.rhessi)" ] }, { "cell_type": "code", "execution_count": 7, "id": "ce8fc72c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "Results from 3 Providers:

2 Results from the LYRAClient:
QueryResponse length=2\n", "\n", "\n", "\n", "\n", "\n", "
Start TimeEnd TimeInstrumentPhysobsSourceProviderLevel
objectobjectstr4str10str6str3int64
2012-03-04 00:00:00.0002012-03-04 23:59:59.999LYRAirradiancePROBA2ESA2
2012-03-04 00:00:00.0002012-03-04 23:59:59.999LYRAirradiancePROBA2ESA3

1 Results from the RHESSIClient:
QueryResponse length=1\n", "\n", "\n", "\n", "\n", "
Start TimeEnd TimeInstrumentPhysobsSourceProvider
objectobjectstr6str18str6str4
2012-03-04 00:00:00.0002012-03-04 23:59:59.999RHESSIsummary_lightcurveRHESSINASA

3 Results from the VSOClient:
VSOQueryResponseTable length=3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Start TimeEnd TimeSourceInstrumentWavelength [2]ProviderPhysobsExtent TypeSizeInfo
keVMibyte
objectobjectstr6str6float64str4str9str11float64str14
2012-03-03 22:57:40.0002012-03-04 00:33:20.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
2012-03-04 00:33:20.0002012-03-04 01:45:40.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
2012-03-04 01:45:40.0002012-03-04 02:09:00.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0

" ], "text/plain": [ "\n", "Results from 3 Providers:\n", "\n", "2 Results from the LYRAClient:\n", " Start Time End Time Instrument Physobs Source Provider Level\n", "----------------------- ----------------------- ---------- ---------- ------ -------- -----\n", "2012-03-04 00:00:00.000 2012-03-04 23:59:59.999 LYRA irradiance PROBA2 ESA 2\n", "2012-03-04 00:00:00.000 2012-03-04 23:59:59.999 LYRA irradiance PROBA2 ESA 3\n", "\n", "1 Results from the RHESSIClient:\n", " Start Time End Time Instrument Physobs Source Provider\n", "----------------------- ----------------------- ---------- ------------------ ------ --------\n", "2012-03-04 00:00:00.000 2012-03-04 23:59:59.999 RHESSI summary_lightcurve RHESSI NASA\n", "\n", "3 Results from the VSOClient:\n", " Start Time End Time Source Instrument Wavelength [2] Provider Physobs Extent Type Size Info \n", " keV Mibyte \n", "----------------------- ----------------------- ------ ---------- -------------- -------- --------- ----------- -------- --------------\n", "2012-03-03 22:57:40.000 2012-03-04 00:33:20.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0\n", "2012-03-04 00:33:20.000 2012-03-04 01:45:40.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0\n", "2012-03-04 01:45:40.000 2012-03-04 02:09:00.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0\n" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result" ] }, { "cell_type": "markdown", "id": "c2879af0", "metadata": {}, "source": [ "Notice here that this search has returned results from several different data providers. These can be indexed either numerically or with the name of the provider, and each one can be further indexed individually." ] }, { "cell_type": "code", "execution_count": 8, "id": "969408c7", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
VSOQueryResponseTable length=3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Start TimeEnd TimeSourceInstrumentWavelength [2]ProviderPhysobsExtent TypeSizeInfo
keVMibyte
objectobjectstr6str6float64str4str9str11float64str14
2012-03-03 22:57:40.0002012-03-04 00:33:20.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
2012-03-04 00:33:20.0002012-03-04 01:45:40.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
2012-03-04 01:45:40.0002012-03-04 02:09:00.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
" ], "text/plain": [ "\n", " Start Time End Time Source Instrument Wavelength [2] Provider Physobs Extent Type Size Info \n", " keV Mibyte \n", "----------------------- ----------------------- ------ ---------- -------------- -------- --------- ----------- -------- --------------\n", "2012-03-03 22:57:40.000 2012-03-04 00:33:20.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0\n", "2012-03-04 00:33:20.000 2012-03-04 01:45:40.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0\n", "2012-03-04 01:45:40.000 2012-03-04 02:09:00.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result[2]" ] }, { "cell_type": "code", "execution_count": 9, "id": "22243e9c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
VSOQueryResponseTable length=2\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Start TimeEnd TimeSourceInstrumentWavelength [2]ProviderPhysobsExtent TypeSizeInfo
keVMibyte
objectobjectstr6str6float64str4str9str11float64str14
2012-03-04 00:33:20.0002012-03-04 01:45:40.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
2012-03-04 01:45:40.0002012-03-04 02:09:00.000RHESSIRHESSI3.0 .. 17000.0LSSPintensityPARTIAL_SUN-0.00098RHESSI level-0
" ], "text/plain": [ "\n", " Start Time End Time Source Instrument Wavelength [2] Provider Physobs Extent Type Size Info \n", " keV Mibyte \n", "----------------------- ----------------------- ------ ---------- -------------- -------- --------- ----------- -------- --------------\n", "2012-03-04 00:33:20.000 2012-03-04 01:45:40.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0\n", "2012-03-04 01:45:40.000 2012-03-04 02:09:00.000 RHESSI RHESSI 3.0 .. 17000.0 LSSP intensity PARTIAL_SUN -0.00098 RHESSI level-0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result['vso'][1:] # or result[2, 1:]" ] }, { "cell_type": "markdown", "id": "cf2b71e8", "metadata": {}, "source": [ "Once we've selected which files we want, these can then be downloaded using `Fido.fetch()`, which takes as an argument a results table of the kind returned by `search()`." ] }, { "cell_type": "code", "execution_count": 10, "id": "660b7a14", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e61982869b764f6ebd631f44c307aa74", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Files Downloaded: 0%| | 0/6 [00:00/sunpy/data`) and returns a list of the names of the downloaded files. Here we've passed the whole search result to download all of the files, but we could also have sliced it as we did above, to download only certain files." ] }, { "cell_type": "markdown", "id": "ef8b9058", "metadata": {}, "source": [ "If you run the command above more than once, you will notice that it is much faster the second time. This is because internally `Fido` checks whether or not the files already exist. If they do, it skips the download and just returns the filename." ] }, { "cell_type": "code", "execution_count": 11, "id": "625a362b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "['/home/ajl/sunpy/data/lyra_20120304-000000_lev2_std.fits', '/home/ajl/sunpy/data/hsi_20120304_014540_003.fits', '/home/ajl/sunpy/data/lyra_20120304-000000_lev3_std.fits', '/home/ajl/sunpy/data/hsi_20120304_003320_003.fits', '/home/ajl/sunpy/data/hsi_obssumm_20120304_058.fits', '/home/ajl/sunpy/data/hsi_20120303_225740_001.fits']" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "files" ] }, { "cell_type": "markdown", "id": "c954de0f", "metadata": {}, "source": [ "## KIS Data interface" ] }, { "cell_type": "markdown", "id": "ebda782d", "metadata": {}, "source": [ "The custom client is required to provide access to the SDC servers. The client is automatically registered with Fido when it is imported, allowing the user to interact with the existing SunPy interfaces rather than directly with the custom client." ] }, { "cell_type": "code", "execution_count": 12, "id": "9473ffc3", "metadata": {}, "outputs": [], "source": [ "from sdc.client import KISClient" ] }, { "cell_type": "markdown", "id": "c188f347", "metadata": {}, "source": [ "Querying SDC data is then done in the same way as any other Fido query, as described above, e.g.:" ] }, { "cell_type": "code", "execution_count": 13, "id": "27d5dbb3", "metadata": {}, "outputs": [], "source": [ "result = Fido.search(a.Instrument(\"GRIS\"), a.Time(\"2014/04/26\", \"2014/04/27\"), a.Level(1))" ] }, { "cell_type": "markdown", "id": "4674bb90", "metadata": {}, "source": [ "**Note:** it is currently necessary to specify the processing level of the data you want - in this case level one. This is expected to change at a later date so that level one is the default, but it will still be possible to specify other levels." ] }, { "cell_type": "code", "execution_count": 14, "id": "094db511", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "Results from 1 Provider:

105 Results from the KISClient:
QueryResponseTable length=105\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
_idupload_date_utclinkstesttagsATMOS_R0_MAXATMOS_R0_MINBTYPECALIB_LEVELDATAPRODUCT_TYPEDATE_BEGDATE_ENDEM_RES_POWEREM_XELEXPTIMEFILTERHPLN_TAN_MAXHPLN_TAN_MINHPLT_TAN_MAXHPLT_TAN_MININSTRUMENTMUN_DIMENSIONSOBS_COLLECTIONOBS_MODEOBS_NAMEPOL_STATESPOL_XELSCAN_STEP_SIZES_RESOLUTIONS_XEL1S_XEL2TARGETTELESCOPETHETAT_RESOLUTIONT_XELWAVELENGTH_MAXWAVELENGTH_MINdata_type
cmcmsarcsecarcsecarcsecarcsecarcsecdegdegnmnm
objectobjectobjectstr16objectfloat64float64str10float64str4objectobjectint64int64float64str7float64float64float64float64str4float64int64str17str14str17str4int64float64float64int64int64str10str6float64float64int64float64float64str7
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e74f22a63bc6fb138d84'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e6e922a63bc6fb138d08'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e64922a63bc6fb138c6d'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31ed4822a63bc6fb139164'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31edc122a63bc6fb1391ff'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31edaa22a63bc6fb1391c1'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e06922a63bc6fb138621'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31ec8422a63bc6fb139107'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e25a22a63bc6fb138928'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31eca722a63bc6fb139126'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31eec822a63bc6fb13925c'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e12b22a63bc6fb1387d3'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e05722a63bc6fb1385e3'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e9a622a63bc6fb138f17'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e32322a63bc6fb138a20'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e80e22a63bc6fb138e1f'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
........................................................................................................................
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31ed9f22a63bc6fb1391a2'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e67522a63bc6fb138cab'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e17322a63bc6fb138830'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31eb8c22a63bc6fb13908b'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e6dc22a63bc6fb138ce9'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e7dd22a63bc6fb138e00'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e15b22a63bc6fb138811'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e37622a63bc6fb138a7d'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e5fc22a63bc6fb138c4e'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e2a622a63bc6fb138966'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e23a22a63bc6fb1388ea'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e9e922a63bc6fb138f55'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31ed7022a63bc6fb139183'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e35222a63bc6fb138a3f'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e54522a63bc6fb138bd2'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data
{'$oid': '5ee0feb97a92554c6de920ab'}{'$date': 1618566414615}{'$oid': '5d31e36522a63bc6fb138a5e'}$upload_date_utc{'embargo_until': {'$date': 1760629194829}}0.00.0phot.count1.0cube1398505619.01398506021.3392201101060.01.565um147.3343657851273787.4269799623221-279.95023082706894-329.36508718479445gris0.94005762140858464gris_observationssingle map polgris_20140426_000IQUV40.135-0.13655105471Sunspot(s)GREGOR19.938764575320242402.011568.04611564.0199l1_data

" ], "text/plain": [ "\n", "Results from 1 Provider:\n", "\n", "105 Results from the KISClient:\n", " _id upload_date_utc links test ... T_XEL WAVELENGTH_MAX WAVELENGTH_MIN data_type\n", " ... nm nm \n", "------------------------------------ ------------------------ ------------------------------------ ---------------- ... ----- -------------- -------------- ---------\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e74f22a63bc6fb138d84'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e6e922a63bc6fb138d08'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e64922a63bc6fb138c6d'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31ed4822a63bc6fb139164'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31edc122a63bc6fb1391ff'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31edaa22a63bc6fb1391c1'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e06922a63bc6fb138621'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31ec8422a63bc6fb139107'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e25a22a63bc6fb138928'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31eca722a63bc6fb139126'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31eec822a63bc6fb13925c'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e12b22a63bc6fb1387d3'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e05722a63bc6fb1385e3'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e9a622a63bc6fb138f17'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e32322a63bc6fb138a20'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e80e22a63bc6fb138e1f'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", " ... ... ... ... ... ... ... ... ...\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e4bd22a63bc6fb138b94'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31ed9f22a63bc6fb1391a2'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e67522a63bc6fb138cab'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e17322a63bc6fb138830'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31eb8c22a63bc6fb13908b'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e6dc22a63bc6fb138ce9'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e7dd22a63bc6fb138e00'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e15b22a63bc6fb138811'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e37622a63bc6fb138a7d'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e5fc22a63bc6fb138c4e'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e2a622a63bc6fb138966'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e23a22a63bc6fb1388ea'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e9e922a63bc6fb138f55'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31ed7022a63bc6fb139183'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e35222a63bc6fb138a3f'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e54522a63bc6fb138bd2'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "{'$oid': '5ee0feb97a92554c6de920ab'} {'$date': 1618566414615} {'$oid': '5d31e36522a63bc6fb138a5e'} $upload_date_utc ... 1 1568.0461 1564.0199 l1_data\n", "Length = 105 rows\n" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result" ] }, { "cell_type": "markdown", "id": "e1705703", "metadata": {}, "source": [ "As we saw earlier, we can download these files using `Fido.fetch()`. In this case, due to how the `KISClient` and the Data Centre are set up, it possible to download either the actual fits files containing the data, or json files containing the observation records. To download the data it is necessary to specify the keyword `binary=True`." ] }, { "cell_type": "code", "execution_count": 15, "id": "9f0b89b1", "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ea2dd84fef9b48e498e63491234134eb", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Files Downloaded: 0%| | 0/105 [00:00\n", "['/home/ajl/sunpy/data/gris_20140426_000/5d31e32322a63bc6fb138a20.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eded22a63bc6fb13921e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ebe522a63bc6fb1390aa.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e3d722a63bc6fb138ada.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e4b422a63bc6fb138b75.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e25a22a63bc6fb138928.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eb2822a63bc6fb13902e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e37622a63bc6fb138a7d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ec2622a63bc6fb1390c9.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eb1b22a63bc6fb13900f.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eca722a63bc6fb139126.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e43022a63bc6fb138b18.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ed9f22a63bc6fb1391a2.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eb1122a63bc6fb138ff0.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e06f22a63bc6fb13865f.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e05722a63bc6fb1385e3.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e75d22a63bc6fb138da3.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e67522a63bc6fb138cab.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ee2c22a63bc6fb13923d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eacd22a63bc6fb138fd1.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e9a622a63bc6fb138f17.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e2ae22a63bc6fb138985.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eb8c22a63bc6fb13908b.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e41622a63bc6fb138af9.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e45b22a63bc6fb138b37.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e0fa22a63bc6fb138795.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e09422a63bc6fb1386db.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e15b22a63bc6fb138811.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e07822a63bc6fb13867e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e64922a63bc6fb138c6d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eb7d22a63bc6fb13906c.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e80e22a63bc6fb138e1f.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e13b22a63bc6fb1387f2.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e6dc22a63bc6fb138ce9.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e87b22a63bc6fb138e5d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e92b22a63bc6fb138ed9.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e59d22a63bc6fb138c2f.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eb3b22a63bc6fb13904d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e23a22a63bc6fb1388ea.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e1bd22a63bc6fb13886e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e89222a63bc6fb138e7c.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e1fb22a63bc6fb1388ac.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e57922a63bc6fb138bf1.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e7dd22a63bc6fb138e00.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e24822a63bc6fb138909.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e20e22a63bc6fb1388cb.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ea8a22a63bc6fb138fb2.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e4f722a63bc6fb138bb3.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e9e922a63bc6fb138f55.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e39222a63bc6fb138a9c.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e12b22a63bc6fb1387d3.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e1c822a63bc6fb13888d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e74722a63bc6fb138d65.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e58f22a63bc6fb138c10.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e5fc22a63bc6fb138c4e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ea7222a63bc6fb138f93.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ed4822a63bc6fb139164.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e2c322a63bc6fb1389a4.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e28b22a63bc6fb138947.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e2d622a63bc6fb1389c3.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e2a622a63bc6fb138966.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e05222a63bc6fb1385c4.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31edc122a63bc6fb1391ff.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e9de22a63bc6fb138f36.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e0c022a63bc6fb138738.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e6c522a63bc6fb138cca.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e35222a63bc6fb138a3f.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e3a722a63bc6fb138abb.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e74f22a63bc6fb138d84.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e09922a63bc6fb1386fa.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e08622a63bc6fb13869d.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e05e22a63bc6fb138602.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ed7022a63bc6fb139183.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e7b522a63bc6fb138de1.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e6e922a63bc6fb138d08.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e6f122a63bc6fb138d27.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e46f22a63bc6fb138b56.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e10622a63bc6fb1387b4.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e73322a63bc6fb138d46.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ec8422a63bc6fb139107.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e17322a63bc6fb138830.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e0d022a63bc6fb138757.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e0e622a63bc6fb138776.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ed3422a63bc6fb139145.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31edaa22a63bc6fb1391c1.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e66322a63bc6fb138c8c.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e30b22a63bc6fb138a01.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e0b022a63bc6fb138719.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e54522a63bc6fb138bd2.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e08e22a63bc6fb1386bc.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31eec822a63bc6fb13925c.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e06b22a63bc6fb138640.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e2e122a63bc6fb1389e2.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e76a22a63bc6fb138dc2.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e36522a63bc6fb138a5e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e91022a63bc6fb138eba.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e06922a63bc6fb138621.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e85e22a63bc6fb138e3e.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e18422a63bc6fb13884f.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ea2522a63bc6fb138f74.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e8d322a63bc6fb138e9b.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31ec6c22a63bc6fb1390e8.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e4bd22a63bc6fb138b94.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31e97222a63bc6fb138ef8.fits', '/home/ajl/sunpy/data/gris_20140426_000/5d31edb822a63bc6fb1391e0.fits']" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "files" ] }, { "cell_type": "markdown", "id": "e886ca4e", "metadata": {}, "source": [ "## Interacting with the data" ] }, { "cell_type": "markdown", "id": "e2602112", "metadata": {}, "source": [ "These files can now be loaded and interacted with in a variety of ways. The most basic would be to use `astropy.io.fits` to open files individually. This would return a HDU (Header-Data Unit) for each file, containing the metadata and the data array. However, for a large number of files this quickly becomes cumbersome. We might also slice the data into 2D images and plot them using SunPy's `Map` object, but again this would be unsuitable for most purposes with such a large dataset." ] }, { "cell_type": "markdown", "id": "99beb340", "metadata": { "scrolled": false }, "source": [ "To quickly inspect this many files, we are instead going to use `ndcube` to load and plot all of the data at once. `ndcube` is a package which provides tools for handling n-dimensional data cubes in a way which is coordinate-aware. The details of `ndcube` are outside the scope of this demo, but as with SunPy, the interested reader can find [help](https://openastronomy.element.io/#/room/#ndcube:openastronomy.org) and [documentation](https://docs.sunpy.org/projects/ndcube/en/stable/index.html) online." ] }, { "cell_type": "markdown", "id": "3add4f4d", "metadata": { "scrolled": false }, "source": [ "First, since the files are not necessarily ordered how we want them, we will have to sort them. We will inspect the headers of the files and sort them by the `\"ISTEP\"` keyword, which provides the slit position ID, and we will store the headers in the corresponding order:" ] }, { "cell_type": "code", "execution_count": 17, "id": "70cf0e9c", "metadata": { "scrolled": true }, "outputs": [], "source": [ "from astropy.io import fits\n", "\n", "sortedfiles = sorted(files, key=lambda f: fits.getheader(f)[\"ISTEP\"])\n", "headers = [fits.getheader(f) for f in sortedfiles]" ] }, { "cell_type": "markdown", "id": "32c8bef8", "metadata": {}, "source": [ "Now, in order to construct the `ndcube` object we need the WCS (World Coordinate System) information from the file headers, which describes how the pixel grid of the images corresponds to physical coordinates." ] }, { "cell_type": "code", "execution_count": 18, "id": "3d6d7eec", "metadata": {}, "outputs": [], "source": [ "from astropy.wcs import WCS" ] }, { "cell_type": "code", "execution_count": 19, "id": "38f985ce", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "WARNING: FITSFixedWarning: 'datfix' made the change 'Set MJD-OBS to 56773.409236 from DATE-OBS.\n", "Set MJD-BEG to 56773.409236 from DATE-BEG'. [astropy.wcs.wcs]\n", "WARNING: FITSFixedWarning: 'obsfix' made the change 'Set OBSGEO-L to -16.510724 from OBSGEO-[XYZ].\n", "Set OBSGEO-B to 28.301797 from OBSGEO-[XYZ].\n", "Set OBSGEO-H to 2386.995 from OBSGEO-[XYZ]'. [astropy.wcs.wcs]\n" ] }, { "data": { "text/plain": [ "WCS Keywords\n", "\n", "Number of WCS axes: 4\n", "CTYPE : 'HPLN-TAN' 'HPLT-TAN' 'WAVE' 'STOKES' \n", "CRVAL : 0.02497888888888889 -0.08943277777777779 1.5640199000000002e-06 1.0 \n", "CRPIX : 0.0 0.0 0.0 0.0 \n", "PC1_1 PC1_2 PC1_3 PC1_4 : -0.594823 -0.803857 0.0 0.0 \n", "PC2_1 PC2_2 PC2_3 PC2_4 : 0.803857 -0.594823 0.0 0.0 \n", "PC3_1 PC3_2 PC3_3 PC3_4 : 0.0 0.0 1.0 0.0 \n", "PC4_1 PC4_2 PC4_3 PC4_4 : 0.0 0.0 0.0 1.0 \n", "CDELT : -3.793055555555556e-05 -3.793055555555556e-05 3.9903e-12 1.0 \n", "NAXIS : 1 471 1010 4" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "with fits.open(files[0]) as hdul:\n", " wcs0 = WCS(hdul[0]) # extract WCS info from PrimaryHDU of first fits file\n", "wcs0" ] }, { "cell_type": "markdown", "id": "6fd5ed52", "metadata": {}, "source": [ "So we can see from this that the data have two spatial dimensions, a wavelength axis and a Stokes axis." ] }, { "cell_type": "markdown", "id": "0edaaee5", "metadata": {}, "source": [ "In principle, in a set of files which constitute a single observation, the WCS headers should be constructed such that they all describe the same coordinate system - therefore the WCS keywords from any one of the files should enable us to construct a correct WCS object. That being the case, we will use only the WCS from the first file." ] }, { "cell_type": "code", "execution_count": 20, "id": "023e67fc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "WCS Keywords\n", "\n", "Number of WCS axes: 4\n", "CTYPE : 'HPLN-TAN' 'HPLT-TAN' 'WAVE' 'STOKES' \n", "CRVAL : 0.02497888888888889 -0.08943277777777779 1.5640199000000002e-06 1.0 \n", "CRPIX : 0.0 0.0 0.0 0.0 \n", "PC1_1 PC1_2 PC1_3 PC1_4 : -0.594823 -0.803857 0.0 0.0 \n", "PC2_1 PC2_2 PC2_3 PC2_4 : 0.803857 -0.594823 0.0 0.0 \n", "PC3_1 PC3_2 PC3_3 PC3_4 : 0.0 0.0 1.0 0.0 \n", "PC4_1 PC4_2 PC4_3 PC4_4 : 0.0 0.0 0.0 1.0 \n", "CDELT : -3.793055555555556e-05 -3.793055555555556e-05 3.9903e-12 1.0 \n", "NAXIS : 1 471 1010 4" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wcs0" ] }, { "cell_type": "markdown", "id": "86872d9b", "metadata": {}, "source": [ "_**Note for the Data Centre:** the above may not be strictly true because of the way the headers are currently recorded. In the observation used in this example, the CRVAL keyword (the reference value) changes from one file to the next, whereas CRPIX (the reference pixel) stays the same. This arrangement probably introduces a small inaccuracy when dealing with the WCS headers, because it means that the centre of the coordinate system moves during the observation. It would be more technically correct to keep the reference value constant across an observation, while changing the reference pixel - for most files this would mean the reference pixel being outside the grid of the image stored in the file._\n", "\n", "_The extent to which this is a problem may depend on how the instrument works, but it is something the Data Centre should consider._" ] }, { "cell_type": "markdown", "id": "2381b621", "metadata": {}, "source": [ "**Important workaround:** There is currently a bug in astropy which means that one of the WCS keywords is not processed properly for this data. This will be fixed in the future but for now it is necessary to use this workaround in order to avoid errors:" ] }, { "cell_type": "code", "execution_count": 21, "id": "1afbe770", "metadata": {}, "outputs": [], "source": [ "wcs0.wcs.specsys = 'TOPOCENT'" ] }, { "cell_type": "markdown", "id": "efbbb6f9", "metadata": {}, "source": [ "Next let's inspect a single file before we combine them. To do this we will load the data from the first file, and pass that and the WCS object to `ndcube`." ] }, { "cell_type": "code", "execution_count": 22, "id": "d2d7f473", "metadata": {}, "outputs": [], "source": [ "import ndcube" ] }, { "cell_type": "code", "execution_count": 23, "id": "bc951967", "metadata": {}, "outputs": [], "source": [ "data = fits.getdata(sortedfiles[0])\n", "ndc = ndcube.NDCube(data, wcs0)" ] }, { "cell_type": "code", "execution_count": 24, "id": "7ec8b264", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(4, 1010, 471, 1)" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data.shape" ] }, { "cell_type": "code", "execution_count": 25, "id": "dfefc62a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "NDCube\n", "------\n", "Dimensions: [4.00e+00 1.01e+03 4.71e+02 1.00e+00] pix\n", "Physical Types of Axes: [('phys.polarization.stokes',), ('em.wl',), ('custom:pos.helioprojective.lon', 'custom:pos.helioprojective.lat'), ('custom:pos.helioprojective.lon', 'custom:pos.helioprojective.lat')]\n", "Unit: None\n", "Data Type: >i4" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ndc" ] }, { "cell_type": "markdown", "id": "61c6f63a", "metadata": {}, "source": [ "Now we can use NDCube's built-in plotting capabilities to display the data. We are also going to use some jupyter notebook magic to do so interactively here in the notebook." ] }, { "cell_type": "code", "execution_count": 26, "id": "1497e36d", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "%matplotlib notebook" ] }, { "cell_type": "code", "execution_count": 27, "id": "d9bffa41", "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\n", "window.mpl = {};\n", "\n", "mpl.get_websocket_type = function () {\n", " if (typeof WebSocket !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof MozWebSocket !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert(\n", " 'Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.'\n", " );\n", " }\n", "};\n", "\n", "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = this.ws.binaryType !== undefined;\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById('mpl-warnings');\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent =\n", " 'This browser does not support binary websocket messages. ' +\n", " 'Performance may be slow.';\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message('supports_binary', { value: fig.supports_binary });\n", " fig.send_message('send_image_mode', {});\n", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\n", " fig.send_message('refresh', {});\n", " };\n", "\n", " this.imageObj.onload = function () {\n", " if (fig.image_mode === 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function () {\n", " fig.ws.close();\n", " };\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "};\n", "\n", "mpl.figure.prototype._init_header = function () {\n", " var titlebar = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", " if (this.ResizeObserver === undefined) {\n", " if (window.ResizeObserver !== undefined) {\n", " this.ResizeObserver = window.ResizeObserver;\n", " } else {\n", " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", " this.ResizeObserver = obs.ResizeObserver;\n", " }\n", " }\n", "\n", " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " this.resizeObserverInstance.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'dblclick',\n", " on_mouse_event_closure('dblclick')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\n", " return false;\n", " });\n", "\n", " function set_focus() {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "};\n", "\n", "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", "};\n", "\n", "mpl.figure.prototype.send_message = function (type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "};\n", "\n", "mpl.figure.prototype.send_draw_message = function () {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "};\n", "\n", "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", " y1 = Math.floor(y1) + 0.5;\n", " var min_x = Math.min(x0, x1);\n", " var min_y = Math.min(y0, y1);\n", " var width = Math.abs(x1 - x0);\n", " var height = Math.abs(y1 - y0);\n", "\n", " fig.rubberband_context.clearRect(\n", " 0,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "};\n", "\n", "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "};\n", "\n", "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch (cursor) {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "};\n", "\n", "mpl.figure.prototype.handle_message = function (fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "};\n", "\n", "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "};\n", "\n", "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "};\n", "\n", "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Called whenever the canvas gets updated.\n", " this.send_message('ack', {});\n", "};\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function (fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " var img = evt.data;\n", " if (img.type !== 'image/png') {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " img.type = 'image/png';\n", " }\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src\n", " );\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " img\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig['handle_' + msg_type];\n", " } catch (e) {\n", " console.log(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\n", " }\n", " }\n", " };\n", "};\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function (e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e) {\n", " e = window.event;\n", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", "\n", " return { x: x, y: y };\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys(original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object') {\n", " obj[key] = original[key];\n", " }\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function (event, name) {\n", " var canvas_pos = mpl.findpos(event);\n", "\n", " if (name === 'button_press') {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", " // Handle any extra behaviour associated with a key event\n", "};\n", "\n", "mpl.figure.prototype.key_event = function (event, name) {\n", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.key === this._key) {\n", " return;\n", " } else {\n", " this._key = event.key;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.key !== 'Control') {\n", " value += 'ctrl+';\n", " }\n", " else if (event.altKey && event.key !== 'Alt') {\n", " value += 'alt+';\n", " }\n", " else if (event.shiftKey && event.key !== 'Shift') {\n", " value += 'shift+';\n", " }\n", "\n", " value += 'k' + event.key;\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", " if (name === 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message('toolbar_button', { name: name });\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "\n", "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", "// prettier-ignore\n", "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";/* global mpl */\n", "\n", "var comm_websocket_adapter = function (comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.binaryType = comm.kernel.ws.binaryType;\n", " ws.readyState = comm.kernel.ws.readyState;\n", " function updateReadyState(_event) {\n", " if (comm.kernel.ws) {\n", " ws.readyState = comm.kernel.ws.readyState;\n", " } else {\n", " ws.readyState = 3; // Closed state.\n", " }\n", " }\n", " comm.kernel.ws.addEventListener('open', updateReadyState);\n", " comm.kernel.ws.addEventListener('close', updateReadyState);\n", " comm.kernel.ws.addEventListener('error', updateReadyState);\n", "\n", " ws.close = function () {\n", " comm.close();\n", " };\n", " ws.send = function (m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function (msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " var data = msg['content']['data'];\n", " if (data['blob'] !== undefined) {\n", " data = {\n", " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", " };\n", " }\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(data);\n", " });\n", " return ws;\n", "};\n", "\n", "mpl.mpl_figure_comm = function (comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.on(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\n", " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable();\n", " fig.parent_element.innerHTML =\n", " '';\n", " fig.close_ws(fig, msg);\n", "};\n", "\n", "mpl.figure.prototype.close_ws = function (fig, msg) {\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "};\n", "\n", "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message('ack', {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " if (event.target !== this) {\n", " // Ignore bubbled events from children.\n", " return;\n", " }\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('tabindex', 0);\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager) {\n", " manager = IPython.keyboard_manager;\n", " }\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\n", "};\n", "\n", "mpl.find_output_cell = function (html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i = 0; i < ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code') {\n", " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] === html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "};\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel !== null) {\n", " IPython.notebook.kernel.comm_manager.register_target(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ndc.plot()" ] }, { "cell_type": "markdown", "id": "913021a6", "metadata": {}, "source": [ "This is obviously not a very interesting plot, because the file only contains a single raster position. `NDCube` does have tools to slice the data differently, but we'll demonstrate this later with the full dataset." ] }, { "cell_type": "markdown", "id": "cfe951ab", "metadata": {}, "source": [ "To do this we will extract the data from the fits files and use `numpy`'s `concatenate()` function to stack the arrays in the desired order, contructing a single array." ] }, { "cell_type": "code", "execution_count": 28, "id": "c7a5cba0", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "data = np.concatenate([fits.getdata(f) for f in sortedfiles], axis=-1)" ] }, { "cell_type": "code", "execution_count": 29, "id": "38145878", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(4, 1010, 471, 105)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data.shape" ] }, { "cell_type": "markdown", "id": "9bcfffc5", "metadata": {}, "source": [ "Notice that now we have an array with the same axes, but we have stacked the raster scans from each of the 105 files on the appropriate axis, so that we have a complete cube of data." ] }, { "cell_type": "code", "execution_count": 30, "id": "721f57e0", "metadata": {}, "outputs": [], "source": [ "ndc = ndcube.NDCube(data, wcs0)" ] }, { "cell_type": "code", "execution_count": 31, "id": "6e169ae4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "NDCube\n", "------\n", "Dimensions: [ 4. 1010. 471. 105.] pix\n", "Physical Types of Axes: [('phys.polarization.stokes',), ('em.wl',), ('custom:pos.helioprojective.lon', 'custom:pos.helioprojective.lat'), ('custom:pos.helioprojective.lon', 'custom:pos.helioprojective.lat')]\n", "Unit: None\n", "Data Type: int32" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ndc" ] }, { "cell_type": "markdown", "id": "c6e4cae1", "metadata": {}, "source": [ "Now if we plot the data in the same way as before, we get a spatial slice through the cube at a given wavelength and Stokes position, which we can move through interactively or run as an animation." ] }, { "cell_type": "code", "execution_count": 32, "id": "afa493f0", "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\n", "window.mpl = {};\n", "\n", "mpl.get_websocket_type = function () {\n", " if (typeof WebSocket !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof MozWebSocket !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert(\n", " 'Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.'\n", " );\n", " }\n", "};\n", "\n", "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = this.ws.binaryType !== undefined;\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById('mpl-warnings');\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent =\n", " 'This browser does not support binary websocket messages. ' +\n", " 'Performance may be slow.';\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message('supports_binary', { value: fig.supports_binary });\n", " fig.send_message('send_image_mode', {});\n", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\n", " fig.send_message('refresh', {});\n", " };\n", "\n", " this.imageObj.onload = function () {\n", " if (fig.image_mode === 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function () {\n", " fig.ws.close();\n", " };\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "};\n", "\n", "mpl.figure.prototype._init_header = function () {\n", " var titlebar = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", " if (this.ResizeObserver === undefined) {\n", " if (window.ResizeObserver !== undefined) {\n", " this.ResizeObserver = window.ResizeObserver;\n", " } else {\n", " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", " this.ResizeObserver = obs.ResizeObserver;\n", " }\n", " }\n", "\n", " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " this.resizeObserverInstance.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'dblclick',\n", " on_mouse_event_closure('dblclick')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\n", " return false;\n", " });\n", "\n", " function set_focus() {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "};\n", "\n", "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", "};\n", "\n", "mpl.figure.prototype.send_message = function (type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "};\n", "\n", "mpl.figure.prototype.send_draw_message = function () {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "};\n", "\n", "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", " y1 = Math.floor(y1) + 0.5;\n", " var min_x = Math.min(x0, x1);\n", " var min_y = Math.min(y0, y1);\n", " var width = Math.abs(x1 - x0);\n", " var height = Math.abs(y1 - y0);\n", "\n", " fig.rubberband_context.clearRect(\n", " 0,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "};\n", "\n", "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "};\n", "\n", "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch (cursor) {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "};\n", "\n", "mpl.figure.prototype.handle_message = function (fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "};\n", "\n", "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "};\n", "\n", "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "};\n", "\n", "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Called whenever the canvas gets updated.\n", " this.send_message('ack', {});\n", "};\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function (fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " var img = evt.data;\n", " if (img.type !== 'image/png') {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " img.type = 'image/png';\n", " }\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src\n", " );\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " img\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig['handle_' + msg_type];\n", " } catch (e) {\n", " console.log(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\n", " }\n", " }\n", " };\n", "};\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function (e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e) {\n", " e = window.event;\n", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", "\n", " return { x: x, y: y };\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys(original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object') {\n", " obj[key] = original[key];\n", " }\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function (event, name) {\n", " var canvas_pos = mpl.findpos(event);\n", "\n", " if (name === 'button_press') {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", " // Handle any extra behaviour associated with a key event\n", "};\n", "\n", "mpl.figure.prototype.key_event = function (event, name) {\n", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.key === this._key) {\n", " return;\n", " } else {\n", " this._key = event.key;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.key !== 'Control') {\n", " value += 'ctrl+';\n", " }\n", " else if (event.altKey && event.key !== 'Alt') {\n", " value += 'alt+';\n", " }\n", " else if (event.shiftKey && event.key !== 'Shift') {\n", " value += 'shift+';\n", " }\n", "\n", " value += 'k' + event.key;\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", " if (name === 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message('toolbar_button', { name: name });\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "\n", "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", "// prettier-ignore\n", "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";/* global mpl */\n", "\n", "var comm_websocket_adapter = function (comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.binaryType = comm.kernel.ws.binaryType;\n", " ws.readyState = comm.kernel.ws.readyState;\n", " function updateReadyState(_event) {\n", " if (comm.kernel.ws) {\n", " ws.readyState = comm.kernel.ws.readyState;\n", " } else {\n", " ws.readyState = 3; // Closed state.\n", " }\n", " }\n", " comm.kernel.ws.addEventListener('open', updateReadyState);\n", " comm.kernel.ws.addEventListener('close', updateReadyState);\n", " comm.kernel.ws.addEventListener('error', updateReadyState);\n", "\n", " ws.close = function () {\n", " comm.close();\n", " };\n", " ws.send = function (m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function (msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " var data = msg['content']['data'];\n", " if (data['blob'] !== undefined) {\n", " data = {\n", " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", " };\n", " }\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(data);\n", " });\n", " return ws;\n", "};\n", "\n", "mpl.mpl_figure_comm = function (comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.on(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\n", " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable();\n", " fig.parent_element.innerHTML =\n", " '';\n", " fig.close_ws(fig, msg);\n", "};\n", "\n", "mpl.figure.prototype.close_ws = function (fig, msg) {\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "};\n", "\n", "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message('ack', {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " if (event.target !== this) {\n", " // Ignore bubbled events from children.\n", " return;\n", " }\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('tabindex', 0);\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager) {\n", " manager = IPython.keyboard_manager;\n", " }\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\n", "};\n", "\n", "mpl.find_output_cell = function (html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i = 0; i < ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code') {\n", " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] === html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "};\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel !== null) {\n", " IPython.notebook.kernel.comm_manager.register_target(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ndc.plot()" ] }, { "cell_type": "markdown", "id": "0948f7b1", "metadata": {}, "source": [ "By default `NDCube` uses the WCS to determine the spatial axes and plots those, and provides the sliders at the bottom of the plot for the remaining axes. If we want to look at the data differently though, for example to see one raster position across the whole wavelength range. To do this `NDCube.plot()` takes a `plot_axes` keyword which can be used to specify which dimensions are plotted and which are given sliders." ] }, { "cell_type": "code", "execution_count": 33, "id": "333e637c", "metadata": { "scrolled": false }, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\n", "window.mpl = {};\n", "\n", "mpl.get_websocket_type = function () {\n", " if (typeof WebSocket !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof MozWebSocket !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert(\n", " 'Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.'\n", " );\n", " }\n", "};\n", "\n", "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = this.ws.binaryType !== undefined;\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById('mpl-warnings');\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent =\n", " 'This browser does not support binary websocket messages. ' +\n", " 'Performance may be slow.';\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message('supports_binary', { value: fig.supports_binary });\n", " fig.send_message('send_image_mode', {});\n", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\n", " fig.send_message('refresh', {});\n", " };\n", "\n", " this.imageObj.onload = function () {\n", " if (fig.image_mode === 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function () {\n", " fig.ws.close();\n", " };\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "};\n", "\n", "mpl.figure.prototype._init_header = function () {\n", " var titlebar = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", " if (this.ResizeObserver === undefined) {\n", " if (window.ResizeObserver !== undefined) {\n", " this.ResizeObserver = window.ResizeObserver;\n", " } else {\n", " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", " this.ResizeObserver = obs.ResizeObserver;\n", " }\n", " }\n", "\n", " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " this.resizeObserverInstance.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'dblclick',\n", " on_mouse_event_closure('dblclick')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\n", " return false;\n", " });\n", "\n", " function set_focus() {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "};\n", "\n", "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", "};\n", "\n", "mpl.figure.prototype.send_message = function (type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "};\n", "\n", "mpl.figure.prototype.send_draw_message = function () {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "};\n", "\n", "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", " y1 = Math.floor(y1) + 0.5;\n", " var min_x = Math.min(x0, x1);\n", " var min_y = Math.min(y0, y1);\n", " var width = Math.abs(x1 - x0);\n", " var height = Math.abs(y1 - y0);\n", "\n", " fig.rubberband_context.clearRect(\n", " 0,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "};\n", "\n", "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "};\n", "\n", "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch (cursor) {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "};\n", "\n", "mpl.figure.prototype.handle_message = function (fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "};\n", "\n", "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "};\n", "\n", "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "};\n", "\n", "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Called whenever the canvas gets updated.\n", " this.send_message('ack', {});\n", "};\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function (fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " var img = evt.data;\n", " if (img.type !== 'image/png') {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " img.type = 'image/png';\n", " }\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src\n", " );\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " img\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig['handle_' + msg_type];\n", " } catch (e) {\n", " console.log(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\n", " }\n", " }\n", " };\n", "};\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function (e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e) {\n", " e = window.event;\n", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", "\n", " return { x: x, y: y };\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys(original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object') {\n", " obj[key] = original[key];\n", " }\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function (event, name) {\n", " var canvas_pos = mpl.findpos(event);\n", "\n", " if (name === 'button_press') {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", " // Handle any extra behaviour associated with a key event\n", "};\n", "\n", "mpl.figure.prototype.key_event = function (event, name) {\n", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.key === this._key) {\n", " return;\n", " } else {\n", " this._key = event.key;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.key !== 'Control') {\n", " value += 'ctrl+';\n", " }\n", " else if (event.altKey && event.key !== 'Alt') {\n", " value += 'alt+';\n", " }\n", " else if (event.shiftKey && event.key !== 'Shift') {\n", " value += 'shift+';\n", " }\n", "\n", " value += 'k' + event.key;\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", " if (name === 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message('toolbar_button', { name: name });\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "\n", "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", "// prettier-ignore\n", "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";/* global mpl */\n", "\n", "var comm_websocket_adapter = function (comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.binaryType = comm.kernel.ws.binaryType;\n", " ws.readyState = comm.kernel.ws.readyState;\n", " function updateReadyState(_event) {\n", " if (comm.kernel.ws) {\n", " ws.readyState = comm.kernel.ws.readyState;\n", " } else {\n", " ws.readyState = 3; // Closed state.\n", " }\n", " }\n", " comm.kernel.ws.addEventListener('open', updateReadyState);\n", " comm.kernel.ws.addEventListener('close', updateReadyState);\n", " comm.kernel.ws.addEventListener('error', updateReadyState);\n", "\n", " ws.close = function () {\n", " comm.close();\n", " };\n", " ws.send = function (m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function (msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " var data = msg['content']['data'];\n", " if (data['blob'] !== undefined) {\n", " data = {\n", " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", " };\n", " }\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(data);\n", " });\n", " return ws;\n", "};\n", "\n", "mpl.mpl_figure_comm = function (comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.on(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\n", " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable();\n", " fig.parent_element.innerHTML =\n", " '';\n", " fig.close_ws(fig, msg);\n", "};\n", "\n", "mpl.figure.prototype.close_ws = function (fig, msg) {\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "};\n", "\n", "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message('ack', {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " if (event.target !== this) {\n", " // Ignore bubbled events from children.\n", " return;\n", " }\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('tabindex', 0);\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager) {\n", " manager = IPython.keyboard_manager;\n", " }\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\n", "};\n", "\n", "mpl.find_output_cell = function (html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i = 0; i < ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code') {\n", " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] === html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "};\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel !== null) {\n", " IPython.notebook.kernel.comm_manager.register_target(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ndc.plot(plot_axes=[0, 'y', 'x', 0])" ] }, { "cell_type": "markdown", "id": "10a7b92c", "metadata": {}, "source": [ "This is a very brief overview of the plotting capabilities of `ndcube` for this kind of data. More detail can be found in the documentation, particularly [here](https://docs.sunpy.org/projects/ndcube/en/stable/visualization.html)." ] }, { "cell_type": "markdown", "id": "69530aea", "metadata": {}, "source": [ "## Open questions for users" ] }, { "cell_type": "markdown", "id": "897b49b0", "metadata": {}, "source": [ "- Does this workflow appeal to people and does it address their needs for aquiring and analysing data? Are there other tools or features that aren't demonstrated here that would be necessary for people's research?\n", "- Currently the Data Centre returns query results grouped by observations, which might contain many files. The custom `Fido` client expands these out to return one result per file, to allow any arbitrary set of files to be selected for download. Does this fit with how users want to obtain the data, or is it expected that people will only ever be downloading entire observations? Or would it be better to have the flexibility to do either?" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.0" } }, "nbformat": 4, "nbformat_minor": 5 }