Binder badge

Plotting Target Pixel Files with Lightkurve

Learning Goals

By the end of this tutorial, you will:

  • Learn how to download and plot target pixel files from the data archive using Lightkurve.

  • Be able to plot the target pixel file background.

  • Be able to extract and plot flux from a target pixel file.

Introduction

The Kepler, K2, and TESS telescopes observe stars for long periods of time, from just under a month to four years. By doing so they observe how the brightnesses of stars change over time.

Pixels around targeted stars are cut out and stored as target pixel files at each observing cadence. In this tutorial, we will learn how to use Lightkurve to download and understand the different photometric data stored in a target pixel file, and how to extract flux using basic aperture photometry.

It is useful to read the accompanying tutorial discussing how to use target pixel file products with Lightkurve before starting this tutorial. It is recommended that you also read the tutorial on using Kepler light curve products with Lightkurve, which will introduce you to some specifics on how Kepler, K2, and TESS make observations, and how these are displayed as light curves. It also introduces some important terms and concepts that are referred to in this tutorial.

Kepler observed a single field in the sky, although not all stars in this field were recorded. Instead, pixels were selected around certain targeted stars. These cutout images are called target pixel files, or TPFs. By combining the amount of flux in the pixels where the star appears, you can make a measurement of the amount of light from a star in that observation. The pixels chosen to include in this measurement are referred to as an aperture.

TPFs are typically the first port of call when studying a star with Kepler, K2, or TESS. They allow us to see where our data is coming from, and identify potential sources of noise or systematic trends. In this tutorial, we will use the Kepler mission as the main example, but these tools equally apply to TESS and K2 as well.

Imports

This tutorial requires: - Lightkurve to work with TPF files. - Matplotlib for plotting.

[1]:
import lightkurve as lk
import matplotlib.pyplot as plt
%matplotlib inline

1. Downloading a TPF

A TPF contains the original imaging data from which a light curve is derived. Besides the brightness data measured by the charge-coupled device (CCD) camera, a TPF also includes post-processing information such as an estimate of the astronomical background, and a recommended pixel aperture for extracting a light curve.

First, we download a target pixel file. We will use one quarter’s worth of Kepler data for the star named Kepler-8, a star somewhat larger than the Sun, and the host of a hot Jupiter planet. To search for TPF’s that contain our object of interest we will use the search_targetpixelfile function as follows,

[2]:
search_result = lk.search_targetpixelfile("Kepler-8", author="Kepler", quarter=4, cadence="long")
search_result
[2]:
SearchResult containing 1 data products.
#missionyearauthorexptimetarget_namedistance
sarcsec
0Kepler Quarter 042010Kepler1800kplr0069222440.0
[3]:
tpf = search_result.download()

This TPF contains data for every cadence in the quarter we downloaded. Let’s focus on the first cadence for now, which we can select using zero-based indexing as follows:

[4]:
first_cadence = tpf[0]
first_cadence
[4]:
KeplerTargetPixelFile Object (ID: 6922244)

2. Flux and Background

At each cadence the TPF has a number of photometry data properties. These are:

  • flux_bkg: the astronomical background of the image.

  • flux_bkg_err: the statistical uncertainty on the background flux.

  • flux: the stellar flux after the background is removed.

  • flux_err: the statistical uncertainty on the stellar flux after background removal.

These properties can be accessed via a TPF object as follows:

[5]:
first_cadence.flux.value
[5]:
array([[[          nan, 5.6079335e+00, 5.1491142e+01, 8.4241745e+01,
         3.0221334e+01],
        [4.4045620e+01, 7.6861229e+01, 1.1227759e+03, 3.2262029e+03,
         4.5486777e+02],
        [2.5911165e+01, 2.2907593e+02, 9.3626543e+03, 2.3606273e+04,
         1.2087750e+03],
        [4.0100830e+01, 8.8543927e+02, 1.7102118e+03, 2.6254871e+03,
         7.0796606e+02],
        [1.5719417e+02, 8.3713440e+02, 5.1021539e+02, 1.1501041e+03,
         1.8313370e+02]]], dtype=float32)

