Visualizing & Crossmatching your Light Curve

We have introduced two new classes into the eleanor package! This first is eleanor.Visualize(), which provides diagnostic tools for you to use to understand your light curves. The second is eleanor.Crossmatch(), which checks if your target was observed at 2-minute cadence, if the light curve is available from the TASOC pipeline, and if the light curve is available from Oelkers & Stassun (difference imaging).

We’ll run through an example for both of these classes.

Visualization Tutorial

We’ve created an eleanor.Visualization() class to help you understand what is going on with hyour light curves. If you have any additional tools you think would be useful in this class, please submit a pull request!

1.1 Setting up the class

Initializing the eleanor.visualization() class is very simple! Once you have the light curve you are interested in, created with the eleanor.TargetData() class, you pass this into the visualization class! We’ll run through an example with WASP-100.

[1]:
import eleanor
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.size'] = 15
WARNING: leap-second auto-update failed due to the following exception: RuntimeError('attempted to use clear_download_cache on the path //anaconda3/lib/python3.7/site-packages/astropy/utils/iers/data/Leap_Second.dat outside the data cache directory /Users/arcticfox/.astropy/cache/download/py3') [astropy.time.core]
[2]:
star = eleanor.Source(tic=38846515, sector=1, tc=True)
data = eleanor.TargetData(star)
Downloading URL https://mast.stsci.edu/tesscut/api/v0.1/astrocut?ra=68.95970833333332&dec=-64.02703611111112&y=31&x=31&units=px&sector=1 to ./tesscut_20200114091740.zip ... [Done]
Inflating...
This is the first light curve you have made for this sector. Getting eleanor metadata products for Sector  1...
This will only take a minute, and only needs to be done once. Any other light curves you make in this sector will be faster.
Target Acquired
Cadences Calculated
Quality Flags Assured
CBVs Made
Success! Sector  1 now available.
WARNING: The "exact" method is not yet implemented for rectangular apertures -- using "subpixel" method with "subpixels=32" [photutils.aperture.core]
[3]:
vis = eleanor.Visualize(data)

1.2 TESS the Movie

A great tool often used to understand what’s going on in your light curve is the FFI movies created by Ethan Kruse, hosted on YouTube. We make it very easy to view these videos. If you are calling the class from a Jupyter Notebook, the video will be embedded in the notebook. If you are calling the class from any other editor, the video will open up in a browser tab.

The sector movie for the target in the eleanor.TargetData() object will play by default.

[4]:
vis.tess_the_movie()
[4]:

1.3 Overplotting your aperture

We provide a very simple function that overplots the aperture you use on the target pixel file. You can also pass in your own aperture and change the color/linewidth of the plotted contour.

[5]:
vis.aperture_contour()
[5]:
../_images/getting_started_vis_crossmatch_15_0.png
../_images/getting_started_vis_crossmatch_15_1.png

Here’s an example of changing the default aperture contour color and linewidth and also passing in a new aperture to plot:

[11]:
ap = np.zeros(data.tpf[0].shape)
ap[5:8,6:9] = 1
fig = vis.aperture_contour(aperture=ap, ap_color='r', ap_linewidth=2)
../_images/getting_started_vis_crossmatch_17_0.png

1.4 Pixel-By-Pixel Light Curves

Another useful tool is what we call a pixel-by-pixel light curve. It’s exactly what it sounds like: we plot the light curve for a single pixel across the sector. The default light curve that is plotted is the “corrected flux” for each pixel. You can simply call:

[7]:
fig = vis.pixel_by_pixel()
//anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py:734: UserWarning: Warning: 'partition' will ignore the 'mask' of the MaskedArray.
  a.partition(kth, axis=axis, kind=kind, order=order)
../_images/getting_started_vis_crossmatch_20_1.png

Or you can specify which rows/columns you want to focus in on within the target pixel file:

[8]:
fig = vis.pixel_by_pixel(colrange=[4,10], rowrange=[4,10])
../_images/getting_started_vis_crossmatch_22_0.png

Or you can plot the raw flux light curve per each pixel (yay Earthshine!):

