streamobs.observed module#

class streamobs.observed.StreamInjector(survey, **kwargs)[source]#

Bases: object

Inject observational effects into stream data for a given survey.

This class handles the core injection logic while keeping survey data separate. All survey data is loaded once and cached, making multiple injections efficient.

survey#

Survey instance containing all survey-specific data and functions.

Type:

Survey

mask_cache#

Cache of previously created HEALPix masks to avoid recomputation.

Type:

dict (class attribute)

_last_gc_frame#

The most recently used great circle frame. This allows reusing the same sky location across multiple inject() calls when gc_frame=’last’.

Type:

GreatCircleICRSFrame or None

Examples

Initialize with a survey:

>>> injector = StreamInjector('lsst', release='dc2')

Or with a pre-loaded Survey object:

>>> survey = Survey.load('lsst', release='dc2')
>>> injector = StreamInjector(survey)

Methods

clear_mask_cache()

Clear the mask cache.

complete_data(data[, bands])

Validate and complete the columns needed for injection.

detect_flag(pix[, mag, band])

Apply the survey selection to determine detection flags for stars.

fluxToMag(flux)

Convert from flux to AB magnitude.

getFluxError(mag, mag_error)

Convert magnitude error to flux error.

inject(data[, bands])

Add observed quantities from the survey to the given data.

list_cached_masks()

List all cached masks.

magToFlux(mag)

Convert from AB magnitude to flux.

phi_to_radec(phi1, phi2[, gc_frame, seed, ...])

Transform stream coordinates (phi1, phi2) to sky coordinates (RA, Dec).

plot_stream_in_mask(data, mask_type[, ...])

Plot the stream over the footprint mask.

sample_measured_magnitudes(mag_true, ...)

Sample measured magnitudes from true apparent magnitudes and errors.

classmethod clear_mask_cache()[source]#

Clear the mask cache.

This can be useful if you want to free memory or force masks to be recomputed.

Examples

>>> StreamInjector.clear_mask_cache()
complete_data(data, bands=['r', 'g'], **kwargs)[source]#

Validate and complete the columns needed for injection.

This function ensures sky coordinates are present and, if requested, fills missing photometric magnitude columns using a stream model. Specifically:

  • If (ra, dec) are missing but (phi1, phi2) exist, it converts to sky coordinates via phi_to_radec.

  • It checks for mag_<band> for each requested band; any missing bands are generated via StreamModel.complete_catalog when a stream_config is provided.

  • Existing columns are preserved and are not overwritten.

Parameters:
  • data (pandas.DataFrame) – Input catalog. Must contain either (ra, dec) or (phi1, phi2). The DataFrame is copied; the input object is not modified in place.

  • bands (list[str], optional) – Photometric bands to ensure (as mag_<band>). Default is ['r', 'g'].

  • **kwargs

    Additional options:

    rngnumpy.random.Generator, optional

    Random number generator instance.

    seedint, optional

    Random seed used to initialize an RNG if rng is not given.

    gc_framegala.coordinates.GreatCircleICRSFrame or ‘last’, optional

    Great circle frame to use. If ‘last’, uses the frame from the previous call. If None, generates a new random frame.

    stream_configdict, optional

    Configuration passed to StreamModel. Required only when at least one requested magnitude band is missing. See StreamModel for the expected schema (e.g., track, distance modulus, isochrone).

    Keyword arguments forwarded to phi_to_radec (only used when converting from (phi1, phi2)):

    mask_typelist[str] or str, optional

    Mask(s) used when searching a frame (e.g., ‘footprint’, ‘maglim_r’, ‘ebv’).

    percentile_thresholdfloat, optional

    Fraction of points that must lie inside the mask when selecting a frame. Default defined in phi_to_radec.

    max_iterint, optional

    Maximum trials when searching a frame. Default defined in phi_to_radec.

Returns:

A copy of the input with the required columns present: ra, dec, and one mag_<band> column per requested band.

Return type:

pandas.DataFrame

Raises:

ValueError – If neither (ra, dec) nor (phi1, phi2) are present; or if one or more magnitude bands are missing and stream_config is not provided; or if after completion a required column is still absent.

Notes

  • Only missing magnitude columns are synthesized; existing values are left untouched.

  • Magnitudes are produced by StreamModel.complete_catalog and rely on the model’s configuration (e.g., isochrone and distance modulus).

  • When a new gc_frame is created or used, it is stored in self._last_gc_frame for potential reuse via gc_frame='last'.