And you can plot the data as follows:

[6]:
first_cadence.plot(column='flux');
[6]:
<AxesSubplot:title={'center':'Target ID: 6922244, Cadence: 11914'}, xlabel='Pixel Column Number', ylabel='Pixel Row Number'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_16_1.png

Alternatively, if you are working directly with a FITS file, you can access the data in extension 1 (for example, first_cadence.hdu[1].data['FLUX']). Note that you can find all of the details on the structure and contents of TPF files in Section 2.3.2 of the Kepler Archive Manual.

When plotting data using the plot() function, what you are seeing in the TPF is the flux after the background has been removed. This background flux typically consists of zodiacal light or earthshine (especially in TESS observations). The background is typically smooth and changes on scales much larger than a single TPF. In Kepler, the background is estimated for the CCD as a whole, before being extracted from each TPF in that CCD. You can learn more about background removal in Section 4.2 of the Kepler Data Processing Handbook.

Now, let’s compare the background to the background-subtracted flux to get a sense of scale. We can do this using the plot() function’s column keyword. By default the function plots the flux, but we can change this to plot the background, as well as other data such as the error on each pixel’s flux.

[7]:
fig, axes = plt.subplots(2,2, figsize=(16,16))
first_cadence.plot(ax=axes[0,0], column='FLUX')
first_cadence.plot(ax=axes[0,1], column='FLUX_BKG')
first_cadence.plot(ax=axes[1,0], column='FLUX_ERR')
first_cadence.plot(ax=axes[1,1], column='FLUX_BKG_ERR');
[7]:
<AxesSubplot:title={'center':'Target ID: 6922244, Cadence: 11914'}, xlabel='Pixel Column Number', ylabel='Pixel Row Number'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_20_1.png

From looking at the color scale on both plots, you may see that the background flux is very low compared to the total flux emitted by a star. This is expected — stars are bright! But these small background corrections become important when looking at the very small scale changes caused by planets or stellar oscillations. Understanding the background is an important part of astronomy with Kepler, K2, and TESS.

If the background is particularly bright and you want to see what the TPF looks like with it included, passing the bkg=True argument to the plot() method will show the TPF with the flux added on top of the background, representing the total flux recorded by the spacecraft.

[8]:
first_cadence.plot(bkg=True);
[8]:
<AxesSubplot:title={'center':'Target ID: 6922244, Cadence: 11914'}, xlabel='Pixel Column Number', ylabel='Pixel Row Number'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_23_1.png

In this case, the background is low and the star is bright, so it doesn’t appear to make much of a difference.

3. Apertures

As part of the data processing done by the Kepler pipeline, each TPF includes a recommended optimal aperture mask. This aperture mask is optimized to ensure that the stellar signal has a high signal-to-noise ratio, with minimal contamination from the background.

The optimal aperture is stored in the TPF as the pipeline_mask property. We can have a look at it by calling it here:

[9]:
first_cadence.pipeline_mask
[9]:
array([[False, False, False, False, False],
       [False, False,  True,  True, False],
       [False, False,  True,  True, False],
       [False,  True,  True,  True, False],
       [False, False, False,  True, False]])

As you can see, it is a Boolean array detailing which pixels are included. We can plot this aperture over the top of our TPF using the plot() function, and passing in the mask to the aperture_mask keyword. This will highlight the pixels included in the aperture mask using red hatched lines.

[10]:
first_cadence.plot(aperture_mask=first_cadence.pipeline_mask);
[10]:
<AxesSubplot:title={'center':'Target ID: 6922244, Cadence: 11914'}, xlabel='Pixel Column Number', ylabel='Pixel Row Number'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_30_1.png