[9]:
fig = vis.pixel_by_pixel(colrange=[4,10], rowrange=[4,10], data_type="raw")
../_images/getting_started_vis_crossmatch_24_0.png

Or you can plot a Lomb Scargle periodogram for each pixel AND you can color each light curve by the color of the associated pixel in the TPF plotted to the left:

[14]:
fig = vis.pixel_by_pixel(colrange=[4,10], rowrange=[4,10], data_type="periodogram",
                        color_by_pixel=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-7061decec7c4> in <module>
      1 fig = vis.pixel_by_pixel(colrange=[4,10], rowrange=[4,10], data_type="periodogram",
----> 2                         color_by_pixel=True)

TypeError: pixel_by_pixel() got an unexpected keyword argument 'color_by_pixel'

OR OR! Oliver Hall made an awesome pull request that allows you to plot the periodogram per each pixel for all of your asteroseismic needs:

[15]:
vis.pixel_by_pixel(colrange=[4,10], rowrange=[4,10], data_type="amplitude")
[15]:
../_images/getting_started_vis_crossmatch_28_0.png
../_images/getting_started_vis_crossmatch_28_1.png

Crossmatching

On to new things! It’s important to check all of the light curves that are available for your target to make sure your astrophysical signal is indeed real. We’ve made this really easy for you to do by introducting a new eleanor.Crossmatch() class. Within this class, you can check if your target has been observed at either 2-minute cadence or is created by the TASOC or Oelkers & Stassun (2019) pipelines.

The eleanor.Crossmatch() class is initialized using an eleanor.TargetData() object.

[ ]:
cross = eleanor.Crossmatch(data)

The 2-minute function returns a list of lightkurve.search.SearchResult objects if your target has been observed in this mode. Users also have the option to set download=True, which then returns a list of lightkurve.lightcurve.TessLightCurve objects. You also have the option to specify which sectors you want to search/download!

[ ]:
cross.two_minute()
[ ]:
lcs = cross.two_minute(download=True)

TASOC pipeline

The TESS Asteroseismic Consortium (TASC) is providing light curves for the community to use that are tailored towards finding asteroseismic signals. Callingn eleanor.Crossmatch.tasoc_lc() searches MAST to find if these light curves are available. For more information on the TASOC light curves, see https://archive.stsci.edu/hlsp/tasoc.

[ ]:
cross.tasoc_lc()

The TASOC light curves have their own quality flags called eleanor.Crossmatch.tasoc_pixel_quality. We can apply these quality flags to the light curve and see that the WASP-100b transits are recovered really nicely!

[ ]:
plt.figure(figsize=(14,8))

q = cross.tasoc_pixel_quality == 0
plt.plot(cross.tasoc_time[q], cross.tasoc_flux_raw[q], 'k')
plt.xlabel('Time [BJD-2457000]')
plt.ylabel('Flux');

Oelkers & Stassun pipeline

Additionally, the Vanderbilt team is providing light curves for stars in the FFIs via difference imaging.

[ ]:
cross.oelkers_lc()
[ ]:
plt.figure(figsize=(14,8))
plt.plot(cross.os_time, cross.os_mag, 'k')
plt.xlabel('Time [BJD-2457000]')
plt.ylabel('Magnitude');

We can now plot all light curves on the same plot and compare. All of the transits pop out really nicely! This (and the fact that WASP-100 has already been confirmed) is very reassuring that our transits are indeed real.

[ ]:
plt.figure(figsize=(14,8))

e = data.quality == 0
plt.plot(data.time[e], data.corr_flux[e]/np.nanmedian(data.corr_flux[e]),
         'k', label='eleanor')

plt.plot(cross.os_time,
         10**(-0.4*cross.os_mag)/np.nanmedian(10**(-0.4*cross.os_mag))-0.05,
         'r', label='OS19')

plt.plot(cross.tasoc_time[q],
         cross.tasoc_flux_raw[q]/np.nanmedian(cross.tasoc_time[q])-8.9,
         'b', label='TASOC')

plt.legend(ncol=3)

plt.xlabel('Time [BJD-2457000]')
plt.ylabel('Flux');