306.1. Transient light curves¶
306.1. Transient light curves¶
Data Release: Data Preview 1
Container Size: large
LSST Science Pipelines version: Release r29.1.1
Last verified to run: 2025-06-20
Repository: github.com/lsst/tutorial-notebooks
Learning objective: An overview of plotting extragalactic transient light curves in DP1.
LSST data products: ForcedSourceOnDiaObject
, Visit
Packages: matplotlib
, numpy
, lsst.rsp
, lsst.utils.plotting
Credit: Originally developed by the Rubin Community Science team with feedback from Eric Bellm. Please consider acknowledging them if this notebook is used for the preparation of journal articles, software releases, or other notebooks.
Get Support: Everyone is encouraged to ask questions or raise issues in the Support Category of the Rubin Community Forum. Rubin staff will respond to all questions posted there.
1. Introduction¶
This notebook demonstrates how to obtain and plot a difference-imaged light curve of an extragalactic transient captured in Data Preview 1 (DP1).
Related tutorials: There are 200-level tutorials on difference_images
as well as the DiaSource
, DiaObject
and ForcedSourceOnDiaObject
catalogs. There is another notebook in this 306 series (306.2) that demonstrates candidate transient identification.
1.1. Import packages¶
Import numpy
, a fundamental package for scientific computing with arrays in Python
(numpy.org), and
matplotlib
, a comprehensive library for data visualization
(matplotlib.org;
matplotlib gallery).
From the lsst
package, import modules for accessing the Table Access Protocol (TAP) service,
the butler, and image display functions from the LSST Science Pipelines (pipelines.lsst.io).
import matplotlib.pyplot as plt
import numpy as np
from lsst.rsp import get_tap_service
from lsst.utils.plotting import (get_multiband_plot_colors,
get_multiband_plot_symbols,)
1.2. Define parameters and functions¶
Create an instance of the TAP service, and assert that it exists.
service = get_tap_service("tap")
assert service is not None
Define filter names, plot markers, and colors for plotting
filter_names = ['u', 'g', 'r', 'i', 'z', 'y']
filter_colors = get_multiband_plot_colors()
filter_symbols = get_multiband_plot_symbols()
2. Retrieve light curve data¶
Obtain light curve data from the ForcedSourceOnDiaObject
table, which contains forced PSF photometry for all difference images as well as non-difference images (i.e. visit_image
). The relevant table columns for plotting light curves are:
psfDiffFlux
: Forced PSF photometry on difference images at DiaObject positiondiaObjectId
: Unique DiaObject identifierband
: Filter associated with flux measurementvisit
: Identifier of the visit where the forced photometry was measured (used for table JOIN onVisit
table)
The date information expMidptMJD
, which is mid-point time for the visit in MJD, can be obtained from the Visit
table.
The units used to plot the light curve are in flux (nJy) and not magnitudes since the negative flux measurements would be omitted when converting to magnituides. More information of the light curve can therefore be plotted in flux units.
The difference-image forced PSF photometry should be used to plot the extragalactic transient light curve instead of the non-difference-image forced PSF photometry because of potential contamination from the host galaxy in the non-difference image.
2.1. From coordinates¶
The first step to obtain light curve data is to define the coordinates (ra and dec) of an extragalactic transient captured in DP1.
ra = 53.125
dec = -27.740
Perform a TAP search on the coordinates of the transient in the ForcedSourceOnDiaObject
table.
A table JOIN is used with the Visit
table to extract visit timing info (expMidptMJD
) for each entry in the ForcedSourceOnDiaObject
.
query = "SELECT fsodo.coord_ra, fsodo.coord_dec, "\
"fsodo.diaObjectId, fsodo.visit, fsodo.band, "\
"fsodo.psfDiffFlux, fsodo.psfDiffFluxErr, "\
"vis.expMidptMJD "\
"FROM dp1.ForcedSourceOnDiaObject as fsodo "\
"JOIN dp1.Visit as vis ON vis.visit = fsodo.visit "\
"WHERE CONTAINS (POINT('ICRS', coord_ra, coord_dec), "\
"CIRCLE('ICRS'," + str(ra) + ", "\
+ str(dec) + ", 0.00028)) = 1 "
print(query)
SELECT fsodo.coord_ra, fsodo.coord_dec, fsodo.diaObjectId, fsodo.visit, fsodo.band, fsodo.psfDiffFlux, fsodo.psfDiffFluxErr, vis.expMidptMJD FROM dp1.ForcedSourceOnDiaObject as fsodo JOIN dp1.Visit as vis ON vis.visit = fsodo.visit WHERE CONTAINS (POINT('ICRS', coord_ra, coord_dec), CIRCLE('ICRS',53.125, -27.74, 0.00028)) = 1
Run the TAP query.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
Job phase is COMPLETED
Fetch the results of the TAP search in table form and print the number of rows.
assert job.phase == 'COMPLETED'
FrcdSrc = job.fetch_result().to_table()
print(len(FrcdSrc))
446
Uncomment to view table.
# FrcdSrc
2.2. From diaObjectIdd¶
For cases where the diaObjectId
is known instead of (or in addition to) the coordinates,
the TAP query can include a constraint on only the diaObjectId
column instead of spatial constraints.
The diaObjectId
of the transient explored in this notebook is 611255759837069401.
Option to define the query using the diaObjectId
. This TAP query returns the same data as the query in Section 2.1.
# DiaObjID = 611255759837069401
# query = "SELECT fsodo.coord_ra, fsodo.coord_dec, "\
# "fsodo.diaObjectId, fsodo.visit, fsodo.band, "\
# "fsodo.psfDiffFlux, fsodo.psfDiffFluxErr, "\
# "fsodo.psfFlux as psfFlux, fsodo.psfFluxErr, "\
# "vis.expMidptMJD "\
# "FROM dp1.ForcedSourceOnDiaObject as fsodo "\
# "JOIN dp1.Visit as vis ON vis.visit = fsodo.visit "\
# "WHERE fsodo.diaObjectId = "+str(DiaObjID)
# print(query)
3. Plot light curve¶
Plot the forced PSF photometry on the difference images covering the extragalactic transient.
fig, ax = plt.subplots(1, 1, figsize=(10, 6), sharey=True, sharex=False)
for f, filt in enumerate(filter_names):
fx = np.where(FrcdSrc['band'] == filt)[0]
ax.errorbar(
FrcdSrc['expMidptMJD'][fx],
FrcdSrc['psfDiffFlux'][fx],
yerr=FrcdSrc['psfDiffFluxErr'][fx],
fmt=filter_symbols[filt],
ms=10,
mew=2,
mec=filter_colors[filt],
ecolor=filter_colors[filt],
alpha=0.5,
color='none',
label=filt
)
del fx
ax.set_xlabel('Modified Julian Date')
ax.set_ylabel('Difference-Image Flux (nJy)')
ax.set_title('Forced PSF Photometry (ForcedSourceOnDiaObject)')
ax.set_ylim(-13000, 15000)
ax.legend(loc='upper right')
plt.subplots_adjust(wspace=.0)
plt.show()
Figure 1: Forced PSF (difference-image) photometry of an extragalactic transient in DP1 from the
ForcedSourceOnDiaObject
table. Note that the difference-image flux is negative because the reference template images used to perform the image subtraction likely captured emission from the transient. This is not surprising given that the temporal baseline of DP1 may not have been long enough to build a reference template that did not include emission from the transient.