Examples

Convert from (phi1, phi2) and generate both bands:

>>> df = pd.DataFrame({'phi1': [-5, 0, 5], 'phi2': [0, 0, 0]})
>>> cfg = {...}  # stream model config
>>> out = injector.complete_data(df, bands=['r', 'g'], stream_config=cfg)

Use already existing ra/dec and fill a missing ‘g’ band from a model:

>>> df = pd.DataFrame({'phi1': [-5, 0, 5], 'phi2': [0, 0, 0], 'ra': [10.1, 12.5, 24.7], 'dec': [5.2, 6.2, 7.2],})
>>> out = injector.complete_data(df, bands=['r', 'g'], stream_config=cfg, seed=42)

Reuse the same gc_frame for multiple streams:

>>> data1 = injector.complete_data(df1, seed=42)  # Creates new frame
>>> data2 = injector.complete_data(df2, gc_frame='last')  # Reuses frame from data1
detect_flag(pix, mag=None, band='r', **kwargs)[source]#

Apply the survey selection to determine detection flags for stars.

This method uses the survey completeness function and random sampling to determine which stars would be detected by the survey.

Parameters:
  • pix (int or np.ndarray) – HEALPix pixel index/indices.

  • mag (float or np.ndarray, optional) – Magnitude(s). Default is None.

  • band (str, optional) – Band to consider for detection. Default is ‘r’.

  • **kwargs

    Additional keyword arguments:

    rngnumpy.random.Generator, optional

    Random number generator instance.

    seedint, optional

    Random seed if rng is not provided.

    perfect_galstarsepbool, optional

    If True, assumes perfect star/galaxy separation. Default is False.

Returns:

Boolean array: True for detected stars, False otherwise.

Return type:

np.ndarray

Raises:

ValueError – If magnitude values are not provided.

static fluxToMag(flux)[source]#

Convert from flux to AB magnitude.

Parameters:

flux (float or np.ndarray) – Flux in Janskys (Jy).

Returns:

AB magnitude(s).

Return type:

float or np.ndarray

static getFluxError(mag, mag_error)[source]#

Convert magnitude error to flux error.

Parameters:
  • mag (float or np.ndarray) – Magnitude(s).

  • mag_error (float or np.ndarray) – Magnitude error(s).

Returns:

Flux error in Janskys (Jy).

Return type:

float or np.ndarray

inject(data, bands=['r', 'g'], **kwargs)[source]#

Add observed quantities from the survey to the given data.

This method applies observational effects including photometric errors, magnitude measurements, and detection flags based on survey properties.

Parameters:
  • data (str or pd.DataFrame) – Input data as DataFrame or path to the file (CSV or Excel). Must contain either (ra, dec) or (phi1, phi2) coordinates, and magnitude columns for the specified bands.

  • bands (list of str, optional) – List of photometric bands to process. Default is [‘r’, ‘g’].

  • **kwargs

    Additional keyword arguments:

    seedint, optional

    Random seed for reproducibility.

    nsideint, optional

    HEALPix nside parameter. Default is 4096.

    detection_mag_cutlist of str, optional

    Bands to apply SNR detection cut. Default is [‘g’].

    savebool, optional

    Whether to save the output data. Default is False.

    folderstr or Path, optional

    Output folder path if save=True.

    dust_correctionbool, optional

    Whether to apply dust correction to observed magnitudes. Default is True.

    perfect_galstarsepbool, optional

    If True, also computes a flag assuming perfect star/galaxy separation (detection efficiency only, no classification losses). Default is False.

    verbosebool, optional

    Whether to print progress information. Default is True.

Returns:

DataFrame with the following added columns:

  • mag_<band>_obs : Observed magnitudes for each band

  • magerr_<band> : Photometric errors for each band

  • flag_observed : Boolean flag (True=detected, False=not detected). Includes both detection and classification efficiencies.

  • flag_perfect_galstarsep : Boolean flag assuming perfect star/galaxy separation (detection efficiency only, no classification losses; only if requested with perfect_galstarsep=True)

  • ra, dec : Sky coordinates (if not already present)

Return type:

pd.DataFrame

Raises:

ValueError – If required columns are missing or bands are not supported.

classmethod list_cached_masks()[source]#

List all cached masks.

Returns:

List of cache keys (survey_name, mask_types, ebv_threshold)

Return type:

list of tuples

Examples

>>> StreamInjector.list_cached_masks()
[('LSST', ('footprint', 'maglim_r'), None),
 ('LSST', ('ebv', 'footprint'), 0.2)]
static magToFlux(mag)[source]#

Convert from AB magnitude to flux.

Parameters:

mag (float or np.ndarray) – AB magnitude(s).

Returns:

Flux in Janskys (Jy).

Return type:

float or np.ndarray

mask_cache = {}#
phi_to_radec(phi1, phi2, gc_frame=None, seed=None, rng=None, mask_type=['footprint'], **kwargs)[source]#

Transform stream coordinates (phi1, phi2) to sky coordinates (RA, Dec).

This method converts stream coordinates to celestial coordinates using a great circle frame. If no frame is provided, it automatically finds one randomly chosen such that a given percentile of the points lie within the mask defined with mask_type.

The frame used (whether provided or generated) is stored in self._last_gc_frame for potential reuse via gc_frame='last' in subsequent calls.

Parameters:
  • phi1 (array-like) – Stream coordinates in degrees.

  • phi2 (array-like) – Stream coordinates in degrees.

  • gc_frame (gala.coordinates.GreatCircleICRSFrame or 'last', optional) – Great circle coordinate frame. If None, will be automatically determined. If ‘last’, uses the frame from the previous call (stored in self._last_gc_frame).

  • seed (int, optional) – Random seed for reproducible frame selection.

  • rng (numpy.random.Generator, optional) – Random number generator instance.

  • mask_type (list of str, optional) – Types of masks to use for footprint validation. Options: [“footprint”, “maglim_g”, “maglim_r”, “ebv”]. Default is [“footprint”].

  • **kwargs

    Additional keyword arguments passed to _find_gc_frame():

    percentile_thresholdfloat, optional

    Minimum fraction of points that must be in mask. Default is 0.99.

    max_iterint, optional

    Maximum number of random trials. Default is 1000.

Returns:

Sky coordinates in ICRS frame.

Return type:

astropy.coordinates.SkyCoord

Raises:
  • ValueError – If phi1 and phi2 have different lengths or contain invalid values.

  • RuntimeError – If no suitable great circle frame could be found.

Examples

Convert stream coordinates to sky coordinates:

>>> phi1 = np.linspace(-10, 10, 1000)
>>> phi2 = np.zeros_like(phi1)
>>> coords = injector.phi_to_radec(phi1, phi2, seed=42)

Reuse the frame from a previous call:

>>> coords2 = injector.phi_to_radec(phi1_2, phi2_2, gc_frame='last')
plot_stream_in_mask(data, mask_type, ebv_threshold=0.2, **kwargs)[source]#

Plot the stream over the footprint mask.

Creates a visualization showing the stream’s position relative to the survey footprint or other masks.

Parameters:
  • data (pd.DataFrame) – Data containing ‘ra’ and ‘dec’ columns.

  • mask_type (str or list of str) – Type(s) of masks to plot. Options: [“footprint”, “coverage”, “maglim_<band>”, “ebv”].

  • ebv_threshold (float, optional) – E(B-V) threshold (only used if ‘ebv’ in mask_type). Default is 0.2.

  • **kwargs

    Additional arguments passed to plotting function:

    output_folderstr, optional

    Path to save the figure.

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

Raises:

ValueError – If mask cannot be created from mask_type parameter.

Examples

Plot stream in footprint:

>>> fig, ax = injector.plot_stream_in_mask(data, ['footprint', 'maglim_r'])

Plot with custom E(B-V) threshold:

>>> fig, ax = injector.plot_stream_in_mask(
...     data, ['footprint', 'ebv'], ebv_threshold=0.15
... )
sample_measured_magnitudes(mag_true, mag_err, **kwargs)[source]#

Sample measured magnitudes from true apparent magnitudes and errors.

This method adds photometric noise to true magnitudes by sampling from a Gaussian distribution in flux space.

Parameters:
  • mag_true (float or np.ndarray) – True apparent magnitude(s).

  • mag_err (float or np.ndarray) – Magnitude error(s).

  • **kwargs

    Additional keyword arguments:

    rngnumpy.random.Generator, optional

    Random number generator instance.

    seedint, optional

    Random seed if rng is not provided.

Returns:

Measured magnitude(s). Returns “BAD_MAG” for objects with negative flux.

Return type:

np.ndarray or str