Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MickaelRigault/ztfquery/llms.txt

Use this file to discover all available pages before exploring further.

The ztfquery.lightcurve module provides access to ZTF light curves served by the IRSA LightCurve API. These light curves are built by matching the ZTF epochal catalogs — completely independently of the alert broker pipeline — making them the preferred source for variability studies, AGN monitoring, and periodic star searches.
These are not alert-packet light curves. ZTF alert light curves are generated by the real-time difference-imaging pipeline and distributed through alert brokers. The light curves in this module come from matching ZTF’s epochal photometry catalogs against reference-image source detections. They are independent of alerts and are particularly useful for the variable star and AGN community.

Requirements

You need an active account on IRSA to access the light curve service. Store your credentials using the ztfquery setup so they are loaded automatically:
python -c "import ztfquery; ztfquery.io.set_account('irsa')"

LCQuery class

LCQuery is the central class for all light curve queries. It wraps HTTP requests to the IRSA light curve API and stores the results as a pandas DataFrame in its .data property. Three class methods cover the most common query patterns; a static download method handles arbitrary API parameters.

Query by sky position — LCQuery.from_position()

Search for all ZTF sources within a circular aperture on the sky. Returns an LCQuery object whose .data DataFrame contains all matching epochal photometry.
from ztfquery import lightcurve

# RA=197.501495 deg, Dec=+75.721959 deg, radius=5 arcsec
lcq = lightcurve.LCQuery.from_position(197.501495, +75.721959, 5)

print(lcq.data)
ra
float
required
ICRS right ascension of the search center in decimal degrees. Valid range: [0, 180].
dec
float
required
ICRS declination of the search center in decimal degrees. Valid range: [-90, 90].
radius_arcsec
float
required
Search radius in arcseconds. For performance reasons the valid range is (0, 600].
bandname
str
Restrict results to one or more filter bands. Accepted values: "g", "r", "i", or comma-separated combinations such as "g,i". Equivalent to filter IDs 1, 2, and 3 respectively.
mag
list[float, float]
Restrict to sources whose median magnitude falls in [mag_min, mag_max]. Implemented as a filter on the medianmag column of the ZTF objects table. Example: mag=[17.0, 17.7].

Query by source ID — LCQuery.from_id()

Retrieve light curves for one or more known ZTF source identifiers. Source IDs are the integer object identifiers used in the ZTF catalog.
from ztfquery import lightcurve

lcq = lightcurve.LCQuery.from_id([686103400067717, 686103400106565])

print(lcq.data)
id
list[int] | str | int
required
One or more ZTF source identifiers. Accepts a single integer, a comma-separated string, or a Python list of integers.
# All three forms are equivalent
LCQuery.from_id(686103400067717)
LCQuery.from_id("686103400067717,686103400106565")
LCQuery.from_id([686103400067717, 686103400106565])
The BAND, BANDNAME, NOBS_MIN, and MAG filter parameters are compatible with position-based queries but not with ID-based queries. Passing them to from_id() will raise a ValueError.

Generic query — LCQuery.download_data()

A static method that accepts the full set of IRSA LightCurve API parameters as keyword arguments. Use this when you need fine-grained control over the query that is not covered by from_position() or from_id().
from ztfquery import lightcurve

# Circle query restricted to g-band
df = lightcurve.LCQuery.download_data(
    circle=[298.0025, 29.87147, 0.0014],
    bandname="g"
)
This method returns a pandas DataFrame directly (not an LCQuery instance). Pass it to the LCQuery constructor if you want to use .show() or other instance methods.
circle
list[float, float, float]
Spatial constraint as [ra, dec, radius], all in degrees. RA valid range: [0, 180]; Dec: [-90, 90]; radius: (0, 0.1667].
bandname
str
Filter band name: "g", "r", or "i", or comma-separated combinations.
num_obs
int
Minimum number of observation epochs required for a source to be included. Filters on the nobs column.
time
list[float] | float
Modified Julian Date (MJD) range for the light curve data. Provide a single value for an exact epoch or a two-element list [mjd_start, mjd_end] for a range.
bad_catflags_mask
int
Bitmask used to exclude photometry points with flagged data quality issues. Points with any of the indicated catflag bits set are removed. Example: bad_catflags_mask=15 excludes points with any of bits 0–3 set.
collection
str
The ZTF light curve collection to query. Default corresponds to the most recent public release. Use "ztf_dr1" for the first data release or "ztf" for the proprietary collection (login required).

Construct from an existing DataFrame

If you have already downloaded and saved a light curve as a CSV or Parquet file, you can wrap it in an LCQuery object to regain access to .show() and other methods.
import pandas as pd
from ztfquery import lightcurve

# Load a previously saved light curve
data = pd.read_csv("my_lightcurve.csv")

# Wrap it in LCQuery
lcq = lightcurve.LCQuery(data)

# Now you can use all LCQuery methods
lcq.show()
data
pandas.DataFrame
required
A DataFrame with the same column structure as the IRSA light curve API response (e.g. mjd, mag, magerr, filtercode). Typically loaded from a file that was saved via lcq.data.to_csv() or lcq.data.to_parquet().

.data property

After any successful query, results are stored in the .data property as a pandas DataFrame. Key columns include:
ColumnDescription
mjdModified Julian Date of the observation
magMagnitude measurement
magerrMagnitude uncertainty
filtercodeFilter identifier (zg, zr, or zi)
catflagsData quality bitmask
print(lcq.data.head())
print(lcq.data.columns.tolist())

.show() method

Plot the light curve using matplotlib. Each filter band is displayed in a distinct colour (zg → green, zr → red, zi → orange), with error bars. The y-axis is inverted (brighter magnitudes at the top).
lcq.show()
show() accepts any keyword arguments that matplotlib.axes.Axes.errorbar() understands, so you can customise marker style, size, and colour directly: lcq.show(marker="s", ms=5).

Code examples

Query by position

from ztfquery import lightcurve

# 5-arcsec cone search around RA=197.50, Dec=+75.72
lcq = lightcurve.LCQuery.from_position(197.501495, +75.721959, 5)

# Inspect the data
print(lcq.data[["mjd", "mag", "magerr", "filtercode"]].head())

# Plot
lcq.show()

Query by source IDs

from ztfquery import lightcurve

# Retrieve light curves for two known ZTF sources
lcq = lightcurve.LCQuery.from_id([686103400067717, 686103400106565])

print(f"Retrieved {len(lcq.data)} photometry points")
lcq.show()

Generic download with CIRCLE and bandname

from ztfquery import lightcurve

# g-band only, within a 0.0014-degree radius circle
df = lightcurve.LCQuery.download_data(
    circle=[298.0025, 29.87147, 0.0014],
    bandname="g"
)

print(df.head())

# Wrap in LCQuery to use .show()
lcq = lightcurve.LCQuery(df)
lcq.show()

Create from a saved DataFrame

import pandas as pd
from ztfquery import lightcurve

# Save your data once
lcq_original = lightcurve.LCQuery.from_position(197.501495, +75.721959, 5)
lcq_original.data.to_csv("lc_197p5_75p7.csv", index=False)

# Later, reload it without re-querying IRSA
data = pd.read_csv("lc_197p5_75p7.csv")
lcq = lightcurve.LCQuery(data)
lcq.show()

Build docs developers (and LLMs) love