{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Basic Principles\n", "\n", "Let's imagine you want to do something slightly more complicated. Maybe you want to make a movie, and include an linked time series plot next to it. Maybe you want to include several movie frames at different cadences. Maybe you want to create your own snazzy custom format. To do so, there are three core concepts you need to understand." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## a `Sequence` is a collection of data, with times\n", "\n", "To make an animation, we need a data structure that has some kind of *data* that has a *time* axis associated with it. For example, here we make a `Sequence` out of a small postage stamp of imaging data. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from playground.tv import *" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from playground.cartoons import create_test_stamp\n", "stamp = create_test_stamp(N=10, seed=42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `make_sequence` function is a general wrapper that does a decent job of figuring out what kind of sequence should be made out of the given inputs." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "seq = make_sequence(stamp)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`make_sequence` should be able to handle at least the following types of input:\n", " + single FITS filename, and an `ext_image=` keyword for the extension to use\n", " + list of FITS filenames, and an `ext_image=` keyword\n", " + a glob pattern to search for FITS files, and an `ext_image=` keyword \n", " + single FITS HDUList, and an `ext_image=` keyword \n", " + list of loaded FITS HDULists, and an `ext_image=` keyword \n", " + a Stamp object from the `cosmics` package" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each `sequence` has a `.time` attribute. It is an `astropy.time` object, and can be indexed as an array. If times are fake (for example, if they are simply image number or cadence number), then we pretend (artificially) that the times are `gps` format with a cadence of 1s. " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " \n", " has 10 times defined,\n", " spanning 2018-01-01 00:00:00.000 \n", " to 2018-01-01 00:00:18.000\n", " with a cadence of 2.0 s\n" ] } ], "source": [ "print(\"\"\"\n", "{} \n", " has {} times defined,\n", " spanning {} \n", " to {}\n", " with a cadence of {:.2}\"\"\".format(\n", " seq, len(seq.time), seq.time[0], seq.time[-1], seq.cadence().to('s')))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each sequence can be indexed directly with `[i]` to extract the `i`th element of the dataset. Different types of sequences will store data in different ways. For a small stamp, it will generally load the entire 3D (x,y,t) dataset into memory. For a sequence of large FITS images, it will generally only load individual FITS images on the fly as needed, to preserve memory. These different background behaviors should hopefully remain hidden to the casual user." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fi, ax = plt.subplots(1,3, figsize=(10,3))\n", "for i in range(3):\n", " ax[i].imshow(seq[i])\n", " ax[i].set_title(seq.time[i])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## a `Frame` is a plot panel, which can display a `Sequence`\n", "\n", "A frame is a container in which a sequence can be displayed. Different frames can display different views, even of the same dataset. For example, here we create two different frames that include our little sequence `seq` as their data." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ " | name=cecelia>" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "normal = imshowFrame(name='cecelia', \n", " data=seq)\n", "normal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below, we can create a different frame using the same data, but by including the `processingsteps` keyword, it will subtract the mean image from each individual image before displaying it." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ " | name=henrietta>" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subtracted = imshowFrame(name='henrietta', \n", " data=seq, \n", " title='(median subtracted)',\n", " processingsteps=['subtractmean'])\n", "subtracted" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will be able to visualize these frames once they are included in an illustration. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## an `Illustration` is a collection of `Frames`, with its own layout\n", "\n", "Once we have created our frames, we can include them in an illustration. The illustration handles not only the basic grid layout of the frames, but also synchronizing their frames when plotting an animation. When you call the illustration's `.plot` method, it will make all the constituent frames `plot` too. When you call the `.animate` method, it will make an animation by looping through a grid of times and updating each frame whenever it needs updating. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i = GenericIllustration(imshows=[normal, subtracted])\n", "i.plot()\n", "i.animate('_static/a-pair-of-frames.mp4')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looking back at the `normal` and `subtracted` frames that we defined, we can see a few features. The data and times for the two frames are identical, so the images update synchronously at each timestep of the animation. The `subtracted` frame looks like noise scattered around 0, as we would expect for having subtracted off the mean image. We gave `subtracted` a custom title, but `normal` fell back on an initial best guess.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want, you can access the individual frames inside an illustration through the `.frames` dictionary. This may come in handy if you want to modify the attributes of a frame once it's in an illustration, or change something in how it is plotted after calling `i.plot()`. (See examples below.)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " contains 2 frames: ['cecelia', 'henrietta'])\n" ] } ], "source": [ "print('{} contains {} frames: {})'.format(i, len(i.frames), list(i.frames.keys())))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default, all image frames will share the same color mapping. We can let each frame have its own color mapping by setting the illustration's `sharecolorbar=` keyword to `False`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i = GenericIllustration(imshows=[normal, subtracted], sharecolorbar=False)\n", "i.plot()\n", "i.animate('_static/a-pair-of-frames-with-different-colorbars.mp4')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you're trying to directly compare values across different frames, keep `sharecolorbar=True`. If you're looking for qualitative features and want to highlight the details unique to each frame, let each have its own colorbar. In this example, where the data were simulated to represent photon counts, we can see that the noise in the difference images is highest where the flux in the normal image is too." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## some example `Frame` combinations\n", "We can treat frames as somewhat modular containers, and build up illustrations through combinations of them. Here are a couple of examples of making custom illustrations by following the general process of \n", " 1. make some sequences\n", " 2. put them in frames\n", " 3. fill an illustration\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### simple `ZoomFrame` (recreating `illustratefits`)\n", "Let's start by recreating the zoom feature shown with `illustratefits` in the quickstart." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# first create a sequence\n", "big = make_sequence(create_test_stamp(N=10, xsize=80, ysize=100))\n", "\n", "# then define some frames\n", "image = imshowFrame(name='big-image', data=big, title='imshow')\n", "zoom = ZoomFrame(name='zoom', source=image, position=(25, 50), size=(20,10), title='zoom')\n", "\n", "# then populate an illustration with them\n", "i = GenericIllustration(imshows=[image, zoom])\n", "i.plot()\n", "#i.animate('_static/an-example-of-a-zoom.mp4', dpi=75)\n", "f = i.frames['big-image']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### multiple `ZoomFrames` on multiple images\n", "Now, let's build a bit on that by including both the original images and some median-subtracted ones. In addition to the extra frames, we're also including some more complicated options in generating the illustration layout." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# first create a sequence\n", "big = make_sequence(create_test_stamp(N=10, xsize=80, ysize=100))\n", "\n", "# then define some frames\n", "image = imshowFrame(name='big-image', data=big, title='imshow')\n", "zoom = ZoomFrame(name='zoom', source=image, position=(25, 50), size=(20,10), title='zoom')\n", "subtracted = imshowFrame(name='big-subtracted', data=big, title='subtracted', processingsteps=['subtractmedian'])\n", "subtractedzoom = ZoomFrame(name='zoom-subtracted', source=subtracted, position=(25, 50), size=(20,10), title='zoom')\n", "\n", "# then populate an illustration with them\n", "i = GenericIllustration(imshows=[image, zoom, subtracted, subtractedzoom], imshowrows=2, \n", " figsize=(7,6), hspace=0.2, wspace=0.02, \n", " left=0.05, right=0.95, bottom=0.05, top=0.9)\n", "i.plot()\n", "i.animate('_static/an-example-of-a-more-complicated-zoom.mp4', dpi=75)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### an `EmptyTimeseriesFrame` linked to an `imshowFrame`\n", "\n", "It might be nice to see a light curve synced up to the data from which it is derived. The `EmptyTimeseriesFrame` provides us with an empty frame, into which we can plot some time-series data. Here's a first step toward that capability; it still needs a bit of work, but hopefully this is enough to get started. The basic idea is to create an available plot location (an `Axes` object, in `matplotlib`-speak), where you can fill later with whatever plot elements you like. The below example demonstrates how to populate the time-series frame in two ways, both using its built-in `.plot` function and simply by adding elements to `i.frames['timeseries'].ax`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# make a dataset\n", "star = make_sequence(create_test_stamp(N=25, xsize=10, ysize=10, single=True))\n", "\n", "# create an empty time-series frame into which we will plot a timeseries\n", "lightcurve = EmptyTimeseriesFrame(name='timeseries')\n", "someimage = imshowFrame(name='image', data=star, title='', plotingredients=['image', 'arrows', 'colorbar'])\n", "\n", "# create an illustration that positions these frames next to each other\n", "i = SideBySideIllustration(timeseries=[lightcurve], imshows=[someimage])\n", "\n", "# plotting the illustration creates the basic structure...\n", "i.plot()\n", "\n", "# ...but we can still modify it through the individual frames\n", "f = i.frames['timeseries']\n", "\n", "# the time-series f.plot plot will subtract a the illustration's shared time offset\n", "time = star.time.jd\n", "flux = star._gather_3d().sum(-1).sum(-1)\n", "f.plot(time, flux, marker='o', color='black')\n", "\n", "# the f.ax refers to the time-series axes, so this is how we set up to plot into it\n", "plt.sca(f.ax)\n", "plt.axhline(np.mean(flux), color='cornflowerblue', zorder=-1)\n", "plt.ylabel('Some Flux')\n", "\n", "i.animate('_static/an-example-of-a-timeseries.mp4')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The interface for plotting timeseries is still a little buggy and may change soon. For now, hopefully you find this helpful! \n", "\n", "Some more examples are included, in one way or another, in the `tests/` directory of the `playground` repository. Check those out, or please feel free to contribute new examples here! As always, please do not hesitate to contact [Zach Berta-Thompson](zach.bertathompson@colorado.edu) or leave an issue on the [gitlab repository](http://tessgit.mit.edu/zkbt/playground)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.2" } }, "nbformat": 4, "nbformat_minor": 2 }