You don’t necessarily have to pass in the pipeline_mask to the plot() function; it can be any mask you create yourself, provided it is the right shape. An accompanying tutorial explains how to create such custom apertures, and goes into aperture photometry in more detail. For specifics on the selection of Kepler’s optimal apertures, read the Kepler Data Processing Handbook, Section 7, Finding Optimal Apertures in Kepler Data.

4. Simple Aperture Photometry

Finally, let’s learn how to perform simple aperture photometry (SAP) using the provided optimal aperture in pipeline_mask and the TPF.

Using the full TPF for all cadences in the quarter, we can perform aperture photometry using the to_lightcurve() method as follows:

[11]:
lc = tpf.to_lightcurve()

This method returns a LightCurve object which details the flux and flux centroid position at each cadence:

[12]:
lc
[12]:
KeplerLightCurve targetid=6922244 length=4116
timefluxflux_errcentroid_colcentroid_rowcadencenoquality
electron / selectron / spixpix
objectfloat32float32float64float64int32int32
352.3763248503528343689.14843756.631562232971191683.1803253801079190.5726135863067119140
352.396758048489643698.0781256.631830215454102683.1799393446446190.57243877622443119158192
352.437624445570743694.105468756.6317877769470215683.1796254892746190.572675734784721191716
352.4580576446387643698.316406256.631948947906494683.1797879898063190.572495708295119180
352.478490843932443687.64843756.631504535675049683.1792868369076190.5724646436399119190
352.498924043466143686.47656256.6314263343811035683.1797248407688190.57284004406665119200
352.519357243349143692.593756.631662845611572683.1797061300535190.57275259977848119210
352.5397903434568443712.019531256.6356940269470215683.1787298941248190.573168239462511922128
352.5602236438062443683.980468756.631390571594238683.1793654382498190.57307253477993119230
.....................
442.0195948041364343153.082031256.599308490753174683.002712235495190.7815066390984163010
442.040029269446743162.85156256.5997772216796875683.0029172184355190.7811747235669163020
442.060463534879143167.781256.600048065185547683.0028434958307190.78150710808106163030
442.080897900421443156.332031256.599843978881836683.0027064285711190.7813695342756516304128
442.101332366146443164.07031256.599811553955078683.0025882793675190.7811069549184163050
442.121766731957943160.66406256.599737167358398683.0028467866362190.78114511476244163068192
442.142200997914243157.6256.5994954109191895683.0026386252844190.78167294557255163070
442.1626354639811343155.800781256.599367618560791683.002560918617190.7812353959604163080
442.183069830200143148.464843756.599063873291016683.0023621573163190.78154300322052163090
442.2035040965274743151.56256.599262714385986683.0024686391082190.7814194325506163100

Note that this KeplerLightCurve object has fewer data columns than in light curves downloaded directly from MAST. This is because we are extracting our light curve directly from the TPF using minimal processing, whereas light curves created using the official pipeline include more processing and more columns.

We can visualize the light curve as follows:

[13]:
lc.plot();
[13]:
<AxesSubplot:xlabel='Time - 2454833 [BKJD days]', ylabel='Flux [$\\mathrm{e^{-}\\,s^{-1}}$]'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_39_1.png

This light curve is similar to the SAP light curve we previously encountered in the light curve tutorial.

Note

The background flux can be plotted in a similar way, using the get_bkg_lightcurve() method. This does not require an aperture, but instead sums the flux in the TPF’s FLUX_BKG column at each timestamp.

[14]:
bkg = tpf.get_bkg_lightcurve()
bkg.plot();
[14]:
<AxesSubplot:xlabel='Time - 2454833 [BKJD days]', ylabel='Flux [$\\mathrm{e^{-}\\,s^{-1}}$]'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_42_1.png

Inspecting the background in this way is useful to identify signals which appear to be present in the background rather than in the astronomical object under study.


Exercises

