Lightcurves

Lightcurve clustering

We have minimal support for costructing the light curves from a sets of per-frame measurements of many objects, by applying simple spatial clusering to their positions. It is implemented in the stdpipe.lcs.LCs container that stores per-detection vectors (e.g. RA/Dec/flux) and can group them into spatial clusters using a KDTree radius search. Results are stored in self.lcs with centroid coordinates and member indices.

lcs = LCs()
lcs.add(ra=ra, dec=dec, flux=flux, time=time1)
# Can be called repeatedly, e.g. to append per-image chunks
lcs.add(ra=ra2, dec=dec2, flux=flux2, time=time2)
lcs.cluster(sr=1/3600, min_length=3)

# Cluster centroids (degrees) and sizes
print(lcs.lcs['ra'], lcs.lcs['dec'], lcs.lcs['N'])

# Show the lightcurve for first object
ids = lcs.lcs['ids'][0]
plt.plot(lcs.time[ids], lcs.flux[ids], 'o--')

The clustering results include:

  • x, y, z: centroid unit-vector coordinates

  • ra, dec: centroid sky coordinates in degrees

  • N: number of points per cluster

  • ids: list of index arrays for member points

  • kd: KDTree built from centroid vectors

You can pass an analyze= callback to compute per-cluster diagnostics. The callable should return a mapping; each value is appended to self.lcs under its key.

def analyze(lcs, ids):
    return {'mean_flux': np.mean(lcs.flux[ids])}

lcs.cluster(sr=1/3600, analyze=analyze)
print(lcs.lcs['mean_flux'])

Key parameters include sr (radius in degrees) and min_length (minimum number of detections required to keep a cluster).

class stdpipe.lcs.LCs[source]

Container for light-curve data vectors with spatial clustering utilities.

Stores user-provided per-detection vectors (e.g., ra/dec/flux/time) and groups detections into spatial clusters using a KDTree radius search. Clustering returns per-cluster centroids and member indices in self.lcs.

Methods

add(**kwargs)

Add per-detection vectors to the container.

cluster([sr, min_length, col_ra, col_dec, ...])

Spatially cluster the data vectors using ra/dec values stored in col_ra and col_dec.

Notes

  • add() broadcasts scalars to the length of the vector inputs, which must all share the same length. Keys omitted from a call, and rows preceding the first appearance of a new key, are padded so that all stored vectors stay aligned: with NaN for floating-point columns (missing Time entries become masked), with None (object dtype) otherwise.

  • Data vectors are stored as per-key lists of ndarray chunks and consolidated lazily into single arrays on first attribute access.

  • cluster() refines centroids and can call an analyze(self, ids) callback per cluster.

  • Coordinate jitter is applied when building the KDTree to avoid degeneracy from repeated positions.

  • Clustering results are stored in self.lcs with keys: - x, y, z: centroid unit-vector coordinates. - ra, dec: centroid sky coordinates in degrees. - N: number of points per cluster. - ids: list of index arrays for member points in the container. - kd: KDTree built from centroid vectors for fast queries.

add(**kwargs)[source]

Add per-detection vectors to the container.

Each keyword defines a stored vector. Scalars are broadcast to the length of the vector inputs, which must all share the same length (ValueError is raised otherwise). This method may be called repeatedly to append new chunks of measurements (e.g., per-image batches) to the existing vectors. Previously stored keys omitted from a call, as well as rows preceding the first appearance of a new key, are padded so that all stored vectors stay aligned - with NaN for floating-point columns (missing Time entries become masked), with None otherwise.

Examples

>>> lcs = LCs()
>>> lcs.add(ra=[1, 2], dec=[3, 4], flux=10.0)
cluster(sr=0.0002777777777777778, min_length=None, col_ra='ra', col_dec='dec', verbose=True, analyze=None, N=1000, max_refine_iter=1, rng=0)[source]

Spatially cluster the data vectors using ra/dec values stored in col_ra and col_dec.

Parameters:
srfloat, optional

Clustering radius in degrees.

min_lengthint or None, optional

Minimum number of points required to keep a cluster.

col_rastr, optional

Name of the RA column in stored vectors.

col_decstr, optional

Name of the Dec column in stored vectors.

verbosebool or callable, optional

Logging control, can be a print-like function.

analyzecallable or None, optional

Optional callback analyze(self, ids) called per accepted cluster. Any returned mapping entries are appended into self.lcs under their respective keys (one entry per cluster). The callback may also return None to skip reporting for a given cluster.

Nint, optional

Progress update interval in points.

max_refine_iterint, optional

Maximum number of centroid refinement iterations (default 1).

rngint, numpy.random.Generator, or None, optional

Seed or generator for the coordinate jitter used to break KDTree degeneracies from repeated positions. The default fixed seed makes clustering deterministic; pass None for non-deterministic jitter.

Notes

Clustering is greedy in storage order: every not-yet-masked point seeds a radius search, and all points within the refined cluster radius are excluded from seeding afterwards. Such points may still be claimed as members of later clusters, so nearby clusters can share points. For point distributions wider than sr, the exact set of clusters may depend on the ordering of the stored points.