pyBIA.catalog ============= .. py:module:: pyBIA.catalog .. autoapi-nested-parse:: Created on Thu Nov 17 10:10:11 2021 @author: danielgodinez Classes ------- .. autoapisummary:: pyBIA.catalog.Catalog Functions --------- .. autoapisummary:: pyBIA.catalog.morph_parameters pyBIA.catalog.make_table pyBIA.catalog.make_dataframe pyBIA.catalog.subtract_background pyBIA.catalog.segm_find pyBIA.catalog.get_segmentation pyBIA.catalog.compute_layered_segmentation pyBIA.catalog.get_extent pyBIA.catalog.get_display_limits pyBIA.catalog.plot_objects_segmentation pyBIA.catalog.plot_images_grid_2x2 pyBIA.catalog.align_error_array Module Contents --------------- .. py:class:: Catalog(data: numpy.ndarray, *, x: numpy.ndarray | list | None = None, y: numpy.ndarray | list | None = None, bkg: float | None = None, error: numpy.ndarray | None = None, zp: float | None = None, exptime: float | None = None, morph_params: bool = True, nsig: float = 0.3, threshold: int = 10, deblend: bool = False, size: int = 100, obj_name=None, field_name=None, flag=None, aperture: int = 15, annulus_in: int = 20, annulus_out: int = 35, kernel_size: int = 21, npixels: int = 9, connectivity: int = 8, invert: bool = False, cat: pandas.DataFrame | None = None) Build photometric and morphological catalogs from postage-stamp astronomical images. This class extracts source positions and performs aperture photometry along with segmentation-based morphological analysis. Sources can be detected automatically via image segmentation or specified manually through input coordinates. The resulting catalog includes flux measurements, optional background subtraction, and a comprehensive set of shape descriptors for use in classification pipelines. :param data: 2D image array. :type data: ndarray :param x: Pixel coordinates of source centers. If None, sources are detected automatically. :type x: array-like or None, optional :param y: Pixel coordinates of source centers. If None, sources are detected automatically. :type y: array-like or None, optional :param bkg: Background mode. Use 0 if background is already subtracted; None to estimate the local sky background. :type bkg: float or None, optional :param error: Pixel-wise error map with the same shape as `data`. :type error: ndarray or None, optional :param zp: Zeropoint for magnitude calculations. If None, magnitudes are not computed. :type zp: float or None, optional :param exptime: Exposure time in seconds. If provided, `data` is normalized (e.g., counts per sec) when performing segmentation and computing morphology. :type exptime: float or None, optional :param morph_params: If True, compute moment-based morphological features (default is True). :type morph_params: bool, optional :param nsig: Detection threshold in units of background sigma. Pixels above `nsig` are considered in segmentation. Default is 0.3. :type nsig: float, optional :param threshold: Radius (in pixels) around the source center used to validate detection. If no object is found within this region, the source is flagged as a non-detection. Set to 0 to require exact overlap. Default is 10. :type threshold: int, optional :param deblend: If True, enables deblending of overlapping sources. Default is False (recommended for diffuse, extended objects). :type deblend: bool, optional :param size: Side length (pixels) of the square cutout used per source. If the image is smaller than `size` along any axis, the largest square that fits is used. Default is 100. :type size: int, optional :param obj_name: List of object names for catalog rows. :type obj_name: array-like or None, optional :param field_name: List of field names for catalog rows. :type field_name: array-like or None, optional :param flag: List of flags for catalog rows. :type flag: array-like or None, optional :param aperture: Aperture radius (in pixels) for photometry. Default is 15. :type aperture: int, optional :param annulus_in: Inner radius (in pixels) of background annulus for local sky estimation. Default is 20. :type annulus_in: int, optional :param annulus_out: Outer radius (in pixels) of background annulus. Default is 35. :type annulus_out: int, optional :param kernel_size: Size of Gaussian kernel (in pixels) for segmentation smoothing. Default is 21. :type kernel_size: int, optional :param npixels: Minimum area (in pixels) for segmentation detection. Default is 9. :type npixels: int, optional :param connectivity: Pixel connectivity for segmentation (4 or 8). Default is 8. :type connectivity: int, optional :param invert: If True, flips the (x, y) input order when cropping sub-images. Useful for data with (row, column) indexing or FITS-style origin. Default is False. :type invert: bool, optional :param cat: Existing catalog to augment or use for metadata. :type cat: pandas.DataFrame or None, optional .. py:attribute:: data .. py:attribute:: error :value: None .. py:attribute:: zp :value: None .. py:attribute:: exptime :value: None .. py:attribute:: morph_params :value: True .. py:attribute:: nsig :value: 0.3 .. py:attribute:: threshold :value: 10 .. py:attribute:: deblend :value: False .. py:attribute:: aperture :value: 15 .. py:attribute:: annulus_in :value: 20 .. py:attribute:: annulus_out :value: 35 .. py:attribute:: kernel_size :value: 21 .. py:attribute:: npixels :value: 9 .. py:attribute:: connectivity :value: 8 .. py:attribute:: invert :value: False .. py:attribute:: bkg :value: None .. py:attribute:: size :value: 100 .. py:attribute:: cat :value: None .. py:attribute:: x :value: None .. py:attribute:: y :value: None .. py:attribute:: obj_name :value: None .. py:attribute:: field_name :value: None .. py:attribute:: flag :value: None .. py:method:: create(*, save_file: bool = True, path: str | None = None, filename: str | None = None) Build the full photometric and morphological catalog. This method performs source detection (via segmentation or user-supplied positions), computes aperture photometry, and optionally includes morphological features. It returns the catalog as a pandas DataFrame and can also save it to disk. :param save_file: If True, saves the catalog as a CSV file. Default is True. :type save_file: bool, optional :param path: Directory where the output CSV file will be saved. If None, defaults to the home directory. :type path: str or None, optional :param filename: Name of the output CSV file. Defaults to "pyBIA_catalog.csv". :type filename: str or None, optional :returns: DataFrame containing the photometric and morphological measurements for all detected sources. :rtype: pandas.DataFrame :raises ValueError: If background mode (`bkg`) is invalid, `data` and `error` shapes mismatch, aperture and annulus sizes are incompatible, or if `x` and `y` coordinates differ in length. .. rubric:: Notes - If `x` and `y` are not provided, automatic source detection is run on the full frame. - If `x` and `y` are given, photometry and morphology are computed only at those positions. - Catalog output includes flux, flux error, optional magnitudes, and morphology features depending on initialization settings. .. py:method:: _auto_detect_sources() Automatically detect sources using segmentation and build the catalog. This method performs full-frame source detection via image segmentation (using `photutils.detect_sources`), estimates background if needed, computes aperture photometry, and optionally derives morphological features using moment-based shape descriptors. Results are stored in `self.cat`. .. py:method:: _aperture_photometry() Perform aperture photometry at user-supplied positions and build the catalog. This method computes circular-aperture fluxes at specified `(x, y)` coordinates, optionally subtracts a local background estimated from an annular region, and calculates flux errors if an error map is provided. Morphological features are computed if enabled. The resulting catalog is stored in `self.cat`. .. py:method:: _subtract_global_background() Estimate and subtract a global background level from the image. Only used when no catalog positions are input. For large images, the method estimates the background using a sliding box of size `2 × annulus_out`, ensuring the region encompasses the largest background annulus used for photometry. For small images, a single sigma-clipped median value is subtracted instead. :returns: Background-subtracted image. :rtype: ndarray .. py:function:: morph_parameters(data, x, y, size=100, nsig=0.6, threshold=10, kernel_size=21, median_bkg=None, invert=False, deblend=False, exptime=None, npixels=9, connectivity=8) Compute segmentation-based morphological features for sources at given positions. For each (x, y) position, a `size × size` cutout is extracted, optionally background- corrected and exposure-normalized, then segmented (via `segm_find`) to isolate the central source. Moment-based features are measured (via `make_moments_table`) and photutils-like source properties are recorded. Results are suitable for downstream classification tasks. :param data: 2D image array. :type data: ndarray :param x: Pixel coordinates of source centers. Scalars are accepted and will be promoted to length-1 arrays. :type x: array-like or scalar :param y: Pixel coordinates of source centers. Scalars are accepted and will be promoted to length-1 arrays. :type y: array-like or scalar :param size: Side length (pixels) of the square cutout used per source. If the image is smaller than `size` along any axis, the largest square that fits is used. Default is 100. :type size: int, optional :param nsig: Detection threshold in units of background sigma for segmentation. Pixels above `nsig` contribute to detected regions. Default is 0.6. :type nsig: float, optional :param threshold: Central-detection validation radius (pixels). If `threshold == 0`, require that the exact central pixel belongs to a segmented object; otherwise, require at least one segmented pixel within a central circular region of radius `threshold`. Sources failing this test are flagged as non-detections. Default is 10. :type threshold: int, optional :param kernel_size: Gaussian kernel size (pixels) used by `segm_find` for segmentation smoothing. Default is 21. :type kernel_size: int, optional :param median_bkg: Per-source median background values to subtract from each cutout (not a full background map). If None, input `data` is assumed to be background-subtracted. Length must match `x`/`y` if provided. Default is None. :type median_bkg: array-like or None, optional :param invert: If True, swap (x, y) when cropping (useful for data in row–column indexing or FITS-style top-left origin). Default is False. :type invert: bool, optional :param deblend: If True, enable deblending in `segm_find` to split overlapping sources. Default is False. :type deblend: bool, optional :param exptime: Exposure time in seconds. If provided, each cutout is divided by `exptime` prior to segmentation/feature measurement (e.g., to convert counts to counts/s). Default is None. :type exptime: float or None, optional :param npixels: Minimum area (pixels) for valid segmented regions. Default is 9. :type npixels: int, optional :param connectivity: Pixel connectivity for segmentation (4 or 8). Default is 8. :type connectivity: int, optional :returns: * **props_list** (*ndarray of object*) -- Array of per-source photutils-like property selections (e.g., slices from `SourceCatalog`). For non-detections, the sentinel value `-999` is inserted. * **moments_list** (*list of pandas.DataFrame*) -- Per-source moment feature tables returned by `make_moments_table`. For non-detections, the sentinel value `-999` is inserted. * **segm_map** (*ndarray*) -- Segmentation map (int labels) for the last processed cutout. If any source failed detection, a zero array of that cutout's shape is returned. :raises ValueError: If the number of properties and moment tables differs (internal consistency check). .. rubric:: Notes - Each source is processed independently using a cropped cutout for computational efficiency. - Central-detection validation: * `threshold == 0` enforces exact central-pixel membership in a segment. * `threshold > 0` accepts any segment intersecting the central circular mask. The segment nearest the center is retained when multiple intersect the mask. - FITS coordinate convention: Many FITS images use a top-left origin (row, column). If your coordinates follow this convention, set `invert=True` so cropping treats inputs correctly. `pyBIA` assumes standard (x to the right, y upward) unless inverted. - For very small images (`< ~50` pixels on a side), results may be unstable if the source is truncated at the edges (a warning is printed). .. py:function:: make_table(props, moments) Assemble a flat feature array from photutils `SourceCatalog` properties and custom moments. For each source, this function concatenates (i) the moment-based features from `moments` and (ii) a selected subset of photutils segmentation properties from `props`. The resulting per-source feature vector is suitable for ML pipelines. :param props: Sequence (length N) where each element is an indexable selection of a photutils `SourceCatalog` (e.g., `props[i][0]`) representing the segmented source for sample i. If a source is missing (e.g., no segment), that entry should still exist but may be unusable; this function will emit sentinels. :type props: sequence :param moments: Sequence (length N) of mapping-like objects (e.g., dict or DataFrame row) containing scalar moment features keyed by the following names: `["M00","M10","M01","M20","M11","M02","M30","M21","M12","M03", "mu00","mu10","mu01","mu20","mu11","mu02","mu30","mu21","mu12","mu03", "G00","G10","G01","G20","G11","G02","G30","G21","G12","G03", "Hu1","Hu2","Hu3","Hu4","Hu5","Hu6","Hu7", "L00","L10","L01","L20","L11","L02","L30","L21","L12","L03"]`. :type moments: sequence :returns: **features** -- Per-source feature matrix. :rtype: ndarray, shape (N, D) .. rubric:: Notes - If a source has no valid segmented object or moments, the function fills the entire feature vector for that source with the sentinel value `-999`. - The `'isscalar'` property is cast to an integer flag: 1 for True (single source), 0 for False. - All other properties are extracted as scalars from the photutils table. .. py:function:: make_dataframe(table=None, x=None, y=None, zp=None, flux=None, flux_err=None, median_bkg=None, obj_name=None, field_name=None, flag=None, save=True, path=None, filename=None) Assemble a photometry+morphology catalog into a pandas DataFrame (and optional CSV). This function merges per-source metadata (names, positions, flags), photometric measurements (flux, flux error, optional magnitudes), background statistics, and morphology features (moments + photutils properties) into a single DataFrame. If requested, the table is also written to disk as a CSV. :param table: Feature matrix from `make_table`, shape (N, D) or (D,) for a single source. Columns are expected to be ordered as: moments ["M00","M10","M01","M20","M11","M02","M30","M21","M12","M03", "mu00","mu10","mu01","mu20","mu11","mu02","mu30","mu21","mu12","mu03", "G00","G10","G01","G20","G11","G02","G30","G21","G12","G03", "Hu1","Hu2","Hu3","Hu4","Hu5","Hu6","Hu7", "L00","L10","L01","L20","L11","L02","L30","L21","L12","L03"] followed by photutils properties ["area","covar_sigx2","covar_sigy2","covar_sigxy", "covariance_eigval1","covariance_eigval2", "cxx","cxy","cyy","eccentricity","ellipticity","elongation", "equivalent_radius","fwhm","gini","orientation","perimeter", "semimajor_sigma","semiminor_sigma","isscalar", "bbox_xmax","bbox_xmin","bbox_ymax","bbox_ymin", "max_value","maxval_xindex","maxval_yindex", "min_value","minval_xindex","minval_yindex"]. Default is None (no morphology columns added). :type table: array-like or None, optional :param x: Pixel coordinates of source centers. If provided, columns `xpix`, `ypix` are added. Length should match the number of rows N. Default is None. :type x: array-like or None, optional :param y: Pixel coordinates of source centers. If provided, columns `xpix`, `ypix` are added. Length should match the number of rows N. Default is None. :type y: array-like or None, optional :param zp: Photometric zeropoint. If provided with `flux`, columns `mag` and `mag_err` are computed as `-2.5*log10(flux) + zp` and `(2.5/ln 10)*(flux_err/flux)`, respectively. Default is None. :type zp: float or None, optional :param flux: Aperture-sum fluxes; adds column `flux`. Default is None. :type flux: array-like or None, optional :param flux_err: Flux uncertainties; adds column `flux_err`. If `zp` is also provided, `mag_err` is computed. Default is None. :type flux_err: array-like or None, optional :param median_bkg: Per-source median background values; adds column `median_bkg`. Default is None. :type median_bkg: array-like or None, optional :param obj_name: Per-source object names; adds column `obj_name`. Default is None. :type obj_name: array-like or None, optional :param field_name: Per-source field names; adds column `field_name`. Default is None. :type field_name: array-like or None, optional :param flag: Per-source flag values; adds column `flag`. Default is None. :type flag: array-like or None, optional :param save: If True, write the DataFrame to CSV. Default is True. :type save: bool, optional :param path: Output directory for CSV. If None, use the user's home directory. Default is None. :type path: str or Path or None, optional :param filename: Output CSV filename. Default is "pyBIA_catalog.csv". :type filename: str or None, optional :returns: **df** -- Catalog with available columns among: - Metadata: `obj_name`, `field_name`, `flag` - Positions: `xpix`, `ypix` - Background: `median_bkg` - Photometry: `flux`, `flux_err`, and (if `zp` provided) `mag`, `mag_err` - Morphology: the full set listed in `table` (moments + photutils properties) :rtype: pandas.DataFrame .. rubric:: Notes - If `table` is 1D, it is promoted to 2D with a single row. - Magnitudes are computed only when both `flux` and `zp` are provided; no guards are applied here for non-positive `flux` (users should prefilter or post-handle infinities/NaNs if needed). - When `save=True`, the CSV is written to `path/filename` with `index=False`. .. py:function:: subtract_background(data, length=150) Subtract a local background estimate from a 2D image. The image is divided into non-overlapping square regions of size `length × length`. For each region, the sigma-clipped median pixel value is computed and subtracted from that region. For images whose dimensions are not divisible by `length`, the array is padded symmetrically so that tiles align evenly. Padding is removed before return. :param data: 2D image array. :type data: ndarray :param length: Side length (pixels) of local regions used for background estimation. Default is 150. Smaller values capture more local variations, while larger values enforce a smoother background. :type length: int, optional :returns: **data_sub** -- Background-subtracted image of the same shape as input. :rtype: ndarray .. rubric:: Notes - For small images (`min(data.shape) < length`), no tiling is done; instead, the global sigma-clipped median is subtracted. - Padding is applied symmetrically (`mode='symmetric'`) so that regions near the edges are treated consistently. Padding is sliced away before returning. - Background estimation uses `astropy.stats.sigma_clipped_stats`, which is robust against outliers. .. py:function:: segm_find(data: numpy.ndarray, *, nsig: float = 0.6, kernel_size: int = 21, deblend: bool = False, npixels: int = 9, connectivity: int = 8) Perform image segmentation to detect sources above a sigma threshold. The input image is convolved with a 2D Gaussian kernel, then thresholded at `nsig × sigma` to identify sources. Optionally, overlapping sources can be deblended. Returns both the segmentation map and the convolved image. :param data: 2D background-subtracted image array. :type data: ndarray :param nsig: Detection threshold in units of background sigma. Pixels above `nsig` are considered during segmentation. Default is 0.6. :type nsig: float, optional :param kernel_size: Size (pixels) of the square Gaussian kernel used for convolution. Must be odd. Default is 21. :type kernel_size: int, optional :param deblend: If True, deblend overlapping sources in the segmentation map. Default is False (recommended when preserving diffuse blobs as single objects). :type deblend: bool, optional :param npixels: Minimum number of connected pixels above threshold required to define a source. Default is 9. :type npixels: int, optional :param connectivity: Pixel connectivity: 4 (edge-connected) or 8 (edge+corner-connected). Default is 8. :type connectivity: int, optional :returns: * **segm** (`photutils.segmentation.SegmentationImage` or None) -- Segmentation image labeling detected sources. None if no sources are found. * **convolved_data** (*ndarray*) -- Gaussian-convolved version of the input `data` used for source detection. .. rubric:: Notes - Input `data` must be background-subtracted prior to calling this function. - The Gaussian kernel is constructed with FWHM = 9 pixels (`sigma = 9 × gaussian_fwhm_to_sigma`) and size `kernel_size × kernel_size`. - If `deblend=True`, `photutils.segmentation.deblend_sources` is applied to split overlapping sources. .. py:function:: get_segmentation(data, nsig, *, xpix=100, ypix=100, size=100, median_bkg=None, kernel_size=21, deblend=False, r_in=20, r_out=35, npixels=9, connectivity=8, invert=False, threshold=10) Extract the segmentation map of a single central object in a postage stamp. A square cutout is taken around `(xpix, ypix)` (or the frame center if unspecified), background-subtracted, and segmented using `segm_find`. Central validation matches `morph_parameters` behavior: * If `threshold == 0`, require the exact central pixel to belong to a segmented object. * If `threshold > 0`, require that at least one segmented pixel lies within a central circular mask of radius `threshold`, then select the object whose centroid is **closest to the center** (from all segments). If validation fails, a zero array is returned. :param data: 2D image array. :type data: ndarray :param nsig: Detection threshold in units of background sigma (passed to `segm_find`). :type nsig: float :param xpix: Central pixel coordinates of the target object. If both are None, the image center is used. Default is 100 each. :type xpix: int or None, optional :param ypix: Central pixel coordinates of the target object. If both are None, the image center is used. Default is 100 each. :type ypix: int or None, optional :param size: Side length (pixels) of the square cutout. If larger than the image dimensions, reduced to fit. Default is 100. :type size: int, optional :param median_bkg: Background estimate for the cutout. If None, a local annulus (radii `r_in`, `r_out`) is used. If 0, no subtraction is applied. Default is None. :type median_bkg: float or None, optional :param kernel_size: Size (pixels) of Gaussian kernel used in `segm_find`. Default is 21. :type kernel_size: int, optional :param deblend: If True, deblend overlapping sources in the segmentation map. Default is False. :type deblend: bool, optional :param r_in: Inner and outer radii (pixels) of the annulus used for local background estimation when `median_bkg` is None. Defaults are 20 and 35. :type r_in: int, optional :param r_out: Inner and outer radii (pixels) of the annulus used for local background estimation when `median_bkg` is None. Defaults are 20 and 35. :type r_out: int, optional :param npixels: Minimum number of connected pixels above threshold required for detection (passed to `segm_find`). Default is 9. :type npixels: int, optional :param connectivity: Pixel connectivity: 4 (edge-connected) or 8 (edge+corner-connected). Default is 8. :type connectivity: int, optional :param invert: If True, swap (x, y) ordering when cropping. Default is False. :type invert: bool, optional :param threshold: Central validation parameter (pixels). See behavior above. Default is 10. :type threshold: int, optional :returns: **seg** -- Segmentation map of shape `(size, size)` with only the selected object retained (nonzero label). If validation fails, a zero array is returned. :rtype: ndarray .. py:function:: compute_layered_segmentation(image, sigma_values, pix_conversion, xpix, ypix, size, *, median_bkg=None, kernel_size=21, deblend=False, r_in=20, r_out=35, npixels=9, connectivity=8, threshold=10) Generate a layered segmentation map across multiple detection thresholds. For each sigma threshold in `sigma_values`, `get_segmentation` is called to isolate the central source in a postage stamp. The resulting masks are stacked into a single 2D array, with different intensity values assigned to each layer. Higher sigma thresholds receive larger intensity values, creating a graded segmentation useful for visualization and contouring. :param image: 2D image array. :type image: ndarray :param sigma_values: Detection thresholds (in sigma) to apply sequentially. Each value is passed as `nsig` to `get_segmentation`. :type sigma_values: sequence of float :param pix_conversion: Pixel-to-arcsecond (or other physical unit) conversion factor. Currently unused internally, but included for consistency with downstream plotting routines. :type pix_conversion: float :param xpix: Pixel coordinates of the central source. :type xpix: int :param ypix: Pixel coordinates of the central source. :type ypix: int :param size: Side length (pixels) of the square cutout to extract. :type size: int :param median_bkg: Background estimate for the cutout. If None, a local annulus (radii `r_in`, `r_out`) is used. If 0, no subtraction is applied. Default is None. :type median_bkg: float or None, optional :param kernel_size: Gaussian kernel size (pixels) used for segmentation convolution. Default is 21. :type kernel_size: int, optional :param deblend: If True, apply deblending to split overlapping sources. Default is False. :type deblend: bool, optional :param r_in: Inner and outer radii (pixels) for annular background estimation if `median_bkg` is None. Defaults are 20 and 35. :type r_in: int, optional :param r_out: Inner and outer radii (pixels) for annular background estimation if `median_bkg` is None. Defaults are 20 and 35. :type r_out: int, optional :param npixels: Minimum number of connected pixels above threshold to define a source. Default is 9. :type npixels: int, optional :param connectivity: Pixel connectivity (4 or 8). Default is 8. :type connectivity: int, optional :param threshold: Central circular mask radius (pixels) used in `get_segmentation` to enforce detection near the cutout center. Default is 10. :type threshold: int, optional :returns: **layered** -- Composite segmentation map. Pixels belonging to a detection at the i-th sigma level are assigned intensity values: [1.0, 0.7, 0.4, 0.1] (truncated to the number of sigma levels). Higher sigma levels correspond to higher intensities. :rtype: ndarray of float, shape (size, size) .. rubric:: Notes - If fewer than four sigma values are provided, only the corresponding fraction of the default intensity sequence is used. - If more than four sigma values are provided, only the first four are represented (later thresholds are ignored). - This function is designed primarily for visualization (e.g., multi-level contours), not for quantitative feature extraction. .. py:function:: get_extent(img: numpy.ndarray, pix_conversion: float) Compute the spatial extent of an image for `matplotlib.imshow`. The extent is centered on (0, 0) and converted from pixels to arcseconds (or other physical units) using the provided pixel-to-unit conversion. :param img: 2D image array. :type img: ndarray :param pix_conversion: Pixel scale conversion factor (pixels per arcsecond, or pixels per unit). The returned extent is expressed in the reciprocal units (e.g., arcsec). :type pix_conversion: float :returns: **extent** -- Extent values suitable for passing to `imshow(extent=...)`, with coordinates centered on (0, 0). :rtype: list of float [xmin, xmax, ymin, ymax] .. rubric:: Notes - The extent is computed as: ``x = (arange(width) - width/2) / pix_conversion``, ``y = (arange(height) - height/2) / pix_conversion``. - Units depend on `pix_conversion`: for example, if `pix_conversion = 3.8961` pixels per arcsec, then the output extent is in arcseconds. .. py:function:: get_display_limits(img: numpy.ndarray) Compute robust display limits for image visualization. The limits are based on the median and median absolute deviation (MAD) of finite pixels in the image, providing a stretch that is less sensitive to outliers than standard min/max scaling. :param img: 2D image array. Non-finite values (NaN, inf) are ignored. :type img: ndarray :returns: **vmin, vmax** -- Lower and upper display limits, defined as: ``vmin = median - 3 * MAD`` ``vmax = median + 10 * MAD`` :rtype: float .. rubric:: Notes - This stretch is useful for displaying faint, extended features while suppressing noise and extreme outliers. - MAD is defined as ``median(|x - median(x)|)``. - The asymmetric scaling (-3 × MAD, +10 × MAD) biases toward emphasizing positive flux features. .. py:function:: plot_objects_segmentation(*images, pix_conversion=1.0, sigma_values=(0.1, 0.25, 0.55, 0.95), titles=None, suptitle='', xpix=None, ypix=None, size=None, median_bkg=None, kernel_size=21, deblend=False, r_in=20, r_out=35, npixels=9, connectivity=8, threshold=10, cmap='viridis', savepath='segm_multi.png', savefig=True) Plot images alongside layered segmentation masks. Each input image is displayed in the top row, with its corresponding layered segmentation map (computed from `sigma_values`) displayed directly below. This provides a side-by-side visualization of raw data and threshold-dependent segmentation. :param \*images: One or more 2D image arrays. Between 1 and 5 are allowed. :type \*images: ndarray :param pix_conversion: Pixel-to-arcsecond (or other unit) conversion factor. Used to compute axis extents. Default is 1.0. :type pix_conversion: float, optional :param sigma_values: Detection thresholds (in sigma) for layered segmentation. Default is (0.1, 0.25, 0.55, 0.95). :type sigma_values: sequence of float, optional :param titles: Titles for each image panel (top row). Length must match number of images. Default is no titles. :type titles: list of str or None, optional :param suptitle: Figure-wide title. Default is "". :type suptitle: str, optional :param xpix: Central pixel coordinates for cropping. If all of `xpix`, `ypix`, and `size` are given, each image is cropped to that region before plotting. Default is None. :type xpix: int or None, optional :param ypix: Central pixel coordinates for cropping. If all of `xpix`, `ypix`, and `size` are given, each image is cropped to that region before plotting. Default is None. :type ypix: int or None, optional :param size: Side length (pixels) of cropped cutouts, if cropping is applied. Default is None (no cropping). :type size: int or None, optional :param median_bkg: Background estimate for segmentation. If None, background is estimated locally via annuli of radii `r_in` and `r_out`. If 0, no subtraction is applied. Default is None. :type median_bkg: float or None, optional :param kernel_size: Gaussian kernel size (pixels) for segmentation convolution. Default is 21. :type kernel_size: int, optional :param deblend: If True, split overlapping sources during segmentation. Default is False. :type deblend: bool, optional :param r_in: Inner and outer radii (pixels) for annular background estimation. Defaults are 20 and 35. :type r_in: int, optional :param r_out: Inner and outer radii (pixels) for annular background estimation. Defaults are 20 and 35. :type r_out: int, optional :param npixels: Minimum connected pixel area (pixels) required for detection. Default is 9. :type npixels: int, optional :param connectivity: Pixel connectivity: 4 (edge-connected) or 8 (edge+corner-connected). Default is 8. :type connectivity: int, optional :param threshold: Central circular mask radius (pixels) used to validate detections during segmentation. Default is 10. :type threshold: int, optional :param cmap: Matplotlib colormap for displaying the original images. Default is "viridis". :type cmap: str, optional :param savepath: Output path for saving the figure when `savefig=True`. Default is "segm_multi.png". :type savepath: str, optional :param savefig: If True, save the figure to `savepath`. If False, display with `plt.show()`. Default is True. :type savefig: bool, optional :returns: Displays or saves the figure. Does not return a DataFrame or array. :rtype: None .. rubric:: Notes - A maximum of 5 images may be passed at once. - Each figure has two rows: raw images (top) and layered segmentation masks (bottom). - A legend indicates which intensity levels correspond to the `sigma_values` used in layered segmentation. - Axis labels are expressed in arcseconds if `pix_conversion` is given in pixels per arcsecond. .. py:function:: plot_images_grid_2x2(img1, img2, img3, img4, *, pix_conversion=1.0, titles=None, suptitle='', xpix=None, ypix=None, size=None, cmap='viridis', savepath='outliers.png', savefig=True) Display four images in a 2×2 grid with consistent visualization settings. This function mirrors the style of the *image panels* from `plot_objects_segmentation`: identical extent handling, robust (median±MAD) display limits, axis labeling, spacing, and aesthetics. Useful for side-by-side comparison of four sources or cutouts. :param img1: Four 2D image arrays to display. :type img1: ndarray :param img2: Four 2D image arrays to display. :type img2: ndarray :param img3: Four 2D image arrays to display. :type img3: ndarray :param img4: Four 2D image arrays to display. :type img4: ndarray :param pix_conversion: Pixel-to-arcsecond (or other unit) conversion factor. Passed to `get_extent`. Default is 1.0. :type pix_conversion: float, optional :param titles: Titles for the four panels, in row-major order ([top-left, top-right, bottom-left, bottom-right]). Must be length 4. Default is None (no titles). :type titles: list of str or None, optional :param suptitle: Figure-level title. Default is "". :type suptitle: str, optional :param xpix: If all three are provided, each image is cropped to a square cutout using `data_processing.crop_image(img, xpix, ypix, size)`. Default is None (no cropping). :type xpix: int or None, optional :param ypix: If all three are provided, each image is cropped to a square cutout using `data_processing.crop_image(img, xpix, ypix, size)`. Default is None (no cropping). :type ypix: int or None, optional :param size: If all three are provided, each image is cropped to a square cutout using `data_processing.crop_image(img, xpix, ypix, size)`. Default is None (no cropping). :type size: int or None, optional :param cmap: Matplotlib colormap for images. Default is "viridis". :type cmap: str, optional :param savepath: Output file path if saving the figure. Default is "outliers.png". :type savepath: str, optional :param savefig: If True, save the figure to `savepath`. If False, display the figure interactively with `plt.show()`. Default is True. :type savefig: bool, optional :returns: Displays or saves the figure. Does not return arrays or DataFrames. :rtype: None .. rubric:: Notes - Each panel is flipped vertically (consistent with other plotting functions in this module) and labeled in arcseconds relative to the cutout center. - Robust display scaling is applied via `get_display_limits`. - Grid layout uses equal spacing (no white space between panels). .. py:function:: align_error_array(data, error, data_coords, error_coords) Align an error map with a data array by shifting and padding. This function shifts the error array so that a reference object (identified by coordinates in both arrays) is aligned, then pads or crops as needed to match the shape of `data`. Useful when error maps (e.g., rms images) are offset relative to science images due to inconsistent sizes or coordinate origins. :param data: Target 2D science image array. :type data: ndarray :param error: Error map (e.g., rms image) to align with `data`. :type error: ndarray :param data_coords: (x, y) pixel coordinates of a reference object in `data`. :type data_coords: tuple of int :param error_coords: (x, y) pixel coordinates of the same object in `error`. :type error_coords: tuple of int :returns: **padded_error** -- Error array aligned and padded/cropped to the same shape as `data`. Non-overlapping regions are filled with zeros. :rtype: ndarray .. rubric:: Notes - This approach assumes both arrays are on the same pixel grid up to an integer shift, and does not perform interpolation. - Alignment is determined by the relative offset between `data_coords` and `error_coords`. - This was originally motivated by the NDWFS Boötes R-band data, where rms maps and images had inconsistent dimensions. In general, a WCS-based solution (via `astropy.wcs`) may be preferable if RA/Dec information is available.