Some stars, such as the planet-hosting star Kepler-10, have been observed both with Kepler and TESS. In this exercise, download and plot both the TESS and Kepler TPFs, along with the optimal apertures. You can do this by either selecting the TPFs from the list returned by search_targetpixelfile(), or by using the mission keyword argument when searching.

Both Kepler and TESS produce target pixel file data products, but these can look different across the two missions. TESS is focused on brighter stars and has larger pixels, so a star that might occupy many pixels in Kepler may only occupy a few in TESS.

How do light curves extracted from both of them compare?

[15]:
#datalist = lk.search_targetpixelfile(...)

[16]:
#soln:
datalist = lk.search_targetpixelfile("Kepler-10")
datalist
[16]:
SearchResult containing 53 data products.
#missionyearauthorexptimetarget_namedistance
sarcsec
0Kepler Quarter 002009Kepler1800kplr0119041510.0
1Kepler Quarter 012009Kepler1800kplr0119041510.0
2Kepler Quarter 022009Kepler60kplr0119041510.0
3Kepler Quarter 022009Kepler1800kplr0119041510.0
4Kepler Quarter 032009Kepler60kplr0119041510.0
5Kepler Quarter 032009Kepler60kplr0119041510.0
6Kepler Quarter 032009Kepler60kplr0119041510.0
7Kepler Quarter 032009Kepler1800kplr0119041510.0
8Kepler Quarter 042010Kepler60kplr0119041510.0
9Kepler Quarter 042010Kepler1800kplr0119041510.0
.....................
43Kepler Quarter 152012Kepler60kplr0119041510.0
44Kepler Quarter 152013Kepler60kplr0119041510.0
45Kepler Quarter 152013Kepler1800kplr0119041510.0
46Kepler Quarter 172013Kepler60kplr0119041510.0
47Kepler Quarter 172013Kepler60kplr0119041510.0
48Kepler Quarter 172013Kepler1800kplr0119041510.0
49TESS Sector 142019SPOC1203777807900.0
50TESS Sector 142019TESS-SPOC18003777807900.0
51TESS Sector 152019TESS-SPOC18003777807900.0
52TESS Sector 262020TESS-SPOC18003777807900.0
Length = 53 rows
[17]:
kep = datalist[6].download()
tes = datalist[15].download()
[18]:
fig, axes = plt.subplots(1, 2, figsize=(14,6))
kep.plot(ax=axes[0], aperture_mask=kep.pipeline_mask, scale='log')
tes.plot(ax=axes[1], aperture_mask=tes.pipeline_mask)
fig.tight_layout();
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_50_0.png
[19]:
lc_kep = kep.to_lightcurve()
lc_tes = tes.to_lightcurve()
[20]:
fig, axes = plt.subplots(1, 2, figsize=(14,6), sharey=True)
lc_kep.flatten().plot(ax=axes[0], c='k', alpha=.8)
lc_tes.flatten().plot(ax=axes[1], c='k', alpha=.8);
[20]:
<AxesSubplot:xlabel='Time - 2454833 [BKJD days]', ylabel='Flux [$\\mathrm{e^{-}\\,s^{-1}}$]'>
../../_images/tutorials_1-getting-started_plotting-target-pixel-files_52_1.png

If you plot the light curves for both missions side by side, you will see a stark difference. The Kepler data has a much smaller scatter, and repeating transits are visible. This is because Kepler’s pixels were smaller, and so could achieve a higher precision on fainter stars. TESS has larger pixels and therefore focuses on brighter stars. For stars like Kepler-10, it would be hard to detect a planet using TESS data alone.

About this Notebook

Authors: Oliver Hall (oliver.hall@esa.int), Geert Barentsen

Updated On: 2020-09-15

Citing Lightkurve and Astropy

If you use lightkurve or astropy for published research, please cite the authors. Click the buttons below to copy BibTeX entries to your clipboard.

lk.show_citation_instructions()

Space Telescope Logo