From f89ce551f35c74eab9e80d2621dc33933b380ff7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 19:34:55 +0000
Subject: [PATCH 01/16] Initial plan
From d5f93f6ec42c08b1edfbeaa40d54b9ed3a4e86cc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 20:00:50 +0000
Subject: [PATCH 02/16] Improve docstrings: RST format, combine_docstrings,
description keys, autodoc structure
- Rewrite combine_docstrings decorator to merge params from full MRO
- Add _parse_docstring helper supporting both RST and markdown formats
- Convert model/mixin docstrings from markdown to RST format
- Convert block math $$...$$ to .. math:: directives
- Convert inline math $expr$ to :math:`expr`
- Add description keys to all _parameter_specs dicts
- Apply combine_docstrings to auto-generated types in radial.py/radial_psf.py
- Update docs structure to use sphinx autodoc
- Remove make_docs.py (replaced by autodoc approach)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
astrophot/models/airy.py | 47 ++++--
astrophot/models/bilinear_sky.py | 28 ++-
astrophot/models/edgeon.py | 37 ++--
astrophot/models/flatsky.py | 12 +-
astrophot/models/gaussian_ellipsoid.py | 49 ++++--
astrophot/models/mixins/brightness.py | 42 +++--
astrophot/models/mixins/exponential.py | 78 ++++++---
astrophot/models/mixins/ferrer.py | 142 ++++++++++++----
astrophot/models/mixins/gaussian.py | 86 +++++++---
astrophot/models/mixins/king.py | 134 +++++++++++----
astrophot/models/mixins/moffat.py | 106 +++++++++---
astrophot/models/mixins/nuker.py | 169 ++++++++++++++-----
astrophot/models/mixins/sersic.py | 122 +++++++++----
astrophot/models/mixins/spline.py | 48 +++---
astrophot/models/mixins/transform.py | 134 ++++++++++-----
astrophot/models/model_object.py | 18 +-
astrophot/models/multi_gaussian_expansion.py | 39 +++--
astrophot/models/pixelated_model.py | 28 ++-
astrophot/models/pixelated_psf.py | 12 +-
astrophot/models/planesky.py | 27 ++-
astrophot/models/point_source.py | 11 +-
astrophot/models/psf_model_object.py | 14 +-
astrophot/models/radial.py | 25 +--
astrophot/models/radial_psf.py | 13 +-
astrophot/utils/decorators.py | 81 ++++++++-
docs/source/_config.yml | 46 +----
docs/source/astrophotdocs/errors.rst | 7 +
docs/source/astrophotdocs/fit.rst | 7 +
docs/source/astrophotdocs/image.rst | 7 +
docs/source/astrophotdocs/index.rst | 28 ++-
docs/source/astrophotdocs/models.rst | 87 ++++++++++
docs/source/astrophotdocs/plots.rst | 7 +
docs/source/astrophotdocs/utils.rst | 7 +
make_docs.py | 103 -----------
34 files changed, 1222 insertions(+), 579 deletions(-)
create mode 100644 docs/source/astrophotdocs/errors.rst
create mode 100644 docs/source/astrophotdocs/fit.rst
create mode 100644 docs/source/astrophotdocs/image.rst
create mode 100644 docs/source/astrophotdocs/models.rst
create mode 100644 docs/source/astrophotdocs/plots.rst
create mode 100644 docs/source/astrophotdocs/utils.rst
delete mode 100644 make_docs.py
diff --git a/astrophot/models/airy.py b/astrophot/models/airy.py
index 0619c2dd..6e93cd2e 100644
--- a/astrophot/models/airy.py
+++ b/astrophot/models/airy.py
@@ -19,34 +19,49 @@ class AiryPSF(RadialMixin, PSFModel):
of the lens system under the assumption that all elements are
perfect. This expression goes as:
- $$I(\\theta) = I_0\\left[\\frac{2J_1(x)}{x}\\right]^2$$
- $$x = ka\\sin(\\theta) = \\frac{2\\pi a r}{\\lambda R}$$
+ .. math::
- where $I(\\theta)$ is the intensity as a function of the
+ I(\\theta) = I_0\\left[\\frac{2J_1(x)}{x}\\right]^2
+
+ .. math::
+
+ x = ka\\sin(\\theta) = \\frac{2\\pi a r}{\\lambda R}
+
+ where :math:`I(\\theta)` is the intensity as a function of the
angular position within the diffraction system along its main
- axis, $I_0$ is the central intensity of the airy disk,
- $J_1$ is the Bessel function of the first kind of order one,
- $k = \\frac{2\\pi}{\\lambda}$ is the wavenumber of the
- light, $a$ is the aperture radius, $r$ is the radial
- position from the center of the pattern, $R$ is the distance
+ axis, :math:`I_0` is the central intensity of the airy disk,
+ :math:`J_1` is the Bessel function of the first kind of order one,
+ :math:`k = \\frac{2\\pi}{\\lambda}` is the wavenumber of the
+ light, :math:`a` is the aperture radius, :math:`r` is the radial
+ position from the center of the pattern, :math:`R` is the distance
from the circular aperture to the observation plane.
- In the `Airy_PSF` class we combine the parameters
- $a,R,\\lambda$ into a single ratio to be optimized (or fixed
+ In the ``Airy_PSF`` class we combine the parameters
+ :math:`a,R,\\lambda` into a single ratio to be optimized (or fixed
by the optical configuration).
- **Parameters:**
- - `I0`: The central intensity of the airy disk in flux/arcsec^2.
- - `aRL`: The ratio of the aperture radius to the
+ :param I0: The central intensity of the airy disk in flux/arcsec^2.
+ :param aRL: The ratio of the aperture radius to the
product of the wavelength and the distance from the aperture to the
- observation plane, $\\frac{a}{R \\lambda}$.
+ observation plane, :math:`\\frac{a}{R \\lambda}`.
"""
_model_type = "airy"
_parameter_specs = {
- "I0": {"units": "flux/arcsec^2", "value": 1.0, "shape": (), "dynamic": False},
- "aRL": {"units": "a/(R lambda)", "shape": (), "dynamic": True},
+ "I0": {
+ "units": "flux/arcsec^2",
+ "value": 1.0,
+ "shape": (),
+ "dynamic": False,
+ "description": "The central intensity of the airy disk in flux/arcsec^2.",
+ },
+ "aRL": {
+ "units": "a/(R lambda)",
+ "shape": (),
+ "dynamic": True,
+ "description": "The ratio of the aperture radius to the product of the wavelength and the distance from the aperture to the observation plane.",
+ },
}
usable = True
diff --git a/astrophot/models/bilinear_sky.py b/astrophot/models/bilinear_sky.py
index abf2ad3b..2d24bfc8 100644
--- a/astrophot/models/bilinear_sky.py
+++ b/astrophot/models/bilinear_sky.py
@@ -17,18 +17,32 @@
class BilinearSky(SkyModel):
"""Sky background model using a coarse bilinear grid for the sky flux.
- **Parameters:**
- - `I`: sky brightness grid
- - `PA`: position angle of the sky grid in radians.
- - `scale`: scale of the sky grid in arcseconds per grid unit.
+ :param I: sky brightness grid
+ :param PA: position angle of the sky grid in radians.
+ :param scale: scale of the sky grid in arcseconds per grid unit.
"""
_model_type = "bilinear"
_parameter_specs = {
- "I": {"units": "flux/arcsec^2", "shape": (None, None), "dynamic": True},
- "PA": {"units": "radians", "shape": (), "dynamic": True},
- "scale": {"units": "arcsec/grid-unit", "shape": (), "dynamic": True},
+ "I": {
+ "units": "flux/arcsec^2",
+ "shape": (None, None),
+ "dynamic": True,
+ "description": "sky brightness grid",
+ },
+ "PA": {
+ "units": "radians",
+ "shape": (),
+ "dynamic": True,
+ "description": "position angle of the sky grid in radians",
+ },
+ "scale": {
+ "units": "arcsec/grid-unit",
+ "shape": (),
+ "dynamic": True,
+ "description": "scale of the sky grid in arcseconds per grid unit",
+ },
}
usable = True
diff --git a/astrophot/models/edgeon.py b/astrophot/models/edgeon.py
index 115e2334..15a5e7fa 100644
--- a/astrophot/models/edgeon.py
+++ b/astrophot/models/edgeon.py
@@ -17,8 +17,7 @@ class EdgeonModel(ComponentModel):
the galaxy on the sky. Defines an edgeon galaxy as an object with
a position angle, no inclination information is included.
- **Parameters:**
- - `PA`: Position angle of the edgeon disk in radians.
+ :param PA: Position angle of the edgeon disk in radians.
"""
@@ -30,6 +29,7 @@ class EdgeonModel(ComponentModel):
"cyclic": True,
"shape": (),
"dynamic": True,
+ "description": "Position angle of the edgeon disk in radians.",
},
}
usable = False
@@ -73,15 +73,25 @@ class EdgeonSech(EdgeonModel):
"""An edgeon profile where the vertical distribution is a sech^2
profile, subclasses define the radial profile.
- **Parameters:**
- - `I0`: The central intensity of the sech^2 profile in flux/arcsec^2.
- - `hs`: The scale height of the sech^2 profile in arcseconds.
+ :param I0: The central intensity of the sech^2 profile in flux/arcsec^2.
+ :param hs: The scale height of the sech^2 profile in arcseconds.
"""
_model_type = "sech2"
_parameter_specs = {
- "I0": {"units": "flux/arcsec^2", "shape": (), "dynamic": True},
- "hs": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
+ "I0": {
+ "units": "flux/arcsec^2",
+ "shape": (),
+ "dynamic": True,
+ "description": "The central intensity of the sech^2 profile in flux/arcsec^2.",
+ },
+ "hs": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "The scale height of the sech^2 profile in arcseconds.",
+ },
}
usable = False
@@ -114,12 +124,19 @@ class EdgeonIsothermal(EdgeonSech):
"""A self-gravitating locally-isothermal edgeon disk. This comes from
van der Kruit & Searle 1981.
- **Parameters:**
- - `rs`: Scale radius of the isothermal disk in arcseconds.
+ :param rs: Scale radius of the isothermal disk in arcseconds.
"""
_model_type = "isothermal"
- _parameter_specs = {"rs": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True}}
+ _parameter_specs = {
+ "rs": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Scale radius of the isothermal disk in arcseconds.",
+ }
+ }
usable = True
@torch.no_grad()
diff --git a/astrophot/models/flatsky.py b/astrophot/models/flatsky.py
index fdb3e50c..5c2c19a1 100644
--- a/astrophot/models/flatsky.py
+++ b/astrophot/models/flatsky.py
@@ -14,13 +14,19 @@ class FlatSky(SkyModel):
"""Model for the sky background in which all values across the image
are the same.
- **Parameters:**
- - `I0`: brightness for the sky, represented as the log of the brightness over pixel scale squared, this is proportional to a surface brightness
+ :param I0: brightness for the sky, represented as the log of the brightness over pixel scale squared, this is proportional to a surface brightness
"""
_model_type = "flat"
- _parameter_specs = {"I0": {"units": "flux/arcsec^2", "shape": (), "dynamic": True}}
+ _parameter_specs = {
+ "I0": {
+ "units": "flux/arcsec^2",
+ "shape": (),
+ "dynamic": True,
+ "description": "brightness for the sky, proportional to a surface brightness",
+ }
+ }
usable = True
@torch.no_grad()
diff --git a/astrophot/models/gaussian_ellipsoid.py b/astrophot/models/gaussian_ellipsoid.py
index 23fab669..6399e599 100644
--- a/astrophot/models/gaussian_ellipsoid.py
+++ b/astrophot/models/gaussian_ellipsoid.py
@@ -38,28 +38,46 @@ class GaussianEllipsoid(ComponentModel):
initialization for this model assumes exactly this interpretation with a
disk thickness of sigma_c = 0.2 *sigma_a.
- **Parameters:**
- - `sigma_a`: Standard deviation of the Gaussian along the alpha axis in arcseconds.
- - `sigma_b`: Standard deviation of the Gaussian along the beta axis in arcseconds.
- - `sigma_c`: Standard deviation of the Gaussian along the gamma axis in arcseconds.
- - `alpha`: Euler angle representing the rotation around the alpha axis in radians.
- - `beta`: Euler angle representing the rotation around the beta axis in radians.
- - `gamma`: Euler angle representing the rotation around the gamma axis in radians.
- - `flux`: Total flux of the galaxy in arbitrary units.
+ :param sigma_a: Standard deviation of the Gaussian along the alpha axis in arcseconds.
+ :param sigma_b: Standard deviation of the Gaussian along the beta axis in arcseconds.
+ :param sigma_c: Standard deviation of the Gaussian along the gamma axis in arcseconds.
+ :param alpha: Euler angle representing the rotation around the alpha axis in radians.
+ :param beta: Euler angle representing the rotation around the beta axis in radians.
+ :param gamma: Euler angle representing the rotation around the gamma axis in radians.
+ :param flux: Total flux of the galaxy in arbitrary units.
"""
_model_type = "gaussianellipsoid"
_parameter_specs = {
- "sigma_a": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "sigma_b": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "sigma_c": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
+ "sigma_a": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Standard deviation of the Gaussian along the alpha axis in arcseconds.",
+ },
+ "sigma_b": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Standard deviation of the Gaussian along the beta axis in arcseconds.",
+ },
+ "sigma_c": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Standard deviation of the Gaussian along the gamma axis in arcseconds.",
+ },
"alpha": {
"units": "radians",
"valid": (0, 2 * np.pi),
"cyclic": True,
"shape": (),
"dynamic": True,
+ "description": "Euler angle representing the rotation around the alpha axis in radians.",
},
"beta": {
"units": "radians",
@@ -67,6 +85,7 @@ class GaussianEllipsoid(ComponentModel):
"cyclic": True,
"shape": (),
"dynamic": True,
+ "description": "Euler angle representing the rotation around the beta axis in radians.",
},
"gamma": {
"units": "radians",
@@ -74,8 +93,14 @@ class GaussianEllipsoid(ComponentModel):
"cyclic": True,
"shape": (),
"dynamic": True,
+ "description": "Euler angle representing the rotation around the gamma axis in radians.",
+ },
+ "flux": {
+ "units": "flux",
+ "shape": (),
+ "dynamic": True,
+ "description": "Total flux of the galaxy in arbitrary units.",
},
- "flux": {"units": "flux", "shape": (), "dynamic": True},
}
usable = True
diff --git a/astrophot/models/mixins/brightness.py b/astrophot/models/mixins/brightness.py
index 168ab77c..ce08670f 100644
--- a/astrophot/models/mixins/brightness.py
+++ b/astrophot/models/mixins/brightness.py
@@ -6,20 +6,28 @@
class RadialMixin:
- """This model defines its `brightness(x,y)` function using a radial model.
- Thus the brightness is instead defined as`radial_model(R)`
+ """This model defines its ``brightness(x,y)`` function using a radial model.
+ Thus the brightness is instead defined as ``radial_model(R)``
More specifically the function is:
- $$x, y = {\\rm transform\\_coordinates}(x, y)$$
- $$R = {\\rm radius\\_metric}(x, y)$$
- $$I(x, y) = {\\rm radial\\_model}(R)$$
+ .. math::
- The `transform_coordinates` function depends on the model. In its simplest
+ x, y = {\\rm transform\\_coordinates}(x, y)
+
+ .. math::
+
+ R = {\\rm radius\\_metric}(x, y)
+
+ .. math::
+
+ I(x, y) = {\\rm radial\\_model}(R)
+
+ The ``transform_coordinates`` function depends on the model. In its simplest
form it simply subtracts the center of the model to re-center the coordinates.
- The `radius_metric` function is also model dependent, in its simplest form
- this is just $R = \\sqrt{x^2 + y^2}$.
+ The ``radius_metric`` function is also model dependent, in its simplest form
+ this is just :math:`R = \\sqrt{x^2 + y^2}`.
"""
@forward
@@ -37,11 +45,10 @@ class WedgeMixin:
model which defines multiple radial models separately along some number of
wedges projected from the center. These wedges have sharp transitions along boundary angles theta.
- **Options:**
- - `symmetric`: If True, the model will have symmetry for rotations of pi radians
+ :param symmetric: If True, the model will have symmetry for rotations of pi radians
and each ray will appear twice on the sky on opposite sides of the model.
If False, each ray is independent.
- - `segments`: The number of segments to divide the model into. This controls
+ :param segments: The number of segments to divide the model into. This controls
how many rays are used in the model. The default is 2
"""
@@ -78,16 +85,17 @@ class RayMixin:
function which depends on the number of rays, for example with two rays the
brightness would be:
- $$I(R,\\theta) = I_1(R)*\\cos(\\theta \\% \\pi) + I_2(R)*\\cos((\\theta + \\pi/2) \\% \\pi)$$
+ .. math::
+
+ I(R,\\theta) = I_1(R)*\\cos(\\theta \\% \\pi) + I_2(R)*\\cos((\\theta + \\pi/2) \\% \\pi)
- For $\\theta = 0$ the brightness comes entirely from `I_1` while for $\\theta = \\pi/2$
- the brightness comes entirely from `I_2`.
+ For :math:`\\theta = 0` the brightness comes entirely from ``I_1`` while for :math:`\\theta = \\pi/2`
+ the brightness comes entirely from ``I_2``.
- **Options:**
- - `symmetric`: If True, the model will have symmetry for rotations of pi radians
+ :param symmetric: If True, the model will have symmetry for rotations of pi radians
and each ray will appear twice on the sky on opposite sides of the model.
If False, each ray is independent.
- - `segments`: The number of segments to divide the model into. This controls
+ :param segments: The number of segments to divide the model into. This controls
how many rays are used in the model. The default is 2
"""
diff --git a/astrophot/models/mixins/exponential.py b/astrophot/models/mixins/exponential.py
index 89da767d..f7bf8d83 100644
--- a/astrophot/models/mixins/exponential.py
+++ b/astrophot/models/mixins/exponential.py
@@ -18,20 +18,33 @@ class ExponentialMixin:
An exponential is a classical radial model used in many contexts. The
functional form of the exponential profile is defined as:
- $$I(R) = I_e * \\exp\\left(- b_1\\left(\\frac{R}{R_e} - 1\\right)\\right)$$
+ .. math::
+
+ I(R) = I_e \\exp\\left(- b_1\\left(\\frac{R}{R_e} - 1\\right)\\right)
Ie is the brightness at the effective radius, and Re is the effective
- radius. $b_1$ is a constant that ensures $I_e$ is the brightness at $R_e$.
+ radius. :math:`b_1` is a constant that ensures :math:`I_e` is the brightness at :math:`R_e`.
- **Parameters:**
- - `Re`: effective radius in arcseconds
- - `Ie`: effective surface density in flux/arcsec^2
+ :param Re: effective radius in arcseconds
+ :param Ie: effective surface density in flux/arcsec^2
"""
_model_type = "exponential"
_parameter_specs = {
- "Re": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "Ie": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (), "dynamic": True},
+ "Re": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "effective radius in arcseconds",
+ },
+ "Ie": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "effective surface density in flux/arcsec^2",
+ },
}
@torch.no_grad()
@@ -58,23 +71,36 @@ class iExponentialMixin:
An exponential is a classical radial model used in many contexts. The
functional form of the exponential profile is defined as:
- $$I(R) = I_e * \\exp\\left(- b_1\\left(\\frac{R}{R_e} - 1\\right)\\right)$$
+ .. math::
+
+ I(R) = I_e \\exp\\left(- b_1\\left(\\frac{R}{R_e} - 1\\right)\\right)
- $I_e$ is the brightness at the effective radius, and $R_e$ is the effective
- radius. $b_1$ is a constant that ensures $I_e$ is the brightness at $R_e$.
+ :math:`I_e` is the brightness at the effective radius, and :math:`R_e` is the effective
+ radius. :math:`b_1` is a constant that ensures :math:`I_e` is the brightness at :math:`R_e`.
- `Re` and `Ie` are batched by their first dimension, allowing for multiple
+ ``Re`` and ``Ie`` are batched by their first dimension, allowing for multiple
exponential profiles to be defined at once.
- **Parameters:**
- - `Re`: effective radius in arcseconds
- - `Ie`: effective surface density in flux/arcsec^2
+ :param Re: effective radius in arcseconds
+ :param Ie: effective surface density in flux/arcsec^2
"""
_model_type = "exponential"
_parameter_specs = {
- "Re": {"units": "arcsec", "valid": (0, None), "shape": (None,), "dynamic": True},
- "Ie": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (None,), "dynamic": True},
+ "Re": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "effective radius in arcseconds",
+ },
+ "Ie": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "effective surface density in flux/arcsec^2",
+ },
}
@torch.no_grad()
@@ -102,25 +128,33 @@ class ExponentialPSFMixin:
An exponential is a classical radial model used in many contexts. The
functional form of the exponential profile is defined as:
- $$I(R) = I_e * \\exp\\left(- b_1\\left(\\frac{R}{R_e} - 1\\right)\\right)$$
+ .. math::
+
+ I(R) = I_e \\exp\\left(- b_1\\left(\\frac{R}{R_e} - 1\\right)\\right)
Ie is the brightness at the effective radius, and Re is the effective
- radius. $b_1$ is a constant that ensures $I_e$ is the brightness at $R_e$.
+ radius. :math:`b_1` is a constant that ensures :math:`I_e` is the brightness at :math:`R_e`.
- **Parameters:**
- - `Re`: effective radius in pixels
- - `Ie`: effective surface density in flux/pix^2
+ :param Re: effective radius in pixels
+ :param Ie: effective surface density in flux/pix^2
"""
_model_type = "exponential"
_parameter_specs = {
- "Re": {"units": "pix", "valid": (0, None), "shape": (), "dynamic": True},
+ "Re": {
+ "units": "pix",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "effective radius in pixels",
+ },
"Ie": {
"units": "flux/pix^2",
"valid": (0, None),
"shape": (),
"dynamic": False,
"value": 1.0,
+ "description": "effective surface density in flux/pix^2",
},
}
diff --git a/astrophot/models/mixins/ferrer.py b/astrophot/models/mixins/ferrer.py
index 27a24932..315c38ce 100644
--- a/astrophot/models/mixins/ferrer.py
+++ b/astrophot/models/mixins/ferrer.py
@@ -19,25 +19,50 @@ class FerrerMixin:
is used in specialized circumstances such as fitting the bar of a galaxy.
The functional form of the Modified Ferrer profile is defined as:
- $$I(R) = I_0 \\left(1 - \\left(\\frac{R}{r_{\\rm out}}\\right)^{2-\\beta}\\right)^{\\alpha}$$
+ .. math::
- where `rout` is the outer truncation radius, `alpha` controls the steepness
- of the truncation, `beta` controls the shape, and `I0` is the intensity at
+ I(R) = I_0 \\left(1 - \\left(\\frac{R}{r_{\\rm out}}\\right)^{2-\\beta}\\right)^{\\alpha}
+
+ where ``rout`` is the outer truncation radius, ``alpha`` controls the steepness
+ of the truncation, ``beta`` controls the shape, and ``I0`` is the intensity at
the center of the profile.
- **Parameters:**
- - `rout`: Outer truncation radius in arcseconds.
- - `alpha`: Inner slope parameter.
- - `beta`: Outer slope parameter.
- - `I0`: Intensity at the center of the profile in flux/arcsec^2
+ :param rout: Outer truncation radius in arcseconds.
+ :param alpha: Inner slope parameter.
+ :param beta: Outer slope parameter.
+ :param I0: Intensity at the center of the profile in flux/arcsec^2
"""
_model_type = "ferrer"
_parameter_specs = {
- "rout": {"units": "arcsec", "valid": (0.0, None), "shape": (), "dynamic": True},
- "alpha": {"units": "unitless", "valid": (0, 10), "shape": (), "dynamic": True},
- "beta": {"units": "unitless", "valid": (0, 2), "shape": (), "dynamic": True},
- "I0": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (), "dynamic": True},
+ "rout": {
+ "units": "arcsec",
+ "valid": (0.0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Outer truncation radius in arcseconds.",
+ },
+ "alpha": {
+ "units": "unitless",
+ "valid": (0, 10),
+ "shape": (),
+ "dynamic": True,
+ "description": "Inner slope parameter.",
+ },
+ "beta": {
+ "units": "unitless",
+ "valid": (0, 2),
+ "shape": (),
+ "dynamic": True,
+ "description": "Outer slope parameter.",
+ },
+ "I0": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Intensity at the center of the profile in flux/arcsec^2",
+ },
}
@torch.no_grad()
@@ -67,28 +92,53 @@ class iFerrerMixin:
is used in specialized circumstances such as fitting the bar of a galaxy.
The functional form of the Modified Ferrer profile is defined as:
- $$I(R) = I_0 \\left(1 - \\left(\\frac{R}{r_{\\rm out}}\\right)^{2-\\beta}\\right)^{\\alpha}$$
+ .. math::
+
+ I(R) = I_0 \\left(1 - \\left(\\frac{R}{r_{\\rm out}}\\right)^{2-\\beta}\\right)^{\\alpha}
- where `rout` is the outer truncation radius, `alpha` controls the steepness
- of the truncation, `beta` controls the shape, and `I0` is the intensity at
+ where ``rout`` is the outer truncation radius, ``alpha`` controls the steepness
+ of the truncation, ``beta`` controls the shape, and ``I0`` is the intensity at
the center of the profile.
- `rout`, `alpha`, `beta`, and `I0` are batched by their first dimension,
+ ``rout``, ``alpha``, ``beta``, and ``I0`` are batched by their first dimension,
allowing for multiple Ferrer profiles to be defined at once.
- **Parameters:**
- - `rout`: Outer truncation radius in arcseconds.
- - `alpha`: Inner slope parameter.
- - `beta`: Outer slope parameter.
- - `I0`: Intensity at the center of the profile in flux/arcsec^2
+ :param rout: Outer truncation radius in arcseconds.
+ :param alpha: Inner slope parameter.
+ :param beta: Outer slope parameter.
+ :param I0: Intensity at the center of the profile in flux/arcsec^2
"""
_model_type = "ferrer"
_parameter_specs = {
- "rout": {"units": "arcsec", "valid": (0.0, None), "shape": (None,), "dynamic": True},
- "alpha": {"units": "unitless", "valid": (0, 10), "shape": (None,), "dynamic": True},
- "beta": {"units": "unitless", "valid": (0, 2), "shape": (None,), "dynamic": True},
- "I0": {"units": "flux/arcsec^2", "valid": (0.0, None), "shape": (None,), "dynamic": True},
+ "rout": {
+ "units": "arcsec",
+ "valid": (0.0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Outer truncation radius in arcseconds.",
+ },
+ "alpha": {
+ "units": "unitless",
+ "valid": (0, 10),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Inner slope parameter.",
+ },
+ "beta": {
+ "units": "unitless",
+ "valid": (0, 2),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Outer slope parameter.",
+ },
+ "I0": {
+ "units": "flux/arcsec^2",
+ "valid": (0.0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Intensity at the center of the profile in flux/arcsec^2",
+ },
}
@torch.no_grad()
@@ -125,30 +175,50 @@ class FerrerPSFMixin:
is used in specialized circumstances such as fitting the bar of a galaxy.
The functional form of the Modified Ferrer profile is defined as:
- $$I(R) = I_0 \\left(1 - \\left(\\frac{R}{r_{\\rm out}}\\right)^{2-\\beta}\\right)^{\\alpha}$$
+ .. math::
+
+ I(R) = I_0 \\left(1 - \\left(\\frac{R}{r_{\\rm out}}\\right)^{2-\\beta}\\right)^{\\alpha}
- where `rout` is the outer truncation radius, `alpha` controls the steepness
- of the truncation, `beta` controls the shape, and `I0` is the intensity at
+ where ``rout`` is the outer truncation radius, ``alpha`` controls the steepness
+ of the truncation, ``beta`` controls the shape, and ``I0`` is the intensity at
the center of the profile.
- **Parameters:**
- - `rout`: Outer truncation radius in pixels.
- - `alpha`: Inner slope parameter.
- - `beta`: Outer slope parameter.
- - `I0`: Intensity at the center of the profile in flux/pix^2
+ :param rout: Outer truncation radius in pixels.
+ :param alpha: Inner slope parameter.
+ :param beta: Outer slope parameter.
+ :param I0: Intensity at the center of the profile in flux/pix^2
"""
_model_type = "ferrer"
_parameter_specs = {
- "rout": {"units": "pix", "valid": (0.0, None), "shape": (), "dynamic": True},
- "alpha": {"units": "unitless", "valid": (0, 10), "shape": (), "dynamic": True},
- "beta": {"units": "unitless", "valid": (0, 2), "shape": (), "dynamic": True},
+ "rout": {
+ "units": "pix",
+ "valid": (0.0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Outer truncation radius in pixels.",
+ },
+ "alpha": {
+ "units": "unitless",
+ "valid": (0, 10),
+ "shape": (),
+ "dynamic": True,
+ "description": "Inner slope parameter.",
+ },
+ "beta": {
+ "units": "unitless",
+ "valid": (0, 2),
+ "shape": (),
+ "dynamic": True,
+ "description": "Outer slope parameter.",
+ },
"I0": {
"units": "flux/pix^2",
"valid": (0, None),
"shape": (),
"dynamic": False,
"value": 1.0,
+ "description": "Intensity at the center of the profile in flux/pix^2",
},
}
diff --git a/astrophot/models/mixins/gaussian.py b/astrophot/models/mixins/gaussian.py
index db34b4f2..75712a5a 100644
--- a/astrophot/models/mixins/gaussian.py
+++ b/astrophot/models/mixins/gaussian.py
@@ -18,20 +18,33 @@ class GaussianMixin:
The Gaussian profile is a simple and widely used model for extended objects.
The functional form of the Gaussian profile is defined as:
- $$I(R) = \\frac{{\\rm flux}}{\\sqrt{2\\pi}\\sigma} \\exp(-R^2 / (2 \\sigma^2))$$
+ .. math::
- where `I_0` is the intensity at the center of the profile and `sigma` is the
+ I(R) = \\frac{{\\rm flux}}{\\sqrt{2\\pi}\\sigma} \\exp(-R^2 / (2 \\sigma^2))
+
+ where ``I_0`` is the intensity at the center of the profile and ``sigma`` is the
standard deviation which controls the width of the profile.
- **Parameters:**
- - `sigma`: Standard deviation of the Gaussian profile in arcseconds.
- - `flux`: Total flux of the Gaussian profile.
+ :param sigma: Standard deviation of the Gaussian profile in arcseconds.
+ :param flux: Total flux of the Gaussian profile.
"""
_model_type = "gaussian"
_parameter_specs = {
- "sigma": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "flux": {"units": "flux", "valid": (0, None), "shape": (), "dynamic": True},
+ "sigma": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Standard deviation of the Gaussian profile in arcseconds.",
+ },
+ "flux": {
+ "units": "flux",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Total flux of the Gaussian profile.",
+ },
}
@torch.no_grad()
@@ -58,24 +71,37 @@ class iGaussianMixin:
The Gaussian profile is a simple and widely used model for extended objects.
The functional form of the Gaussian profile is defined as:
- $$I(R) = \\frac{{\\rm flux}}{\\sqrt{2\\pi}\\sigma} \\exp(-R^2 / (2 \\sigma^2))$$
+ .. math::
+
+ I(R) = \\frac{{\\rm flux}}{\\sqrt{2\\pi}\\sigma} \\exp(-R^2 / (2 \\sigma^2))
- where `sigma` is the standard deviation which controls the width of the
- profile and `flux` gives the total flux of the profile (assuming no
+ where ``sigma`` is the standard deviation which controls the width of the
+ profile and ``flux`` gives the total flux of the profile (assuming no
perturbations).
- `sigma` and `flux` are batched by their first dimension, allowing for
+ ``sigma`` and ``flux`` are batched by their first dimension, allowing for
multiple Gaussian profiles to be defined at once.
- **Parameters:**
- - `sigma`: Standard deviation of the Gaussian profile in arcseconds.
- - `flux`: Total flux of the Gaussian profile.
+ :param sigma: Standard deviation of the Gaussian profile in arcseconds.
+ :param flux: Total flux of the Gaussian profile.
"""
_model_type = "gaussian"
_parameter_specs = {
- "sigma": {"units": "arcsec", "valid": (0, None), "shape": (None,), "dynamic": True},
- "flux": {"units": "flux", "valid": (0, None), "shape": (None,), "dynamic": True},
+ "sigma": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Standard deviation of the Gaussian profile in arcseconds.",
+ },
+ "flux": {
+ "units": "flux",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Total flux of the Gaussian profile.",
+ },
}
@torch.no_grad()
@@ -103,20 +129,34 @@ class GaussianPSFMixin:
The Gaussian profile is a simple and widely used model for extended objects.
The functional form of the Gaussian profile is defined as:
- $$I(R) = \\frac{{\\rm flux}}{\\sqrt{2\\pi}\\sigma} \\exp(-R^2 / (2 \\sigma^2))$$
+ .. math::
+
+ I(R) = \\frac{{\\rm flux}}{\\sqrt{2\\pi}\\sigma} \\exp(-R^2 / (2 \\sigma^2))
- where `I_0` is the intensity at the center of the profile and `sigma` is the
+ where ``I_0`` is the intensity at the center of the profile and ``sigma`` is the
standard deviation which controls the width of the profile.
- **Parameters:**
- - `sigma`: Standard deviation of the Gaussian profile in pixels.
- - `flux`: Total flux of the Gaussian profile.
+ :param sigma: Standard deviation of the Gaussian profile in pixels.
+ :param flux: Total flux of the Gaussian profile.
"""
_model_type = "gaussian"
_parameter_specs = {
- "sigma": {"units": "pix", "valid": (0, None), "shape": (), "dynamic": True},
- "flux": {"units": "flux", "valid": (0, None), "shape": (), "dynamic": False, "value": 1.0},
+ "sigma": {
+ "units": "pix",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Standard deviation of the Gaussian profile in pixels.",
+ },
+ "flux": {
+ "units": "flux",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": False,
+ "value": 1.0,
+ "description": "Total flux of the Gaussian profile.",
+ },
}
@torch.no_grad()
diff --git a/astrophot/models/mixins/king.py b/astrophot/models/mixins/king.py
index ccdf2a19..bee07a31 100644
--- a/astrophot/models/mixins/king.py
+++ b/astrophot/models/mixins/king.py
@@ -16,35 +16,55 @@ def x0_func(model_params, R, F):
class KingMixin:
"""Empirical King radial light profile (Elson 1999).
- Often used for star clusters. By default the profile has `alpha = 2` but we
+ Often used for star clusters. By default the profile has ``alpha = 2`` but we
allow the parameter to vary freely for fitting. The functional form of the
Empirical King profile is defined as:
- $$I(R) = I_0\\left[\\frac{1}{(1 + (R/R_c)^2)^{1/\\alpha}} - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{\\alpha}\\left[1 - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{-\\alpha}$$
+ .. math::
- where `R_c` is the core radius, `R_t` is the truncation radius, and `I_0` is
- the intensity at the center of the profile. `alpha` is the concentration
+ I(R) = I_0\\left[\\frac{1}{(1 + (R/R_c)^2)^{1/\\alpha}} - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{\\alpha}\\left[1 - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{-\\alpha}
+
+ where ``R_c`` is the core radius, ``R_t`` is the truncation radius, and ``I_0`` is
+ the intensity at the center of the profile. ``alpha`` is the concentration
index which controls the shape of the profile.
- **Parameters:**
- - `Rc`: core radius
- - `Rt`: truncation radius
- - `alpha`: concentration index which controls the shape of the brightness profile
- - `I0`: intensity at the center of the profile
+ :param Rc: core radius
+ :param Rt: truncation radius
+ :param alpha: concentration index which controls the shape of the brightness profile
+ :param I0: intensity at the center of the profile
"""
_model_type = "king"
_parameter_specs = {
- "Rc": {"units": "arcsec", "valid": (0.0, None), "shape": (), "dynamic": True},
- "Rt": {"units": "arcsec", "valid": (0.0, None), "shape": (), "dynamic": True},
+ "Rc": {
+ "units": "arcsec",
+ "valid": (0.0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "core radius",
+ },
+ "Rt": {
+ "units": "arcsec",
+ "valid": (0.0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "truncation radius",
+ },
"alpha": {
"units": "unitless",
"valid": (0, 10),
"shape": (),
"value": 2.0,
"dynamic": False,
+ "description": "concentration index which controls the shape of the brightness profile",
+ },
+ "I0": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "intensity at the center of the profile",
},
- "I0": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (), "dynamic": True},
}
@torch.no_grad()
@@ -70,32 +90,57 @@ def radial_model(
class iKingMixin:
"""Empirical King radial light profile (Elson 1999).
- Often used for star clusters. By default the profile has `alpha = 2` but we
+ Often used for star clusters. By default the profile has ``alpha = 2`` but we
allow the parameter to vary freely for fitting. The functional form of the
Empirical King profile is defined as:
- $$I(R) = I_0\\left[\\frac{1}{(1 + (R/R_c)^2)^{1/\\alpha}} - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{\\alpha}\\left[1 - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{-\\alpha}$$
+ .. math::
+
+ I(R) = I_0\\left[\\frac{1}{(1 + (R/R_c)^2)^{1/\\alpha}} - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{\\alpha}\\left[1 - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{-\\alpha}
- where `R_c` is the core radius, `R_t` is the truncation radius, and `I_0` is
- the intensity at the center of the profile. `alpha` is the concentration
+ where ``R_c`` is the core radius, ``R_t`` is the truncation radius, and ``I_0`` is
+ the intensity at the center of the profile. ``alpha`` is the concentration
index which controls the shape of the profile.
- `Rc`, `Rt`, `alpha`, and `I0` are batched by their first dimension, allowing
+ ``Rc``, ``Rt``, ``alpha``, and ``I0`` are batched by their first dimension, allowing
for multiple King profiles to be defined at once.
- **Parameters:**
- - `Rc`: core radius
- - `Rt`: truncation radius
- - `alpha`: concentration index which controls the shape of the brightness profile
- - `I0`: intensity at the center of the profile
+ :param Rc: core radius
+ :param Rt: truncation radius
+ :param alpha: concentration index which controls the shape of the brightness profile
+ :param I0: intensity at the center of the profile
"""
_model_type = "king"
_parameter_specs = {
- "Rc": {"units": "arcsec", "valid": (0.0, None), "shape": (None,), "dynamic": True},
- "Rt": {"units": "arcsec", "valid": (0.0, None), "shape": (None,), "dynamic": True},
- "alpha": {"units": "unitless", "valid": (0, 10), "shape": (None,), "dynamic": False},
- "I0": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (None,), "dynamic": True},
+ "Rc": {
+ "units": "arcsec",
+ "valid": (0.0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "core radius",
+ },
+ "Rt": {
+ "units": "arcsec",
+ "valid": (0.0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "truncation radius",
+ },
+ "alpha": {
+ "units": "unitless",
+ "valid": (0, 10),
+ "shape": (None,),
+ "dynamic": False,
+ "description": "concentration index which controls the shape of the brightness profile",
+ },
+ "I0": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "intensity at the center of the profile",
+ },
}
@torch.no_grad()
@@ -125,33 +170,47 @@ def iradial_model(
class KingPSFMixin:
"""Empirical King radial light profile (Elson 1999).
- Often used for star clusters. By default the profile has `alpha = 2` but we
+ Often used for star clusters. By default the profile has ``alpha = 2`` but we
allow the parameter to vary freely for fitting. The functional form of the
Empirical King profile is defined as:
- $$I(R) = I_0\\left[\\frac{1}{(1 + (R/R_c)^2)^{1/\\alpha}} - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{\\alpha}\\left[1 - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{-\\alpha}$$
+ .. math::
+
+ I(R) = I_0\\left[\\frac{1}{(1 + (R/R_c)^2)^{1/\\alpha}} - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{\\alpha}\\left[1 - \\frac{1}{(1 + (R_t/R_c)^2)^{1/\\alpha}}\\right]^{-\\alpha}
- where `R_c` is the core radius, `R_t` is the truncation radius, and `I_0` is
- the intensity at the center of the profile. `alpha` is the concentration
+ where ``R_c`` is the core radius, ``R_t`` is the truncation radius, and ``I_0`` is
+ the intensity at the center of the profile. ``alpha`` is the concentration
index which controls the shape of the profile.
- **Parameters:**
- - `Rc`: core radius [pix]
- - `Rt`: truncation radius [pix]
- - `alpha`: concentration index which controls the shape of the brightness profile
- - `I0`: intensity at the center of the profile [flux/pix^2]
+ :param Rc: core radius [pix]
+ :param Rt: truncation radius [pix]
+ :param alpha: concentration index which controls the shape of the brightness profile
+ :param I0: intensity at the center of the profile [flux/pix^2]
"""
_model_type = "king"
_parameter_specs = {
- "Rc": {"units": "pix", "valid": (0.0, None), "shape": (), "dynamic": True},
- "Rt": {"units": "pix", "valid": (0.0, None), "shape": (), "dynamic": True},
+ "Rc": {
+ "units": "pix",
+ "valid": (0.0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "core radius [pix]",
+ },
+ "Rt": {
+ "units": "pix",
+ "valid": (0.0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "truncation radius [pix]",
+ },
"alpha": {
"units": "unitless",
"valid": (0, 10),
"shape": (),
"value": 2.0,
"dynamic": False,
+ "description": "concentration index which controls the shape of the brightness profile",
},
"I0": {
"units": "flux/pix^2",
@@ -159,6 +218,7 @@ class KingPSFMixin:
"shape": (),
"dynamic": False,
"value": 1.0,
+ "description": "intensity at the center of the profile [flux/pix^2]",
},
}
diff --git a/astrophot/models/mixins/moffat.py b/astrophot/models/mixins/moffat.py
index df80162b..8ccc432b 100644
--- a/astrophot/models/mixins/moffat.py
+++ b/astrophot/models/mixins/moffat.py
@@ -19,21 +19,40 @@ class MoffatMixin:
PSF functions for ground based data. It can also be used to fit extended
objects. The functional form of the Moffat profile is defined as:
- $$I(R) = \\frac{I_0}{(1 + (R/R_d)^2)^n}$$
+ .. math::
- `n` is the concentration index which controls the shape of the profile.
+ I(R) = \\frac{I_0}{(1 + (R/R_d)^2)^n}
- **Parameters:**
- - `n`: Concentration index which controls the shape of the brightness profile
- - `Rd`: Scale length radius
- - `I0`: Intensity at the center of the profile
+ ``n`` is the concentration index which controls the shape of the profile.
+
+ :param n: Concentration index which controls the shape of the brightness profile
+ :param Rd: Scale length radius
+ :param I0: Intensity at the center of the profile
"""
_model_type = "moffat"
_parameter_specs = {
- "n": {"units": "none", "valid": (0.1, 10), "shape": (), "dynamic": True},
- "Rd": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "I0": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (), "dynamic": True},
+ "n": {
+ "units": "none",
+ "valid": (0.1, 10),
+ "shape": (),
+ "dynamic": True,
+ "description": "Concentration index which controls the shape of the brightness profile",
+ },
+ "Rd": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Scale length radius",
+ },
+ "I0": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Intensity at the center of the profile",
+ },
}
@torch.no_grad()
@@ -61,24 +80,43 @@ class iMoffatMixin:
PSF functions for ground based data. It can also be used to fit extended
objects. The functional form of the Moffat profile is defined as:
- $$I(R) = \\frac{I_0}{(1 + (R/R_d)^2)^n}$$
+ .. math::
+
+ I(R) = \\frac{I_0}{(1 + (R/R_d)^2)^n}
- `n` is the concentration index which controls the shape of the profile.
+ ``n`` is the concentration index which controls the shape of the profile.
- `n`, `Rd`, and `I0` are batched by their first dimension, allowing for
+ ``n``, ``Rd``, and ``I0`` are batched by their first dimension, allowing for
multiple Moffat profiles to be defined at once.
- **Parameters:**
- - `n`: Concentration index which controls the shape of the brightness profile
- - `Rd`: Scale length radius
- - `I0`: Intensity at the center of the profile
+ :param n: Concentration index which controls the shape of the brightness profile
+ :param Rd: Scale length radius
+ :param I0: Intensity at the center of the profile
"""
_model_type = "moffat"
_parameter_specs = {
- "n": {"units": "none", "valid": (0.1, 10), "shape": (None,), "dynamic": True},
- "Rd": {"units": "arcsec", "valid": (0, None), "shape": (None,), "dynamic": True},
- "I0": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (None,), "dynamic": True},
+ "n": {
+ "units": "none",
+ "valid": (0.1, 10),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Concentration index which controls the shape of the brightness profile",
+ },
+ "Rd": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Scale length radius",
+ },
+ "I0": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Intensity at the center of the profile",
+ },
}
@torch.no_grad()
@@ -109,26 +147,40 @@ class MoffatPSFMixin:
PSF functions for ground based data. It can also be used to fit extended
objects. The functional form of the Moffat profile is defined as:
- $$I(R) = \\frac{I_0}{(1 + (R/R_d)^2)^n}$$
+ .. math::
+
+ I(R) = \\frac{I_0}{(1 + (R/R_d)^2)^n}
- `n` is the concentration index which controls the shape of the profile.
+ ``n`` is the concentration index which controls the shape of the profile.
- **Parameters:**
- - `n`: Concentration index which controls the shape of the brightness profile
- - `Rd`: Scale length radius [pix]
- - `I0`: Intensity at the center of the profile [flux/pix^2]
+ :param n: Concentration index which controls the shape of the brightness profile
+ :param Rd: Scale length radius [pix]
+ :param I0: Intensity at the center of the profile [flux/pix^2]
"""
_model_type = "moffat"
_parameter_specs = {
- "n": {"units": "none", "valid": (0.1, 10), "shape": (), "dynamic": True},
- "Rd": {"units": "pix", "valid": (0, None), "shape": (), "dynamic": True},
+ "n": {
+ "units": "none",
+ "valid": (0.1, 10),
+ "shape": (),
+ "dynamic": True,
+ "description": "Concentration index which controls the shape of the brightness profile",
+ },
+ "Rd": {
+ "units": "pix",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "Scale length radius [pix]",
+ },
"I0": {
"units": "flux/pix^2",
"valid": (0, None),
"shape": (),
"dynamic": False,
"value": 1.0,
+ "description": "Intensity at the center of the profile [flux/pix^2]",
},
}
diff --git a/astrophot/models/mixins/nuker.py b/astrophot/models/mixins/nuker.py
index d6c5e1a9..837017d1 100644
--- a/astrophot/models/mixins/nuker.py
+++ b/astrophot/models/mixins/nuker.py
@@ -18,27 +18,57 @@ class NukerMixin:
This is a classic profile used widely in galaxy modelling. The functional
form of the Nuker profile is defined as:
- $$I(R) = I_b2^{\\frac{\\beta - \\gamma}{\\alpha}}\\left(\\frac{R}{R_b}\\right)^{-\\gamma}\\left[1 + \\left(\\frac{R}{R_b}\\right)^{\\alpha}\\right]^{\\frac{\\gamma-\\beta}{\\alpha}}$$
+ .. math::
- It is effectively a double power law profile. $\\gamma$ gives the inner
- slope, $\\beta$ gives the outer slope, $\\alpha$ is somewhat degenerate with
+ I(R) = I_b2^{\\frac{\\beta - \\gamma}{\\alpha}}\\left(\\frac{R}{R_b}\\right)^{-\\gamma}\\left[1 + \\left(\\frac{R}{R_b}\\right)^{\\alpha}\\right]^{\\frac{\\gamma-\\beta}{\\alpha}}
+
+ It is effectively a double power law profile. :math:`\\gamma` gives the inner
+ slope, :math:`\\beta` gives the outer slope, :math:`\\alpha` is somewhat degenerate with
the other slopes.
- **Parameters:**
- - `Rb`: scale length radius
- - `Ib`: intensity at the scale length
- - `alpha`: sharpness of transition between power law slopes
- - `beta`: outer power law slope
- - `gamma`: inner power law slope
+ :param Rb: scale length radius
+ :param Ib: intensity at the scale length
+ :param alpha: sharpness of transition between power law slopes
+ :param beta: outer power law slope
+ :param gamma: inner power law slope
"""
_model_type = "nuker"
_parameter_specs = {
- "Rb": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "Ib": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (), "dynamic": True},
- "alpha": {"units": "none", "valid": (0, None), "shape": (), "dynamic": True},
- "beta": {"units": "none", "valid": (0, None), "shape": (), "dynamic": True},
- "gamma": {"units": "none", "shape": (), "dynamic": True},
+ "Rb": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "scale length radius",
+ },
+ "Ib": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "intensity at the scale length",
+ },
+ "alpha": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "sharpness of transition between power law slopes",
+ },
+ "beta": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "outer power law slope",
+ },
+ "gamma": {
+ "units": "none",
+ "shape": (),
+ "dynamic": True,
+ "description": "inner power law slope",
+ },
}
@torch.no_grad()
@@ -73,30 +103,60 @@ class iNukerMixin:
This is a classic profile used widely in galaxy modelling. The functional
form of the Nuker profile is defined as:
- $$I(R) = I_b2^{\\frac{\\beta - \\gamma}{\\alpha}}\\left(\\frac{R}{R_b}\\right)^{-\\gamma}\\left[1 + \\left(\\frac{R}{R_b}\\right)^{\\alpha}\\right]^{\\frac{\\gamma-\\beta}{\\alpha}}$$
+ .. math::
+
+ I(R) = I_b2^{\\frac{\\beta - \\gamma}{\\alpha}}\\left(\\frac{R}{R_b}\\right)^{-\\gamma}\\left[1 + \\left(\\frac{R}{R_b}\\right)^{\\alpha}\\right]^{\\frac{\\gamma-\\beta}{\\alpha}}
- It is effectively a double power law profile. $\\gamma$ gives the inner
- slope, $\\beta$ gives the outer slope, $\\alpha$ is somewhat degenerate with
+ It is effectively a double power law profile. :math:`\\gamma` gives the inner
+ slope, :math:`\\beta` gives the outer slope, :math:`\\alpha` is somewhat degenerate with
the other slopes.
- `Rb`, `Ib`, `alpha`, `beta`, and `gamma` are batched by their first
+ ``Rb``, ``Ib``, ``alpha``, ``beta``, and ``gamma`` are batched by their first
dimension, allowing for multiple Nuker profiles to be defined at once.
- **Parameters:**
- - `Rb`: scale length radius
- - `Ib`: intensity at the scale length
- - `alpha`: sharpness of transition between power law slopes
- - `beta`: outer power law slope
- - `gamma`: inner power law slope
+ :param Rb: scale length radius
+ :param Ib: intensity at the scale length
+ :param alpha: sharpness of transition between power law slopes
+ :param beta: outer power law slope
+ :param gamma: inner power law slope
"""
_model_type = "nuker"
_parameter_specs = {
- "Rb": {"units": "arcsec", "valid": (0, None), "shape": (None,), "dynamic": True},
- "Ib": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (None,), "dynamic": True},
- "alpha": {"units": "none", "valid": (0, None), "shape": (None,), "dynamic": True},
- "beta": {"units": "none", "valid": (0, None), "shape": (None,), "dynamic": True},
- "gamma": {"units": "none", "shape": (None,), "dynamic": True},
+ "Rb": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "scale length radius",
+ },
+ "Ib": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "intensity at the scale length",
+ },
+ "alpha": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "sharpness of transition between power law slopes",
+ },
+ "beta": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "outer power law slope",
+ },
+ "gamma": {
+ "units": "none",
+ "shape": (None,),
+ "dynamic": True,
+ "description": "inner power law slope",
+ },
}
@torch.no_grad()
@@ -133,33 +193,58 @@ class NukerPSFMixin:
This is a classic profile used widely in galaxy modelling. The functional
form of the Nuker profile is defined as:
- $$I(R) = I_b2^{\\frac{\\beta - \\gamma}{\\alpha}}\\left(\\frac{R}{R_b}\\right)^{-\\gamma}\\left[1 + \\left(\\frac{R}{R_b}\\right)^{\\alpha}\\right]^{\\frac{\\gamma-\\beta}{\\alpha}}$$
+ .. math::
+
+ I(R) = I_b2^{\\frac{\\beta - \\gamma}{\\alpha}}\\left(\\frac{R}{R_b}\\right)^{-\\gamma}\\left[1 + \\left(\\frac{R}{R_b}\\right)^{\\alpha}\\right]^{\\frac{\\gamma-\\beta}{\\alpha}}
- It is effectively a double power law profile. $\\gamma$ gives the inner
- slope, $\\beta$ gives the outer slope, $\\alpha$ is somewhat degenerate with
+ It is effectively a double power law profile. :math:`\\gamma` gives the inner
+ slope, :math:`\\beta` gives the outer slope, :math:`\\alpha` is somewhat degenerate with
the other slopes.
- **Parameters:**
- - `Rb`: scale length radius [pix]
- - `Ib`: intensity at the scale length [flux/pix^2]
- - `alpha`: sharpness of transition between power law slopes
- - `beta`: outer power law slope
- - `gamma`: inner power law slope
+ :param Rb: scale length radius [pix]
+ :param Ib: intensity at the scale length [flux/pix^2]
+ :param alpha: sharpness of transition between power law slopes
+ :param beta: outer power law slope
+ :param gamma: inner power law slope
"""
_model_type = "nuker"
_parameter_specs = {
- "Rb": {"units": "pix", "valid": (0, None), "shape": (), "dynamic": True},
+ "Rb": {
+ "units": "pix",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "scale length radius [pix]",
+ },
"Ib": {
"units": "flux/pix^2",
"valid": (0, None),
"shape": (),
"dynamic": False,
"value": 1.0,
+ "description": "intensity at the scale length [flux/pix^2]",
+ },
+ "alpha": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "sharpness of transition between power law slopes",
+ },
+ "beta": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "outer power law slope",
+ },
+ "gamma": {
+ "units": "none",
+ "shape": (),
+ "dynamic": True,
+ "description": "inner power law slope",
},
- "alpha": {"units": "none", "valid": (0, None), "shape": (), "dynamic": True},
- "beta": {"units": "none", "valid": (0, None), "shape": (), "dynamic": True},
- "gamma": {"units": "none", "shape": (), "dynamic": True},
}
@torch.no_grad()
diff --git a/astrophot/models/mixins/sersic.py b/astrophot/models/mixins/sersic.py
index 96074f4a..93607048 100644
--- a/astrophot/models/mixins/sersic.py
+++ b/astrophot/models/mixins/sersic.py
@@ -19,24 +19,43 @@ class SersicMixin:
starting point for many extended objects. The functional form of the Sersic
profile is defined as:
- $$I(R) = I_e * \\exp(- b_n((R/R_e)^{1/n} - 1))$$
+ .. math::
+
+ I(R) = I_e \\exp(- b_n((R/R_e)^{1/n} - 1))
It is a generalization of a gaussian, exponential, and de-Vaucouleurs
- profile. The Sersic index `n` controls the shape of the profile, with `n=1`
- being an exponential profile, `n=4` being a de-Vaucouleurs profile, and
- `n=0.5` being a Gaussian profile.
-
- **Parameters:**
- - `n`: Sersic index which controls the shape of the brightness profile
- - `Re`: half light radius [arcsec]
- - `Ie`: intensity at the half light radius [flux/arcsec^2]
+ profile. The Sersic index ``n`` controls the shape of the profile, with ``n=1``
+ being an exponential profile, ``n=4`` being a de-Vaucouleurs profile, and
+ ``n=0.5`` being a Gaussian profile.
+
+ :param n: Sersic index which controls the shape of the brightness profile
+ :param Re: half light radius [arcsec]
+ :param Ie: intensity at the half light radius [flux/arcsec^2]
"""
_model_type = "sersic"
_parameter_specs = {
- "n": {"units": "none", "valid": (0.36, 8), "shape": (), "dynamic": True},
- "Re": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "Ie": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (), "dynamic": True},
+ "n": {
+ "units": "none",
+ "valid": (0.36, 8),
+ "shape": (),
+ "dynamic": True,
+ "description": "Sersic index which controls the shape of the brightness profile",
+ },
+ "Re": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "half light radius [arcsec]",
+ },
+ "Ie": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "intensity at the half light radius [flux/arcsec^2]",
+ },
}
@torch.no_grad()
@@ -60,27 +79,46 @@ class iSersicMixin:
starting point for many extended objects. The functional form of the Sersic
profile is defined as:
- $$I(R) = I_e * \\exp(- b_n((R/R_e)^{1/n} - 1))$$
+ .. math::
+
+ I(R) = I_e \\exp(- b_n((R/R_e)^{1/n} - 1))
It is a generalization of a gaussian, exponential, and de-Vaucouleurs
- profile. The Sersic index `n` controls the shape of the profile, with `n=1`
- being an exponential profile, `n=4` being a de-Vaucouleurs profile, and
- `n=0.5` being a Gaussian profile.
+ profile. The Sersic index ``n`` controls the shape of the profile, with ``n=1``
+ being an exponential profile, ``n=4`` being a de-Vaucouleurs profile, and
+ ``n=0.5`` being a Gaussian profile.
- `n`, `Re`, and `Ie` are batched by their first dimension, allowing for
+ ``n``, ``Re``, and ``Ie`` are batched by their first dimension, allowing for
multiple Sersic profiles to be defined at once.
- **Parameters:**
- - `n`: Sersic index which controls the shape of the brightness profile
- - `Re`: half light radius [arcsec]
- - `Ie`: intensity at the half light radius [flux/arcsec^2]
+ :param n: Sersic index which controls the shape of the brightness profile
+ :param Re: half light radius [arcsec]
+ :param Ie: intensity at the half light radius [flux/arcsec^2]
"""
_model_type = "sersic"
_parameter_specs = {
- "n": {"units": "none", "valid": (0.36, 8), "shape": (None,), "dynamic": True},
- "Re": {"units": "arcsec", "valid": (0, None), "shape": (None,), "dynamic": True},
- "Ie": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (None,), "dynamic": True},
+ "n": {
+ "units": "none",
+ "valid": (0.36, 8),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Sersic index which controls the shape of the brightness profile",
+ },
+ "Re": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "half light radius [arcsec]",
+ },
+ "Ie": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "intensity at the half light radius [flux/arcsec^2]",
+ },
}
@torch.no_grad()
@@ -112,29 +150,43 @@ class SersicPSFMixin:
point for many objects. The functional form of the Sersic profile is
defined as:
- $$I(R) = I_e * \\exp(- b_n((R/R_e)^{1/n} - 1))$$
+ .. math::
+
+ I(R) = I_e \\exp(- b_n((R/R_e)^{1/n} - 1))
It includes the gaussian, exponential, and de-Vaucouleurs
- profiles. The Sersic index `n` controls the shape of the profile, with `n=1`
- being an exponential profile, `n=4` being a de-Vaucouleurs profile, and
- `n=0.5` being a Gaussian profile.
-
- **Parameters:**
- - `n`: Sersic index which controls the shape of the brightness profile
- - `Re`: half light radius [pix]
- - `Ie`: intensity at the half light radius [flux/pix^2]
+ profiles. The Sersic index ``n`` controls the shape of the profile, with ``n=1``
+ being an exponential profile, ``n=4`` being a de-Vaucouleurs profile, and
+ ``n=0.5`` being a Gaussian profile.
+
+ :param n: Sersic index which controls the shape of the brightness profile
+ :param Re: half light radius [pix]
+ :param Ie: intensity at the half light radius [flux/pix^2]
"""
_model_type = "sersic"
_parameter_specs = {
- "n": {"units": "none", "valid": (0.36, 8), "shape": (), "dynamic": True},
- "Re": {"units": "pix", "valid": (0, None), "shape": (), "dynamic": True},
+ "n": {
+ "units": "none",
+ "valid": (0.36, 8),
+ "shape": (),
+ "dynamic": True,
+ "description": "Sersic index which controls the shape of the brightness profile",
+ },
+ "Re": {
+ "units": "pix",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "half light radius [pix]",
+ },
"Ie": {
"units": "flux/pix^2",
"valid": (0, None),
"shape": (),
"dynamic": False,
"value": 1.0,
+ "description": "intensity at the half light radius [flux/pix^2]",
},
}
diff --git a/astrophot/models/mixins/spline.py b/astrophot/models/mixins/spline.py
index 57862578..d6c59e5b 100644
--- a/astrophot/models/mixins/spline.py
+++ b/astrophot/models/mixins/spline.py
@@ -12,18 +12,23 @@
class SplineMixin:
"""Spline radial model for brightness.
- The `radial_model` function for this model is defined as a spline
- interpolation from the parameter `I_R`. The `I_R` parameter is a tensor
+ The ``radial_model`` function for this model is defined as a spline
+ interpolation from the parameter ``I_R``. The ``I_R`` parameter is a tensor
that contains the radial profile of the brightness in units of
- flux/arcsec^2. The radius of each node is determined from `I_R.prof`.
+ flux/arcsec^2. The radius of each node is determined from ``I_R.prof``.
- **Parameters:**
- - `I_R`: Tensor of radial brightness values in units of flux/arcsec^2.
+ :param I_R: Tensor of radial brightness values in units of flux/arcsec^2.
"""
_model_type = "spline"
_parameter_specs = {
- "I_R": {"units": "flux/arcsec^2", "valid": (0, None), "shape": (None,), "dynamic": True}
+ "I_R": {
+ "units": "flux/arcsec^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Tensor of radial brightness values in units of flux/arcsec^2.",
+ }
}
@torch.no_grad()
@@ -60,17 +65,16 @@ def radial_model(self, R: ArrayLike, I_R: ArrayLike) -> ArrayLike:
class iSplineMixin:
"""Batched spline radial model for brightness.
- The `radial_model` function for this model is defined as a spline
- interpolation from the parameter `I_R`. The `I_R` parameter is a tensor that
+ The ``radial_model`` function for this model is defined as a spline
+ interpolation from the parameter ``I_R``. The ``I_R`` parameter is a tensor that
contains the radial profile of the brightness in units of flux/arcsec^2. The
- radius of each node is determined from `I_R.prof`.
+ radius of each node is determined from ``I_R.prof``.
- Both `I_R` and `I_R.prof` are batched by their first dimension, allowing for
+ Both ``I_R`` and ``I_R.prof`` are batched by their first dimension, allowing for
multiple spline profiles to be defined at once. Each individual spline model
- is then `I_R[i]` and `I_R.prof[i]` where `i` indexes the profiles.
+ is then ``I_R[i]`` and ``I_R.prof[i]`` where ``i`` indexes the profiles.
- **Parameters:**
- - `I_R`: Tensor of radial brightness values in units of flux/arcsec^2.
+ :param I_R: Tensor of radial brightness values in units of flux/arcsec^2.
"""
_model_type = "spline"
@@ -80,6 +84,7 @@ class iSplineMixin:
"valid": (0, None),
"shape": (None, None),
"dynamic": True,
+ "description": "Tensor of radial brightness values in units of flux/arcsec^2.",
}
}
@@ -128,18 +133,23 @@ def iradial_model(self, i: int, R: ArrayLike, I_R: ArrayLike) -> ArrayLike:
class SplinePSFMixin:
"""Spline radial model for brightness.
- The `radial_model` function for this model is defined as a spline
- interpolation from the parameter `I_R`. The `I_R` parameter is a tensor
+ The ``radial_model`` function for this model is defined as a spline
+ interpolation from the parameter ``I_R``. The ``I_R`` parameter is a tensor
that contains the radial profile of the brightness in units of
- flux/pix^2. The radius of each node is determined from `I_R.prof`.
+ flux/pix^2. The radius of each node is determined from ``I_R.prof``.
- **Parameters:**
- - `I_R`: Tensor of radial brightness values in units of flux/pix^2.
+ :param I_R: Tensor of radial brightness values in units of flux/pix^2.
"""
_model_type = "spline"
_parameter_specs = {
- "I_R": {"units": "flux/pix^2", "valid": (0, None), "shape": (None,), "dynamic": True}
+ "I_R": {
+ "units": "flux/pix^2",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Tensor of radial brightness values in units of flux/pix^2.",
+ }
}
@torch.no_grad()
diff --git a/astrophot/models/mixins/transform.py b/astrophot/models/mixins/transform.py
index 223bfc40..553be9ca 100644
--- a/astrophot/models/mixins/transform.py
+++ b/astrophot/models/mixins/transform.py
@@ -16,35 +16,46 @@ class InclinedMixin:
PA and q operate on the coordinates to transform the model. Given some x,y
the updated values are:
- $$x', y' = {\\rm rotate}(-PA + \\pi/2, x, y)$$
- $$y'' = y' / q$$
+ .. math::
- where x' and y'' are the final transformed coordinates. The $\\pi/2$ is included
+ x', y' = {\\rm rotate}(-PA + \\pi/2, x, y)
+
+ .. math::
+
+ y'' = y' / q
+
+ where x' and y'' are the final transformed coordinates. The :math:`\\pi/2` is included
such that the position angle is defined with 0 at north. The -PA is such
that the position angle increases to the East. Thus, the position angle is a
standard East of North definition assuming the WCS of the image is correct.
- Note that this means radii are defined with $R = \\sqrt{x^2 +
- \\left(\\frac{y}{q}\\right)^2}$ rather than the common alternative which is $R =
- \\sqrt{qx^2 + \\frac{y^2}{q}}$
+ Note that this means radii are defined with :math:`R = \\sqrt{x^2 +
+ \\left(\\frac{y}{q}\\right)^2}` rather than the common alternative which is :math:`R =
+ \\sqrt{qx^2 + \\frac{y^2}{q}}`
- **Parameters:**
- - `q`: Axis ratio of the model, defined as the ratio of the
+ :param q: Axis ratio of the model, defined as the ratio of the
semi-minor axis to the semi-major axis. A value of 1.0 is
circular.
- - `PA`: Position angle of the model, defined as the angle
+ :param PA: Position angle of the model, defined as the angle
between the semi-major axis and North, measured East of North.
A value of 0.0 is North, a value of pi/2 is East.
"""
_parameter_specs = {
- "q": {"units": "b/a", "valid": (0.01, 1), "shape": (), "dynamic": True},
+ "q": {
+ "units": "b/a",
+ "valid": (0.01, 1),
+ "shape": (),
+ "dynamic": True,
+ "description": "Axis ratio of the model, defined as the ratio of the semi-minor axis to the semi-major axis. A value of 1.0 is circular.",
+ },
"PA": {
"units": "radians",
"valid": (0, np.pi),
"cyclic": True,
"shape": (),
"dynamic": True,
+ "description": "Position angle of the model, defined as the angle between the semi-major axis and North, measured East of North.",
},
}
@@ -100,16 +111,17 @@ class SuperEllipseMixin:
extension of the standard elliptical representation, especially for
early-type galaxies. The functional form for this is:
- $$R = (|x|^C + |y|^C)^{1/C}$$
+ .. math::
- where $R$ is the new distance metric, $X$ and $Y$ are the coordinates, and $C$ is the
- coefficient for the superellipse. $C$ can take on any value greater than zero
- where $C = 2$ is the standard distance metric, $0 < C < 2$ creates disky or
- pointed perturbations to an ellipse, and $C > 2$ transforms an ellipse to be
+ R = (|x|^C + |y|^C)^{1/C}
+
+ where :math:`R` is the new distance metric, :math:`X` and :math:`Y` are the coordinates, and :math:`C` is the
+ coefficient for the superellipse. :math:`C` can take on any value greater than zero
+ where :math:`C = 2` is the standard distance metric, :math:`0 < C < 2` creates disky or
+ pointed perturbations to an ellipse, and :math:`C > 2` transforms an ellipse to be
more boxy.
- **Parameters:**
- - `C`: Superellipse distance metric parameter, controls the shape of the isophotes.
+ :param C: Superellipse distance metric parameter, controls the shape of the isophotes.
A value of 2.0 is a standard elliptical distance metric, values
less than 2.0 create disky or pointed perturbations to an ellipse,
and values greater than 2.0 create boxy perturbations to an ellipse.
@@ -118,7 +130,14 @@ class SuperEllipseMixin:
_model_type = "superellipse"
_parameter_specs = {
- "C": {"units": "none", "value": 2.0, "valid": (0, 10), "shape": (), "dynamic": True},
+ "C": {
+ "units": "none",
+ "value": 2.0,
+ "valid": (0, 10),
+ "shape": (),
+ "dynamic": True,
+ "description": "Superellipse distance metric parameter, controls the shape of the isophotes.",
+ },
}
@forward
@@ -133,12 +152,14 @@ class FourierEllipseMixin:
pure ellipses. This is a common extension of the standard elliptical
representation. The form of the Fourier perturbations is:
- $$R' = R * \\exp\\left(\\sum_m(a_m * \\cos(m * \\theta + \\phi_m))\\right)$$
+ .. math::
+
+ R' = R * \\exp\\left(\\sum_m(a_m * \\cos(m * \\theta + \\phi_m))\\right)
where R' is the new radius value, R is the original radius (typically
- computed as $\\sqrt{x^2+y^2}$), m is the index of the Fourier mode, a_m is
+ computed as :math:`\\sqrt{x^2+y^2}`), m is the index of the Fourier mode, a_m is
the amplitude of the m'th Fourier mode, theta is the angle around the
- ellipse (typically $\\arctan(y/x)$), and phi_m is the phase of the m'th
+ ellipse (typically :math:`\\arctan(y/x)`), and phi_m is the phase of the m'th
fourier mode.
One can create extremely complex shapes using different Fourier modes,
@@ -155,26 +176,29 @@ class FourierEllipseMixin:
should consider carefully why the Fourier modes are being used for the
science case at hand.
- **Parameters:**
- - `am`: Tensor of amplitudes for the Fourier modes, indicates the strength
+ :param am: Tensor of amplitudes for the Fourier modes, indicates the strength
of each mode.
- - `phim`: Tensor of phases for the Fourier modes, adjusts the
+ :param phim: Tensor of phases for the Fourier modes, adjusts the
orientation of the mode perturbation relative to the major axis. It
is cyclically defined in the range [0,2pi)
-
- **Options:**
- - `modes`: Tuple of integers indicating which Fourier modes to use.
+ :param modes: Tuple of integers indicating which Fourier modes to use.
"""
_model_type = "fourier"
_parameter_specs = {
- "am": {"units": "none", "shape": (None,), "dynamic": True},
+ "am": {
+ "units": "none",
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Tensor of amplitudes for the Fourier modes, indicates the strength of each mode.",
+ },
"phim": {
"units": "radians",
"valid": (0, 2 * np.pi),
"cyclic": True,
"shape": (None,),
"dynamic": False,
+ "description": "Tensor of phases for the Fourier modes, adjusts the orientation of the mode perturbation relative to the major axis.",
},
}
_options = ("modes",)
@@ -218,29 +242,43 @@ class WarpMixin:
appearance, variations of PA, q profiles can create complex galaxy models.
The form of the coordinate transformation for each pixel looks like:
- $$R = \\sqrt{x^2 + y^2}$$
- $$x', y' = \\rm{rotate}(-PA(R) + \\pi/2, x, y)$$
- $$y'' = y' / q(R)$$
+ .. math::
+
+ R = \\sqrt{x^2 + y^2}
+
+ .. math::
+
+ x', y' = \\rm{rotate}(-PA(R) + \\pi/2, x, y)
+
+ .. math::
+
+ y'' = y' / q(R)
Note that now PA and q are functions of radius R, which is computed from the
original coordinates X, Y. This is achieved by making PA and q a spline
profile.
- **Parameters:**
- - `q_R`: Tensor of axis ratio values for axis ratio spline
- - `PA_R`: Tensor of position angle values as input to the spline
+ :param q_R: Tensor of axis ratio values for axis ratio spline
+ :param PA_R: Tensor of position angle values as input to the spline
"""
_model_type = "warp"
_parameter_specs = {
- "q_R": {"units": "b/a", "valid": (0, 1), "shape": (None,), "dynamic": True},
+ "q_R": {
+ "units": "b/a",
+ "valid": (0, 1),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "Tensor of axis ratio values for axis ratio spline",
+ },
"PA_R": {
"units": "radians",
"valid": (0, np.pi),
"cyclic": True,
"shape": (None,),
"dynamic": True,
+ "description": "Tensor of position angle values as input to the spline",
},
}
@@ -284,21 +322,31 @@ class TruncationMixin:
optimized in a model, though it is possible for this parameter to be
unstable if there isn't a clear truncation signal in the data.
- **Parameters:**
- - `Rt`: The truncation radius in arcseconds.
- - `St`: The steepness of the truncation profile, controlling how quickly
+ :param Rt: The truncation radius in arcseconds.
+ :param St: The steepness of the truncation profile, controlling how quickly
the brightness drops to zero at the truncation radius.
-
- **Options:**
- - `outer_truncation`: If True, the model will truncate the brightness beyond
+ :param outer_truncation: If True, the model will truncate the brightness beyond
the truncation radius. If False, the model will truncate the
brightness within the truncation radius.
"""
_model_type = "truncated"
_parameter_specs = {
- "Rt": {"units": "arcsec", "valid": (0, None), "shape": (), "dynamic": True},
- "St": {"units": "none", "valid": (0, None), "shape": (), "value": 1.0, "dynamic": False},
+ "Rt": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "The truncation radius in arcseconds.",
+ },
+ "St": {
+ "units": "none",
+ "valid": (0, None),
+ "shape": (),
+ "value": 1.0,
+ "dynamic": False,
+ "description": "The steepness of the truncation profile, controlling how quickly the brightness drops to zero at the truncation radius.",
+ },
}
_options = ("outer_truncation",)
diff --git a/astrophot/models/model_object.py b/astrophot/models/model_object.py
index 7340d111..dddced13 100644
--- a/astrophot/models/model_object.py
+++ b/astrophot/models/model_object.py
@@ -21,17 +21,21 @@ class ComponentModel(GradMixin, SampleMixin, Model):
"""Component of a model for an object in an image.
This is a single component of an image model. It has a position on the sky
- determined by `center` and may or may not be convolved with a PSF to represent some data.
+ determined by ``center`` and may or may not be convolved with a PSF to represent some data.
- **Parameters:**
- - `center`: The center of the component in arcseconds [x, y] defined on the tangent plane.
-
- **Options:**
- - `psf_convolve`: Whether to convolve the model with a PSF. (bool)
+ :param center: The center of the component in arcseconds [x, y] defined on the tangent plane.
+ :param psf_convolve: Whether to convolve the model with a PSF. (bool)
"""
- _parameter_specs = {"center": {"units": "arcsec", "shape": (2,), "dynamic": True}}
+ _parameter_specs = {
+ "center": {
+ "units": "arcsec",
+ "shape": (2,),
+ "dynamic": True,
+ "description": "The center of the component in arcseconds [x, y] defined on the tangent plane.",
+ }
+ }
usable = False
psf_convolve = True
diff --git a/astrophot/models/multi_gaussian_expansion.py b/astrophot/models/multi_gaussian_expansion.py
index abc3c949..b6fa5808 100644
--- a/astrophot/models/multi_gaussian_expansion.py
+++ b/astrophot/models/multi_gaussian_expansion.py
@@ -17,28 +17,47 @@ class MultiGaussianExpansion(ComponentModel):
"""Model that represents a galaxy as a sum of multiple Gaussian
profiles. The model is defined as:
- $$I(R) = \\sum_i {\\rm flux}_i * \\exp(-0.5*(R_i / \\sigma_i)^2) / (2 * \\pi * q_i * \\sigma_i^2)$$
+ .. math::
- where $R_i$ is a radius computed using $q_i$ and $PA_i$ for that component. All components share the same center.
+ I(R) = \\sum_i {\\rm flux}_i * \\exp(-0.5*(R_i / \\sigma_i)^2) / (2 * \\pi * q_i * \\sigma_i^2)
- **Parameters:**
- - `q`: axis ratio to scale minor axis from the ratio of the minor/major axis b/a, this parameter is unitless, it is restricted to the range (0,1)
- - `PA`: position angle of the semi-major axis relative to the image positive x-axis in radians, it is a cyclic parameter in the range [0,pi)
- - `sigma`: standard deviation of each Gaussian
- - `flux`: amplitude of each Gaussian
+ where :math:`R_i` is a radius computed using :math:`q_i` and :math:`PA_i` for that component. All components share the same center.
+
+ :param q: axis ratio to scale minor axis from the ratio of the minor/major axis b/a, this parameter is unitless, it is restricted to the range (0,1)
+ :param PA: position angle of the semi-major axis relative to the image positive x-axis in radians, it is a cyclic parameter in the range [0,pi)
+ :param sigma: standard deviation of each Gaussian
+ :param flux: amplitude of each Gaussian
"""
_model_type = "mge"
_parameter_specs = {
- "q": {"units": "b/a", "valid": (0, 1), "shape": (None,), "dynamic": True},
+ "q": {
+ "units": "b/a",
+ "valid": (0, 1),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "axis ratio to scale minor axis from the ratio of the minor/major axis b/a",
+ },
"PA": {
"units": "radians",
"valid": (0, np.pi),
"cyclic": True,
"dynamic": True,
+ "description": "position angle of the semi-major axis relative to the image positive x-axis in radians",
}, # No shape for PA since there are two options, use with caution
- "sigma": {"units": "arcsec", "valid": (0, None), "shape": (None,), "dynamic": True},
- "flux": {"units": "flux", "shape": (None,), "dynamic": True},
+ "sigma": {
+ "units": "arcsec",
+ "valid": (0, None),
+ "shape": (None,),
+ "dynamic": True,
+ "description": "standard deviation of each Gaussian",
+ },
+ "flux": {
+ "units": "flux",
+ "shape": (None,),
+ "dynamic": True,
+ "description": "amplitude of each Gaussian",
+ },
}
usable = True
diff --git a/astrophot/models/pixelated_model.py b/astrophot/models/pixelated_model.py
index 0442e385..d4bda5ba 100644
--- a/astrophot/models/pixelated_model.py
+++ b/astrophot/models/pixelated_model.py
@@ -25,18 +25,32 @@ class Pixelated(ComponentModel):
The PA and scale are also parameters of this model, so one could alternately
fix the pixels to some image and just fit the PA and scale.
- **Parameters:**
- - `I`: the total flux within each pixel, represented as the log of the flux.
- - `PA`: the position angle of the model, in radians.
- - `scale`: the scale of the model, in arcsec per grid unit.
+ :param I: the total flux within each pixel, represented as the log of the flux.
+ :param PA: the position angle of the model, in radians.
+ :param scale: the scale of the model, in arcsec per grid unit.
"""
_model_type = "pixelated"
_parameter_specs = {
- "I": {"units": "flux/arcsec^2", "shape": (None, None), "dynamic": True},
- "PA": {"units": "radians", "shape": (), "dynamic": False},
- "scale": {"units": "arcsec/grid-unit", "shape": (), "dynamic": False},
+ "I": {
+ "units": "flux/arcsec^2",
+ "shape": (None, None),
+ "dynamic": True,
+ "description": "the total flux within each pixel, represented as the log of the flux",
+ },
+ "PA": {
+ "units": "radians",
+ "shape": (),
+ "dynamic": False,
+ "description": "the position angle of the model, in radians",
+ },
+ "scale": {
+ "units": "arcsec/grid-unit",
+ "shape": (),
+ "dynamic": False,
+ "description": "the scale of the model, in arcsec per grid unit",
+ },
}
usable = True
diff --git a/astrophot/models/pixelated_psf.py b/astrophot/models/pixelated_psf.py
index 348670c6..e270edb1 100644
--- a/astrophot/models/pixelated_psf.py
+++ b/astrophot/models/pixelated_psf.py
@@ -33,13 +33,19 @@ class PixelatedPSF(PSFModel):
(essentially just divide the pixelscale by the upsampling factor
you used).
- **Parameters:**
- - `pixels`: the total flux within each pixel, represented as the log of the flux.
+ :param pixels: the total flux within each pixel, represented as the log of the flux.
"""
_model_type = "pixelated"
- _parameter_specs = {"pixels": {"units": "flux/pix^2", "shape": (None, None), "dynamic": True}}
+ _parameter_specs = {
+ "pixels": {
+ "units": "flux/pix^2",
+ "shape": (None, None),
+ "dynamic": True,
+ "description": "the total flux within each pixel, represented as the log of the flux",
+ }
+ }
usable = True
@torch.no_grad()
diff --git a/astrophot/models/planesky.py b/astrophot/models/planesky.py
index f0d572af..71516cba 100644
--- a/astrophot/models/planesky.py
+++ b/astrophot/models/planesky.py
@@ -13,22 +13,33 @@
class PlaneSky(SkyModel):
"""Sky background model using a tilted plane for the sky flux. The brightness for each pixel is defined as:
- $$I(X, Y) = I_0 + X*\\delta_x + Y*\\delta_y$$
+ .. math::
- where $I(X,Y)$ is the brightness as a function of image position $X, Y$,
- $I_0$ is the central sky brightness value, and $\\delta_x, \\delta_y$ are the slopes of
+ I(X, Y) = I_0 + X*\\delta_x + Y*\\delta_y
+
+ where :math:`I(X,Y)` is the brightness as a function of image position :math:`X, Y`,
+ :math:`I_0` is the central sky brightness value, and :math:`\\delta_x, \\delta_y` are the slopes of
the sky brightness plane.
- **Parameters:**
- - `I0`: central sky brightness value
- - `delta`: Tensor for slope of the sky brightness in each image dimension
+ :param I0: central sky brightness value
+ :param delta: Tensor for slope of the sky brightness in each image dimension
"""
_model_type = "plane"
_parameter_specs = {
- "I0": {"units": "flux/arcsec^2", "shape": (), "dynamic": True},
- "delta": {"units": "flux/arcsec", "shape": (2,), "dynamic": True},
+ "I0": {
+ "units": "flux/arcsec^2",
+ "shape": (),
+ "dynamic": True,
+ "description": "central sky brightness value",
+ },
+ "delta": {
+ "units": "flux/arcsec",
+ "shape": (2,),
+ "dynamic": True,
+ "description": "Tensor for slope of the sky brightness in each image dimension",
+ },
}
usable = True
diff --git a/astrophot/models/point_source.py b/astrophot/models/point_source.py
index 44707963..6e7cf3ad 100644
--- a/astrophot/models/point_source.py
+++ b/astrophot/models/point_source.py
@@ -26,14 +26,19 @@ class PointSource(ComponentModel):
other object which can essentially be entirely described by a
position and total flux (no structure).
- **Parameters:**
- - `flux`: The total flux of the point source
+ :param flux: The total flux of the point source
"""
_model_type = "point"
_parameter_specs = {
- "flux": {"units": "flux", "valid": (0, None), "shape": (), "dynamic": True},
+ "flux": {
+ "units": "flux",
+ "valid": (0, None),
+ "shape": (),
+ "dynamic": True,
+ "description": "The total flux of the point source",
+ },
}
internal_psf = True
usable = True
diff --git a/astrophot/models/psf_model_object.py b/astrophot/models/psf_model_object.py
index ab91a0b3..fe5c79e1 100644
--- a/astrophot/models/psf_model_object.py
+++ b/astrophot/models/psf_model_object.py
@@ -80,14 +80,12 @@ def sample(
the pixel centers. The output is the flux evaluated over the pixel grid
at native resolution (for the PSFImage associated with this model.)
- **Parameters:**
- - `i`: 2D array of x-coordinates of pixel centers (or pre-upsampled
- according to the `sampling_mode`) in pixel units.
- - `j`: 2D array of y-coordinates of pixel centers (or pre-upsampled
- according to the `sampling_mode`) in pixel units.
-
- **Returns:**
- - ``Z``: 2D array of flux values at each pixel center, representing the
+ :param i: 2D array of x-coordinates of pixel centers (or pre-upsampled
+ according to the ``sampling_mode``) in pixel units.
+ :param j: 2D array of y-coordinates of pixel centers (or pre-upsampled
+ according to the ``sampling_mode``) in pixel units.
+
+ :returns: ``Z``: 2D array of flux values at each pixel center, representing the
PSF model evaluated at those coordinates.
"""
Z = self.pixel_brightness(i, j)
diff --git a/astrophot/models/radial.py b/astrophot/models/radial.py
index ac3c1c33..24784155 100644
--- a/astrophot/models/radial.py
+++ b/astrophot/models/radial.py
@@ -24,6 +24,7 @@
TruncationMixin,
)
from .galaxy_model_object import GalaxyModel
+from ..utils.decorators import combine_docstrings
radial_models = (
SersicMixin,
@@ -39,18 +40,18 @@
__all__ = []
for mixin in radial_models:
# Galaxy Model
- g_mixin = type(
+ g_mixin = combine_docstrings(type(
mixin.__name__[:-5] + "Galaxy", (mixin, RadialMixin, GalaxyModel), {"usable": True}
- )
+ ))
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
# Truncated Galaxy Model
- t_mixin = type(
+ t_mixin = combine_docstrings(type(
"T" + mixin.__name__[:-5] + "Galaxy",
(TruncationMixin, mixin, RadialMixin, GalaxyModel),
{"usable": True},
- )
+ ))
globals()[t_mixin.__name__] = t_mixin
__all__.append(t_mixin.__name__)
@@ -59,18 +60,18 @@
(SuperEllipseMixin, FourierEllipseMixin, WarpMixin),
):
# Galaxy Model with additional perturbation mixin
- g_mixin = type(
+ g_mixin = combine_docstrings(type(
mixin.__name__[:-5] + n, (mixin, RadialMixin, p, GalaxyModel), {"usable": True}
- )
+ ))
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
# Truncated Galaxy Model with additional perturbation mixin
- t_mixin = type(
+ t_mixin = combine_docstrings(type(
"T" + mixin.__name__[:-5] + n,
(TruncationMixin, mixin, RadialMixin, p, GalaxyModel),
{"usable": True},
- )
+ ))
globals()[t_mixin.__name__] = t_mixin
__all__.append(t_mixin.__name__)
@@ -87,13 +88,15 @@
for mixin in iradial_models:
# Ray Galaxy Model
- r_mixin = type(mixin.__name__[1:-5] + "Ray", (mixin, RayMixin, GalaxyModel), {"usable": True})
+ r_mixin = combine_docstrings(type(
+ mixin.__name__[1:-5] + "Ray", (mixin, RayMixin, GalaxyModel), {"usable": True}
+ ))
globals()[r_mixin.__name__] = r_mixin
__all__.append(r_mixin.__name__)
# Wedge Galaxy Model
- w_mixin = type(
+ w_mixin = combine_docstrings(type(
mixin.__name__[1:-5] + "Wedge", (mixin, WedgeMixin, GalaxyModel), {"usable": True}
- )
+ ))
globals()[w_mixin.__name__] = w_mixin
__all__.append(w_mixin.__name__)
diff --git a/astrophot/models/radial_psf.py b/astrophot/models/radial_psf.py
index dcebe377..007aed8a 100644
--- a/astrophot/models/radial_psf.py
+++ b/astrophot/models/radial_psf.py
@@ -14,6 +14,7 @@
InclinedMixin,
)
from .psf_model_object import PSFModel
+from ..utils.decorators import combine_docstrings
radial_models = (
SersicPSFMixin,
@@ -26,20 +27,20 @@
SplinePSFMixin,
)
-EllipseMixin = type("EllipseMixin", (InclinedMixin,), {"usable": False, "_model_type": "ellipse"})
+EllipseMixin = combine_docstrings(type("EllipseMixin", (InclinedMixin,), {"usable": False, "_model_type": "ellipse"}))
__all__ = []
for mixin in radial_models:
# PSF Model
- g_mixin = type(mixin.__name__[:-5], (mixin, RadialMixin, PSFModel), {"usable": True})
+ g_mixin = combine_docstrings(type(mixin.__name__[:-5], (mixin, RadialMixin, PSFModel), {"usable": True}))
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
# Ellipse PSF Model
- g_mixin = type(
+ g_mixin = combine_docstrings(type(
mixin.__name__[:-5] + "Ellipse",
(mixin, EllipseMixin, RadialMixin, PSFModel),
{"usable": True},
- )
+ ))
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
@@ -48,10 +49,10 @@
(SuperEllipseMixin, FourierEllipseMixin, WarpMixin),
):
# Galaxy Model with additional perturbation mixin
- g_mixin = type(
+ g_mixin = combine_docstrings(type(
mixin.__name__[:-5] + n,
(mixin, InclinedMixin, RadialMixin, p, PSFModel),
{"usable": True},
- )
+ ))
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index 0423ebf1..b163aa86 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -1,4 +1,5 @@
from functools import wraps
+import re
import warnings
from inspect import cleandoc
import caskade as ck
@@ -42,13 +43,81 @@ def wrapped(*args, **kwargs):
return wrapped
+def _parse_docstring(doc):
+ """Parse a docstring into (body, params_dict).
+
+ Handles both RST ``:param name: desc`` format and markdown
+ ``**Parameters:**`` / ``**Options:**`` format.
+ Returns body text (params/options removed) and an ordered dict of {name: desc}.
+ """
+ params = {}
+
+ # --- RST-style :param name: desc (possibly multi-line) ---
+ for m in re.finditer(
+ r':param\s+(\w+):\s*(.*?)(?=\n:param\s|\n:type\s|\n\n|\Z)',
+ doc,
+ re.DOTALL,
+ ):
+ params[m.group(1)] = m.group(2).strip()
+
+ # --- Markdown-style **Parameters:** and **Options:** sections ---
+ for section_match in re.finditer(
+ r'\*\*(?:Parameters|Options):\*\*\n((?:[ \t]*-[^\n]*\n?)+)',
+ doc,
+ re.MULTILINE,
+ ):
+ for item in re.finditer(
+ r'[ \t]*-+\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)',
+ section_match.group(1),
+ re.DOTALL,
+ ):
+ params[item.group(1)] = item.group(2).strip()
+
+ # Strip :param/:type entries from body
+ body = re.sub(r'\n:(?:param|type)\s+\S+:.*?(?=\n:(?:param|type)\s|\n\n|\Z)', '', doc, flags=re.DOTALL)
+ # Strip markdown Parameters/Options sections from body
+ body = re.sub(r'\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+', '', body)
+ body = body.strip()
+
+ return body, params
+
+
def combine_docstrings(cls):
+ """Combine docstrings from a class and all of its base classes.
+
+ Finds all ``:param`` entries and markdown ``**Parameters:**`` /
+ ``**Options:**`` sections from every class in the MRO and merges
+ them into a single consolidated ``:param`` list so that Sphinx
+ autodoc renders them correctly.
+ """
+ # Collect params from full MRO (base → derived so derived class wins)
+ all_params = {}
+ for klass in reversed(cls.__mro__):
+ if klass is object:
+ continue
+ if not klass.__doc__:
+ continue
+ _, klass_params = _parse_docstring(cleandoc(klass.__doc__))
+ all_params.update(klass_params)
+
+ # Build combined body: cls body + direct-base bodies
try:
- combined_docs = [cleandoc(cls.__doc__)]
- except AttributeError:
- combined_docs = []
+ main_body, _ = _parse_docstring(cleandoc(cls.__doc__))
+ except (AttributeError, TypeError):
+ main_body = ""
+
for base in cls.__bases__:
- if base.__doc__:
- combined_docs.append(f"\n\n> SUBUNIT {base.__name__}\n\n{cleandoc(base.__doc__)}")
- cls.__doc__ = "\n".join(combined_docs).strip()
+ if base is object or not base.__doc__:
+ continue
+ base_body, _ = _parse_docstring(cleandoc(base.__doc__))
+ if base_body:
+ main_body += f"\n\n.. rubric:: {base.__name__}\n\n{base_body}"
+
+ # Append merged parameter list
+ if all_params:
+ main_body += "\n\n" + "\n".join(
+ f":param {name}: {desc}" for name, desc in all_params.items()
+ )
+
+ cls.__doc__ = main_body.strip()
return cls
diff --git a/docs/source/_config.yml b/docs/source/_config.yml
index 635dc983..de98afb1 100644
--- a/docs/source/_config.yml
+++ b/docs/source/_config.yml
@@ -1,51 +1,15 @@
-# Book settings
-# Learn more at https://jupyterbook.org/customize/config.html
-
-title: AstroPhot
-author: Connor Stone
-logo: ../../media/AP_logo.png
-
-# Force re-execution of notebooks on each build.
-# See https://jupyterbook.org/content/execute.html
-execute:
- execute_notebooks: force
- allow_errors: false
- timeout: 360
-
-# Define the name of the latex output file for PDF builds
-latex:
- latex_documents:
- targetname: book.tex
-
-# Add a bibtex file so that we can create citations
-# bibtex_bibfiles:
-# - references.bib
-
-# Information about where the book exists on the web
-repository:
- url: https://github.com/Autostronomy/AstroPhot # Online location of your book
- path_to_book: docs/source # Optional path to your book, relative to the repository root
- branch: main # Which branch of the repository should be used when creating links (optional)
-
-# Add GitHub buttons to your book
-# See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository
-html:
- favicon: ../media/AP_logo_favicon.ico
- use_issues_button: true
- use_repository_button: true
-
sphinx:
extra_extensions:
- "sphinx.ext.autodoc"
- "sphinx.ext.autosummary"
- "sphinx.ext.viewcode"
- # - "sphinx.ext.napoleon"
- # - "sphinx.ext.doctest"
- # - "sphinx.ext.coverage"
- # - "sphinx.ext.mathjax"
- # - "sphinx.ext.ifconfig"
+ - "sphinx.ext.mathjax"
config:
html_theme_options:
logo:
image_light: ../../media/AP_logo.png
image_dark: ../../media/AP_logo_white.png
+ autodoc_default_options:
+ members: true
+ undoc-members: true
+ show-inheritance: true
diff --git a/docs/source/astrophotdocs/errors.rst b/docs/source/astrophotdocs/errors.rst
new file mode 100644
index 00000000..cac06aec
--- /dev/null
+++ b/docs/source/astrophotdocs/errors.rst
@@ -0,0 +1,7 @@
+Errors
+======
+
+.. automodule:: astrophot.errors
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/source/astrophotdocs/fit.rst b/docs/source/astrophotdocs/fit.rst
new file mode 100644
index 00000000..d4bbeacc
--- /dev/null
+++ b/docs/source/astrophotdocs/fit.rst
@@ -0,0 +1,7 @@
+Fitting
+=======
+
+.. automodule:: astrophot.fit
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/source/astrophotdocs/image.rst b/docs/source/astrophotdocs/image.rst
new file mode 100644
index 00000000..bbf4a0fe
--- /dev/null
+++ b/docs/source/astrophotdocs/image.rst
@@ -0,0 +1,7 @@
+Image
+=====
+
+.. automodule:: astrophot.image
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/source/astrophotdocs/index.rst b/docs/source/astrophotdocs/index.rst
index 6d12dec0..1fde5efb 100644
--- a/docs/source/astrophotdocs/index.rst
+++ b/docs/source/astrophotdocs/index.rst
@@ -1,21 +1,15 @@
-====================
-AstroPhot Docstrings
-====================
+AstroPhot API Reference
+=======================
-Here you will find all of the AstroPhot class and method docstrings, built using
-markdown formatting. These are useful for understanding the details of a given
-model and can also be accessed via the python help command
-```help(ap.object)```. For the AstroPhot ``ap.Model`` objects, the docstrings are a
-combination of the various base-classes and mixins that make them up. They are
-very detailed, but can be a bit awkward in their formatting, the good news is
-that a lot of useful information is available there!
+This reference documents all public classes and functions in AstroPhot.
+Use the module index below to navigate to specific components.
.. toctree::
- :maxdepth: 2
+ :maxdepth: 2
- models
- image
- fit
- plots
- utils
- errors
+ models
+ image
+ fit
+ plots
+ utils
+ errors
diff --git a/docs/source/astrophotdocs/models.rst b/docs/source/astrophotdocs/models.rst
new file mode 100644
index 00000000..f0c0147a
--- /dev/null
+++ b/docs/source/astrophotdocs/models.rst
@@ -0,0 +1,87 @@
+Models
+======
+
+.. automodule:: astrophot.models
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Sky Models
+----------
+
+.. automodule:: astrophot.models.flatsky
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.planesky
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.bilinear_sky
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Point Source Models
+-------------------
+
+.. automodule:: astrophot.models.point_source
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Galaxy Models
+-------------
+
+.. automodule:: astrophot.models.radial
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.edgeon
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.gaussian_ellipsoid
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.multi_gaussian_expansion
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.pixelated_model
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+PSF Models
+----------
+
+.. automodule:: astrophot.models.radial_psf
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.airy
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: astrophot.models.pixelated_psf
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Model Mixins
+------------
+
+.. automodule:: astrophot.models.mixins
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/source/astrophotdocs/plots.rst b/docs/source/astrophotdocs/plots.rst
new file mode 100644
index 00000000..222ac8ca
--- /dev/null
+++ b/docs/source/astrophotdocs/plots.rst
@@ -0,0 +1,7 @@
+Plots
+=====
+
+.. automodule:: astrophot.plots
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/source/astrophotdocs/utils.rst b/docs/source/astrophotdocs/utils.rst
new file mode 100644
index 00000000..e780c7f4
--- /dev/null
+++ b/docs/source/astrophotdocs/utils.rst
@@ -0,0 +1,7 @@
+Utilities
+=========
+
+.. automodule:: astrophot.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/make_docs.py b/make_docs.py
deleted file mode 100644
index f9670b26..00000000
--- a/make_docs.py
+++ /dev/null
@@ -1,103 +0,0 @@
-import astrophot as ap
-import nbformat
-from nbformat.v4 import new_notebook, new_markdown_cell
-import pkgutil
-from types import ModuleType, FunctionType
-import os
-from textwrap import dedent
-from inspect import cleandoc, getmodule, signature
-
-skip_methods = [
- "to_valid",
- "topological_ordering",
- "to_static",
- "to_dynamic",
- "unlink",
- "update_graph",
- "save_state",
- "load_state",
- "append_state",
- "link",
- "graphviz",
- "graph_print",
- "graph_dict",
- "from_valid",
- "fill_params",
- "fill_kwargs",
- "fill_dynamic_values",
- "clear_params",
- "build_params_list",
- "build_params_dict",
- "build_params_array",
-]
-
-
-def dot_path(path):
- i = path.rfind("AstroPhot")
- path = path[i + 10 :]
- path = path.replace("/", ".")
- return path[:-3]
-
-
-def gather_docs(module, module_only=False):
- docs = {}
- for name in module.__all__:
- obj = getattr(module, name)
- if module_only and not isinstance(obj, ModuleType):
- continue
- if isinstance(obj, type):
- if obj.__doc__ is None:
- continue
- docs[name] = cleandoc(obj.__doc__)
- subfuncs = [docs[name]]
- for attr in dir(obj):
- if attr.startswith("_"):
- continue
- if attr in skip_methods:
- continue
- attrobj = getattr(obj, attr)
- if not isinstance(attrobj, FunctionType):
- continue
- if attrobj.__doc__ is None:
- continue
- sig = str(signature(attrobj)).replace("self,", "").replace("self", "")
- subfuncs.append(f"**method:** {attr}{sig}\n\n" + cleandoc(attrobj.__doc__))
- if len(subfuncs) > 1:
- docs[name] = "\n\n".join(subfuncs)
- elif isinstance(obj, FunctionType):
- if obj.__doc__ is None:
- continue
- sig = str(signature(obj))
- docs[name] = "**signature:** " + name + sig + "\n\n" + cleandoc(obj.__doc__)
- elif isinstance(obj, ModuleType):
- docs[name] = gather_docs(obj)
- else:
- print(f"!!!unexpected type {type(obj)}!!!")
- return docs
-
-
-def make_cells(mod_dict, path, depth=2):
- print(mod_dict.keys())
- cells = []
- for k in mod_dict:
- if isinstance(mod_dict[k], str):
- cells.append(new_markdown_cell(f"{'#'*depth} {path}.{k}\n\n" + mod_dict[k]))
- elif isinstance(mod_dict[k], dict):
- print(k)
- cells += make_cells(mod_dict[k], path=path + "." + k, depth=depth + 1)
- return cells
-
-
-output_dir = "docs/source/astrophotdocs"
-all_ap = gather_docs(ap, True)
-
-for submodule in all_ap:
- nb = new_notebook()
- nb.cells = [new_markdown_cell(f"# {submodule}")] + make_cells(
- all_ap[submodule], f"astrophot.{submodule}"
- )
-
- filename = f"{submodule}.ipynb"
- path = os.path.join(output_dir, filename)
- with open(path, "w", encoding="utf-8") as f:
- nbformat.write(nb, f)
From 92f936f9391db63c074f4fa4c0af4fd0612a7505 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 20:02:46 +0000
Subject: [PATCH 03/16] Fix regex patterns in _parse_docstring for robustness
- Use \w+ instead of \S+ when matching param/type names in body stripping
- Use single dash '-' with MULTILINE flag for markdown list item matching
- These address edge cases around colons in descriptions and multi-dash lines
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
astrophot/utils/decorators.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index b163aa86..62fc8129 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -67,14 +67,14 @@ def _parse_docstring(doc):
re.MULTILINE,
):
for item in re.finditer(
- r'[ \t]*-+\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)',
+ r'^[ \t]*-\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)',
section_match.group(1),
- re.DOTALL,
+ re.DOTALL | re.MULTILINE,
):
params[item.group(1)] = item.group(2).strip()
# Strip :param/:type entries from body
- body = re.sub(r'\n:(?:param|type)\s+\S+:.*?(?=\n:(?:param|type)\s|\n\n|\Z)', '', doc, flags=re.DOTALL)
+ body = re.sub(r'\n:(?:param|type)\s+\w+:.*?(?=\n:(?:param|type)\s|\n\n|\Z)', '', doc, flags=re.DOTALL)
# Strip markdown Parameters/Options sections from body
body = re.sub(r'\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+', '', body)
body = body.strip()
From 72c770a0af78f0c3fe95a4f6189f76f1dcb026c4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 20:05:29 +0000
Subject: [PATCH 04/16] Fix :returns: RST format in psf_model_object.py
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
astrophot/models/psf_model_object.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/astrophot/models/psf_model_object.py b/astrophot/models/psf_model_object.py
index fe5c79e1..8e6c01ad 100644
--- a/astrophot/models/psf_model_object.py
+++ b/astrophot/models/psf_model_object.py
@@ -85,7 +85,7 @@ def sample(
:param j: 2D array of y-coordinates of pixel centers (or pre-upsampled
according to the ``sampling_mode``) in pixel units.
- :returns: ``Z``: 2D array of flux values at each pixel center, representing the
+ :returns: 2D array (``Z``) of flux values at each pixel center, representing the
PSF model evaluated at those coordinates.
"""
Z = self.pixel_brightness(i, j)
From 8f60d572d23b1e3fbaee7d6c5bcf85f490fbcb94 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 20:13:18 +0000
Subject: [PATCH 05/16] Changes before error encountered
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/d8acb003-647d-4ac3-bb3b-92de85d29ff9
---
astrophot/models/psf_model_object.py | 25 +++++++++++------
astrophot/models/radial_psf.py | 10 ++++++-
astrophot/models/sky_model_object.py | 20 +++++++++-----
astrophot/utils/decorators.py | 7 ++---
docs/source/_config.yml | 40 ++++++++++++++++++++++++++++
5 files changed, 84 insertions(+), 18 deletions(-)
diff --git a/astrophot/models/psf_model_object.py b/astrophot/models/psf_model_object.py
index 8e6c01ad..3e7bc620 100644
--- a/astrophot/models/psf_model_object.py
+++ b/astrophot/models/psf_model_object.py
@@ -14,17 +14,26 @@ class PSFModel(GradMixin, SampleMixin, Model):
"""Prototype point source (typically a star) model, to be subclassed
by other point source models which define specific behavior.
- PSF_Models behave differently than component models. For starters,
- their target image must be a PSF_Image object instead of a
- Target_Image object. PSF_Models also don't define a "center"
- variable since their center is always (0,0) just like a
- PSF_Image. A PSF_Model will never be convolved with a PSF_Model
- (that's it's job!), so a lot of the sampling method is simpler.
-
+ PSF models behave differently than component models. Their target image
+ must be a ``PSFImage`` object instead of a ``TargetImage`` object.
+ PSF models do not fit a free ``center`` parameter; their center is
+ always ``(0, 0)`` in pixel coordinates, matching the convention of a
+ ``PSFImage``. A PSF model is never convolved with another PSF model.
+
+ :param center: Center of the PSF in pixel coordinates ``[x, y]``.
+ Fixed at ``(0, 0)`` by default and not included in the fit.
+ :param normalize_psf: When ``True`` (default) the sampled PSF is
+ normalised so that its total flux within the fitting window equals 1.
"""
_parameter_specs = {
- "center": {"units": "pix", "value": (0.0, 0.0), "shape": (2,), "dynamic": False},
+ "center": {
+ "units": "pix",
+ "value": (0.0, 0.0),
+ "shape": (2,),
+ "dynamic": False,
+ "description": "center of the PSF in pixel coordinates [x, y], fixed at (0,0)",
+ },
}
_model_type = "psf"
usable = False
diff --git a/astrophot/models/radial_psf.py b/astrophot/models/radial_psf.py
index 007aed8a..ea2f973f 100644
--- a/astrophot/models/radial_psf.py
+++ b/astrophot/models/radial_psf.py
@@ -27,7 +27,15 @@
SplinePSFMixin,
)
-EllipseMixin = combine_docstrings(type("EllipseMixin", (InclinedMixin,), {"usable": False, "_model_type": "ellipse"}))
+EllipseMixin = type(
+ "EllipseMixin",
+ (InclinedMixin,),
+ {
+ "usable": False,
+ "_model_type": "ellipse",
+ "__doc__": "PSF model with elliptical isophotes defined by a position angle and axis ratio.",
+ },
+)
__all__ = []
for mixin in radial_models:
# PSF Model
diff --git a/astrophot/models/sky_model_object.py b/astrophot/models/sky_model_object.py
index 86762b2e..63b0dac6 100644
--- a/astrophot/models/sky_model_object.py
+++ b/astrophot/models/sky_model_object.py
@@ -6,15 +6,23 @@
@combine_docstrings
class SkyModel(ComponentModel):
- """prototype class for any sky background model. This simply imposes
- that the center is a locked parameter, not involved in the
- fit. Also, a sky model object has no psf mode or integration mode
- by default since it is intended to change over much larger spatial
- scales than the psf or pixel size.
+ """Prototype class for any sky background model.
+
+ This base class imposes that the ``center`` is a locked parameter not
+ involved in the fit. Sky models also have no PSF convolution or
+ integration mode by default, since sky backgrounds vary on spatial
+ scales much larger than the PSF or pixel size.
"""
- _parameter_specs = {"center": {"units": "arcsec", "shape": (2,), "dynamic": False}}
+ _parameter_specs = {
+ "center": {
+ "units": "arcsec",
+ "shape": (2,),
+ "dynamic": False,
+ "description": "center of the sky model in arcsec [x, y], locked to the image center",
+ }
+ }
_model_type = "sky"
usable = False
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index 62fc8129..c9d6ea61 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -53,8 +53,9 @@ def _parse_docstring(doc):
params = {}
# --- RST-style :param name: desc (possibly multi-line) ---
+ # Split on ":param " boundaries so multi-line descriptions are captured correctly.
for m in re.finditer(
- r':param\s+(\w+):\s*(.*?)(?=\n:param\s|\n:type\s|\n\n|\Z)',
+ r':param\s+(\w+):\s*((?:(?!\n:(?:param|type)\s).)*)',
doc,
re.DOTALL,
):
@@ -73,8 +74,8 @@ def _parse_docstring(doc):
):
params[item.group(1)] = item.group(2).strip()
- # Strip :param/:type entries from body
- body = re.sub(r'\n:(?:param|type)\s+\w+:.*?(?=\n:(?:param|type)\s|\n\n|\Z)', '', doc, flags=re.DOTALL)
+ # Strip :param/:type entries from body (handle multi-line descriptions)
+ body = re.sub(r':(?:param|type)\s+\w+:\s*(?:(?!\n:(?:param|type)\s).)*', '', doc, flags=re.DOTALL)
# Strip markdown Parameters/Options sections from body
body = re.sub(r'\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+', '', body)
body = body.strip()
diff --git a/docs/source/_config.yml b/docs/source/_config.yml
index de98afb1..33cc634f 100644
--- a/docs/source/_config.yml
+++ b/docs/source/_config.yml
@@ -1,9 +1,49 @@
+# Book settings
+# Learn more at https://jupyterbook.org/customize/config.html
+
+title: AstroPhot
+author: Connor Stone
+logo: ../../media/AP_logo.png
+
+# Force re-execution of notebooks on each build.
+# See https://jupyterbook.org/content/execute.html
+execute:
+ execute_notebooks: force
+ allow_errors: false
+ timeout: 360
+
+# Define the name of the latex output file for PDF builds
+latex:
+ latex_documents:
+ targetname: book.tex
+
+# Add a bibtex file so that we can create citations
+# bibtex_bibfiles:
+# - references.bib
+
+# Information about where the book exists on the web
+repository:
+ url: https://github.com/Autostronomy/AstroPhot # Online location of your book
+ path_to_book: docs/source # Optional path to your book, relative to the repository root
+ branch: main # Which branch of the repository should be used when creating links (optional)
+
+# Add GitHub buttons to your book
+# See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository
+html:
+ favicon: ../media/AP_logo_favicon.ico
+ use_issues_button: true
+ use_repository_button: true
+
sphinx:
extra_extensions:
- "sphinx.ext.autodoc"
- "sphinx.ext.autosummary"
- "sphinx.ext.viewcode"
- "sphinx.ext.mathjax"
+ # - "sphinx.ext.napoleon"
+ # - "sphinx.ext.doctest"
+ # - "sphinx.ext.coverage"
+ # - "sphinx.ext.ifconfig"
config:
html_theme_options:
logo:
From 7013cc7aa12baf61b65bb1130f8733ac2b20252c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Mar 2026 00:36:04 +0000
Subject: [PATCH 06/16] Label model parameters in combined docs
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/cff088e1-801d-4b12-9940-ce2887562ad3
---
astrophot/utils/decorators.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index c9d6ea61..a2628f50 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -116,6 +116,14 @@ def combine_docstrings(cls):
# Append merged parameter list
if all_params:
+ model_params = set()
+ try:
+ model_params = set(cls.parameter_specs.keys())
+ except Exception:
+ model_params = set()
+ for name, desc in list(all_params.items()):
+ if name in model_params and "[model param]" not in desc:
+ all_params[name] = f"{desc} [model param]"
main_body += "\n\n" + "\n".join(
f":param {name}: {desc}" for name, desc in all_params.items()
)
From 86617a9cc94dfe3e74f41a7418c18947ebaafa0e Mon Sep 17 00:00:00 2001
From: Connor Stone
Date: Tue, 24 Mar 2026 20:48:32 -0400
Subject: [PATCH 07/16] fix readthedocs config for new documentation
---
.readthedocs.yaml | 2 --
.../tutorials/FunctionalInterface.ipynb | 22 +++++++++++--------
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 9ff01961..3f53ca8d 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -26,8 +26,6 @@ build:
- graphviz
jobs:
pre_build:
- # Build docstring jupyter notebooks
- - "python make_docs.py"
# Generate the Sphinx configuration for this Jupyter Book so it builds.
- "jupyter-book config sphinx docs/source/"
# Create font cache ahead of jupyter book
diff --git a/docs/source/tutorials/FunctionalInterface.ipynb b/docs/source/tutorials/FunctionalInterface.ipynb
index 8676d0a7..a2f9dc64 100644
--- a/docs/source/tutorials/FunctionalInterface.ipynb
+++ b/docs/source/tutorials/FunctionalInterface.ipynb
@@ -343,9 +343,9 @@
"source": [
"# Let's compare how fast the two code are\n",
"print(\"Functional interface timings:\")\n",
- "%timeit model(params_true, *extra)\n",
+ "%timeit jax.block_until_ready(model(params_true, *extra))\n",
"print(\"AstroPhot model timings:\")\n",
- "%timeit apmodel()"
+ "%timeit jax.block_until_ready(apmodel())"
]
},
{
@@ -366,22 +366,26 @@
"outputs": [],
"source": [
"jmodel = jax.jit(model)\n",
- "_ = jmodel(params_true, *extra)\n",
- "_ = jmodel(params_true, *extra)\n",
+ "_ = jax.block_until_ready(jmodel(params_true, *extra))\n",
+ "_ = jax.block_until_ready(jmodel(params_true, *extra))\n",
"print(\"JIT-compiled functional interface timings:\")\n",
- "%timeit jmodel(params_true, *extra)\n",
+ "%timeit jax.block_until_ready(jmodel(params_true, *extra))\n",
"japmodel = jax.jit(lambda: apmodel()._data)\n",
- "_ = japmodel()\n",
- "_ = japmodel()\n",
+ "_ = jax.block_until_ready(japmodel())\n",
+ "_ = jax.block_until_ready(japmodel())\n",
"print(\"JIT-compiled AstroPhot model timings:\")\n",
- "%timeit japmodel()"
+ "%timeit jax.block_until_ready(japmodel())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
- "metadata": {},
+ "metadata": {
+ "tags": [
+ "hide-output"
+ ]
+ },
"outputs": [],
"source": [
"# Make 8 chains, starting at the true parameters\n",
From 625270974bdffac111a40deeea5589474fc05e8a Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Wed, 25 Mar 2026 00:48:53 +0000
Subject: [PATCH 08/16] style: pre-commit fixes
---
astrophot/models/radial.py | 48 ++++++++++++++++++----------------
astrophot/models/radial_psf.py | 28 ++++++++++++--------
astrophot/utils/decorators.py | 12 +++++----
3 files changed, 50 insertions(+), 38 deletions(-)
diff --git a/astrophot/models/radial.py b/astrophot/models/radial.py
index 24784155..9dcc4ab1 100644
--- a/astrophot/models/radial.py
+++ b/astrophot/models/radial.py
@@ -40,18 +40,20 @@
__all__ = []
for mixin in radial_models:
# Galaxy Model
- g_mixin = combine_docstrings(type(
- mixin.__name__[:-5] + "Galaxy", (mixin, RadialMixin, GalaxyModel), {"usable": True}
- ))
+ g_mixin = combine_docstrings(
+ type(mixin.__name__[:-5] + "Galaxy", (mixin, RadialMixin, GalaxyModel), {"usable": True})
+ )
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
# Truncated Galaxy Model
- t_mixin = combine_docstrings(type(
- "T" + mixin.__name__[:-5] + "Galaxy",
- (TruncationMixin, mixin, RadialMixin, GalaxyModel),
- {"usable": True},
- ))
+ t_mixin = combine_docstrings(
+ type(
+ "T" + mixin.__name__[:-5] + "Galaxy",
+ (TruncationMixin, mixin, RadialMixin, GalaxyModel),
+ {"usable": True},
+ )
+ )
globals()[t_mixin.__name__] = t_mixin
__all__.append(t_mixin.__name__)
@@ -60,18 +62,20 @@
(SuperEllipseMixin, FourierEllipseMixin, WarpMixin),
):
# Galaxy Model with additional perturbation mixin
- g_mixin = combine_docstrings(type(
- mixin.__name__[:-5] + n, (mixin, RadialMixin, p, GalaxyModel), {"usable": True}
- ))
+ g_mixin = combine_docstrings(
+ type(mixin.__name__[:-5] + n, (mixin, RadialMixin, p, GalaxyModel), {"usable": True})
+ )
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
# Truncated Galaxy Model with additional perturbation mixin
- t_mixin = combine_docstrings(type(
- "T" + mixin.__name__[:-5] + n,
- (TruncationMixin, mixin, RadialMixin, p, GalaxyModel),
- {"usable": True},
- ))
+ t_mixin = combine_docstrings(
+ type(
+ "T" + mixin.__name__[:-5] + n,
+ (TruncationMixin, mixin, RadialMixin, p, GalaxyModel),
+ {"usable": True},
+ )
+ )
globals()[t_mixin.__name__] = t_mixin
__all__.append(t_mixin.__name__)
@@ -88,15 +92,15 @@
for mixin in iradial_models:
# Ray Galaxy Model
- r_mixin = combine_docstrings(type(
- mixin.__name__[1:-5] + "Ray", (mixin, RayMixin, GalaxyModel), {"usable": True}
- ))
+ r_mixin = combine_docstrings(
+ type(mixin.__name__[1:-5] + "Ray", (mixin, RayMixin, GalaxyModel), {"usable": True})
+ )
globals()[r_mixin.__name__] = r_mixin
__all__.append(r_mixin.__name__)
# Wedge Galaxy Model
- w_mixin = combine_docstrings(type(
- mixin.__name__[1:-5] + "Wedge", (mixin, WedgeMixin, GalaxyModel), {"usable": True}
- ))
+ w_mixin = combine_docstrings(
+ type(mixin.__name__[1:-5] + "Wedge", (mixin, WedgeMixin, GalaxyModel), {"usable": True})
+ )
globals()[w_mixin.__name__] = w_mixin
__all__.append(w_mixin.__name__)
diff --git a/astrophot/models/radial_psf.py b/astrophot/models/radial_psf.py
index ea2f973f..59743148 100644
--- a/astrophot/models/radial_psf.py
+++ b/astrophot/models/radial_psf.py
@@ -39,16 +39,20 @@
__all__ = []
for mixin in radial_models:
# PSF Model
- g_mixin = combine_docstrings(type(mixin.__name__[:-5], (mixin, RadialMixin, PSFModel), {"usable": True}))
+ g_mixin = combine_docstrings(
+ type(mixin.__name__[:-5], (mixin, RadialMixin, PSFModel), {"usable": True})
+ )
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
# Ellipse PSF Model
- g_mixin = combine_docstrings(type(
- mixin.__name__[:-5] + "Ellipse",
- (mixin, EllipseMixin, RadialMixin, PSFModel),
- {"usable": True},
- ))
+ g_mixin = combine_docstrings(
+ type(
+ mixin.__name__[:-5] + "Ellipse",
+ (mixin, EllipseMixin, RadialMixin, PSFModel),
+ {"usable": True},
+ )
+ )
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
@@ -57,10 +61,12 @@
(SuperEllipseMixin, FourierEllipseMixin, WarpMixin),
):
# Galaxy Model with additional perturbation mixin
- g_mixin = combine_docstrings(type(
- mixin.__name__[:-5] + n,
- (mixin, InclinedMixin, RadialMixin, p, PSFModel),
- {"usable": True},
- ))
+ g_mixin = combine_docstrings(
+ type(
+ mixin.__name__[:-5] + n,
+ (mixin, InclinedMixin, RadialMixin, p, PSFModel),
+ {"usable": True},
+ )
+ )
globals()[g_mixin.__name__] = g_mixin
__all__.append(g_mixin.__name__)
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index a2628f50..f15adfe0 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -55,7 +55,7 @@ def _parse_docstring(doc):
# --- RST-style :param name: desc (possibly multi-line) ---
# Split on ":param " boundaries so multi-line descriptions are captured correctly.
for m in re.finditer(
- r':param\s+(\w+):\s*((?:(?!\n:(?:param|type)\s).)*)',
+ r":param\s+(\w+):\s*((?:(?!\n:(?:param|type)\s).)*)",
doc,
re.DOTALL,
):
@@ -63,21 +63,23 @@ def _parse_docstring(doc):
# --- Markdown-style **Parameters:** and **Options:** sections ---
for section_match in re.finditer(
- r'\*\*(?:Parameters|Options):\*\*\n((?:[ \t]*-[^\n]*\n?)+)',
+ r"\*\*(?:Parameters|Options):\*\*\n((?:[ \t]*-[^\n]*\n?)+)",
doc,
re.MULTILINE,
):
for item in re.finditer(
- r'^[ \t]*-\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)',
+ r"^[ \t]*-\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)",
section_match.group(1),
re.DOTALL | re.MULTILINE,
):
params[item.group(1)] = item.group(2).strip()
# Strip :param/:type entries from body (handle multi-line descriptions)
- body = re.sub(r':(?:param|type)\s+\w+:\s*(?:(?!\n:(?:param|type)\s).)*', '', doc, flags=re.DOTALL)
+ body = re.sub(
+ r":(?:param|type)\s+\w+:\s*(?:(?!\n:(?:param|type)\s).)*", "", doc, flags=re.DOTALL
+ )
# Strip markdown Parameters/Options sections from body
- body = re.sub(r'\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+', '', body)
+ body = re.sub(r"\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+", "", body)
body = body.strip()
return body, params
From 7f4274299df1ef2bd53da076c4bfcf1df9617cd9 Mon Sep 17 00:00:00 2001
From: Connor Stone
Date: Tue, 24 Mar 2026 21:37:02 -0400
Subject: [PATCH 09/16] tweak documentation formatting
---
astrophot/image/image_object.py | 27 +++++++++++---------------
astrophot/models/basis.py | 7 +++----
astrophot/models/basis_psf.py | 6 ++----
astrophot/models/mixins/sample.py | 32 +++++++++++++++----------------
astrophot/utils/decorators.py | 28 ++++++++++++++++++---------
docs/source/_toc.yml | 3 +--
6 files changed, 51 insertions(+), 52 deletions(-)
diff --git a/astrophot/image/image_object.py b/astrophot/image/image_object.py
index 6fc57609..8e25e349 100644
--- a/astrophot/image/image_object.py
+++ b/astrophot/image/image_object.py
@@ -24,22 +24,17 @@ class Image(Module):
image boundaries. It also provides methods for determining the coordinate
locations of pixels
- **Args:**
- - `data`: The image data as a tensor of pixel values. If not provided, a tensor of zeros will be created.
- - `zeropoint`: The zeropoint of the image, which is used to convert from pixel flux to magnitude.
- - `crpix`: The reference pixel coordinates in the image, which is used to convert from pixel coordinates to tangent plane coordinates.
- - `pixelscale`: The side length of a pixel, used to create a simple diagonal CD matrix.
- - `wcs`: An optional Astropy WCS object to initialize the image.
- - `filename`: The filename to load the image from. If provided, the image will be loaded from the file.
- - `hduext`: The HDU extension to load from the FITS file specified in `filename`.
- - `identity`: An optional identity string for the image.
-
- these parameters are added to the optimization model:
-
- **Parameters:**
- - `crval`: The reference coordinate of the image in degrees [RA, DEC].
- - `crtan`: The tangent plane coordinate of the image in arcseconds [x, y].
- - `CD`: The coordinate transformation matrix in arcseconds/pixel.
+ :param data: The image data as a tensor of pixel values. If not provided, a tensor of zeros will be created.
+ :param zeropoint: The zeropoint of the image, which is used to convert from pixel flux to magnitude.
+ :param crpix: The reference pixel coordinates in the image, which is used to convert from pixel coordinates to tangent plane coordinates.
+ :param pixelscale: The side length of a pixel, used to create a simple diagonal CD matrix.
+ :param wcs: An optional Astropy WCS object to initialize the image.
+ :param filename: The filename to load the image from. If provided, the image will be loaded from the file.
+ :param hduext: The HDU extension to load from the FITS file specified in `filename`.
+ :param identity: An optional identity string for the image.
+ :param crval: The reference coordinate of the image in degrees [RA, DEC].
+ :param crtan: The tangent plane coordinate of the image in arcseconds [x, y].
+ :param CD: The coordinate transformation matrix in arcseconds/pixel.
"""
expect_ctype = (("RA---TAN",), ("DEC--TAN",))
diff --git a/astrophot/models/basis.py b/astrophot/models/basis.py
index 364c2bea..52694ec7 100644
--- a/astrophot/models/basis.py
+++ b/astrophot/models/basis.py
@@ -27,10 +27,9 @@ class BasisModel(ComponentModel):
range of sources, but depending on the number of basis elements it can become
computationally expensive to optimize.
- **Parameters:**
- - `weights`: The weights of the basis set of images in units of flux.
- - `PA`: the position angle of the model, in radians.
- - `scale`: the scale of the model, in arcsec per grid unit.
+ :param weights: The weights of the basis set of images in units of flux.
+ :param PA: the position angle of the model, in radians.
+ :param scale: the scale of the model, in arcsec per grid unit.
"""
_model_type = "basis"
diff --git a/astrophot/models/basis_psf.py b/astrophot/models/basis_psf.py
index b7ad25c4..71ef9fea 100644
--- a/astrophot/models/basis_psf.py
+++ b/astrophot/models/basis_psf.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple
+from typing import Union
import torch
import numpy as np
@@ -10,7 +10,6 @@
from ..errors import SpecificationConflict
from ..param import forward
from . import func
-from ..utils.initialize import polar_decomposition
__all__ = ["PixelBasisPSF"]
@@ -25,8 +24,7 @@ class PixelBasisPSF(PSFModel):
accurate for smooth models, so it is possible to do the expensive
interpolation before optimization and save time.
- **Parameters:**
- - `weights`: The weights of the basis set of images in units of flux.
+ :param weights: The weights of the basis set of images in units of flux.
"""
_model_type = "basis"
diff --git a/astrophot/models/mixins/sample.py b/astrophot/models/mixins/sample.py
index dc089984..db15124e 100644
--- a/astrophot/models/mixins/sample.py
+++ b/astrophot/models/mixins/sample.py
@@ -13,21 +13,20 @@
class SampleMixin:
"""
- **Options:**
- - `sampling_mode`: The method used to sample the model in image pixels. Options are:
- - `auto`: Automatically choose the sampling method based on the image size.
- - `midpoint`: Use midpoint sampling, evaluate the brightness at the center of each pixel.
- - `simpsons`: Use Simpson's rule for sampling integrating each pixel.
- - `quad:x`: Use quadrature sampling with order x, where x is a positive integer to integrate each pixel.
- - `integrate_mode`: The method used to select pixels to integrate further where the model varies significantly. Options are:
- - `none`: No extra integration is performed (beyond the sampling_mode).
- - `bright`: Select the brightest pixels for further integration.
- - `threshold`: Select pixels which show signs of significant higher order derivatives.
- - `integrate_tolerance`: The tolerance for selecting a pixel in the integration method. This is the total flux fraction that is integrated over the image.
- - `integrate_fraction`: The fraction of the pixels to super sample during integration.
- - `integrate_max_depth`: The maximum depth of the integration method.
- - `integrate_gridding`: The gridding used for the integration method to super-sample a pixel at each iteration.
- - `integrate_quad_order`: The order of the quadrature used for the integration method on the super sampled pixels.
+ :param sampling_mode: The method used to sample the model in image pixels. Options are:
+ * `auto`: Automatically choose the sampling method based on the image size.
+ * `midpoint`: Use midpoint sampling, evaluate the brightness at the center of each pixel.
+ * `simpsons`: Use Simpson's rule for sampling integrating each pixel.
+ * `quad:x`: Use quadrature sampling with order x, where x is a positive integer to integrate each pixel.
+ :param integrate_mode: The method used to select pixels to integrate further where the model varies significantly. Options are:
+ * `none`: No extra integration is performed (beyond the sampling_mode).
+ * `bright`: Select the brightest pixels for further integration.
+ * `threshold`: Select pixels which show signs of significant higher order derivatives.
+ :param integrate_tolerance: The tolerance for selecting a pixel in the integration method. This is the total flux fraction that is integrated over the image.
+ :param integrate_fraction: The fraction of the pixels to super sample during integration.
+ :param integrate_max_depth: The maximum depth of the integration method.
+ :param integrate_gridding: The gridding used for the integration method to super-sample a pixel at each iteration.
+ :param integrate_quad_order: The order of the quadrature used for the integration method on the super sampled pixels.
"""
integrate_fraction = 0.05 # fraction of the pixels to super sample
@@ -190,8 +189,7 @@ def integrate_mode(self, integrate_mode):
class GradMixin:
"""
- **Options:**
- - `jacobian_maxparams`: The maximum number of parameters before the Jacobian will be broken into smaller chunks. This is helpful for limiting the memory requirements to fit a model.
+ :param jacobian_maxparams: The maximum number of parameters before the Jacobian will be broken into smaller chunks. This is helpful for limiting the memory requirements to fit a model.
"""
# Maximum size of parameter list before jacobian will be broken into smaller chunks, this is helpful for limiting the memory requirements to build a model, lower jacobian_chunksize is slower but uses less memory
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index a2628f50..7baf970a 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -55,7 +55,7 @@ def _parse_docstring(doc):
# --- RST-style :param name: desc (possibly multi-line) ---
# Split on ":param " boundaries so multi-line descriptions are captured correctly.
for m in re.finditer(
- r':param\s+(\w+):\s*((?:(?!\n:(?:param|type)\s).)*)',
+ r":param\s+(\w+):\s*((?:(?!\n:(?:param|type)\s).)*)",
doc,
re.DOTALL,
):
@@ -63,21 +63,23 @@ def _parse_docstring(doc):
# --- Markdown-style **Parameters:** and **Options:** sections ---
for section_match in re.finditer(
- r'\*\*(?:Parameters|Options):\*\*\n((?:[ \t]*-[^\n]*\n?)+)',
+ r"\*\*(?:Parameters|Options):\*\*\n((?:[ \t]*-[^\n]*\n?)+)",
doc,
re.MULTILINE,
):
for item in re.finditer(
- r'^[ \t]*-\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)',
+ r"^[ \t]*-\s+`(\w+)`\s*:\s*(.+?)(?=\n[ \t]*-|\Z)",
section_match.group(1),
re.DOTALL | re.MULTILINE,
):
params[item.group(1)] = item.group(2).strip()
# Strip :param/:type entries from body (handle multi-line descriptions)
- body = re.sub(r':(?:param|type)\s+\w+:\s*(?:(?!\n:(?:param|type)\s).)*', '', doc, flags=re.DOTALL)
+ body = re.sub(
+ r":(?:param|type)\s+\w+:\s*(?:(?!\n:(?:param|type)\s).)*", "", doc, flags=re.DOTALL
+ )
# Strip markdown Parameters/Options sections from body
- body = re.sub(r'\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+', '', body)
+ body = re.sub(r"\*\*(?:Parameters|Options):\*\*\n(?:[ \t]*-[^\n]*\n?)+", "", body)
body = body.strip()
return body, params
@@ -121,11 +123,19 @@ def combine_docstrings(cls):
model_params = set(cls.parameter_specs.keys())
except Exception:
model_params = set()
+
+ params = {}
+ options = {}
for name, desc in list(all_params.items()):
- if name in model_params and "[model param]" not in desc:
- all_params[name] = f"{desc} [model param]"
- main_body += "\n\n" + "\n".join(
- f":param {name}: {desc}" for name, desc in all_params.items()
+ if name in model_params:
+ params[name] = f"{desc} [model param]"
+ else:
+ options[name] = desc
+ main_body += (
+ "\n\n"
+ + "\n".join(f":param {name}: {desc}" for name, desc in params.items())
+ + "\n"
+ + "\n".join(f":param {name}: {desc}" for name, desc in options.items())
)
cls.__doc__ = main_body.strip()
diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml
index e35a6cd2..083c0150 100644
--- a/docs/source/_toc.yml
+++ b/docs/source/_toc.yml
@@ -10,10 +10,9 @@ chapters:
- file: fastfit
- file: tutorials/index
- file: coordinates
+ - file: astrophotdocs/index
- file: communitycontrib
- file: troubleshooting
- file: contributing
- file: citation
- file: license
- - file: astrophotdocs/index
- - file: modules
From 9c239761e52ad96026a5a7e66bf78f77339ea7d3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Mar 2026 01:48:46 +0000
Subject: [PATCH 10/16] Convert image fit plot docstrings to RST markers
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/c48da40e-0846-464e-a2ea-c0274b9ae0f1
---
astrophot/fit/base.py | 2 +-
astrophot/fit/gradient.py | 4 ++--
astrophot/fit/hmc.py | 6 +++---
astrophot/fit/iterative.py | 2 +-
astrophot/fit/lm.py | 8 ++++----
astrophot/fit/mala.py | 2 +-
astrophot/fit/mhmcmc.py | 2 +-
astrophot/fit/scipy_fit.py | 2 +-
astrophot/image/func/wcs.py | 16 ++++++++--------
astrophot/image/image_object.py | 2 +-
astrophot/image/mixins/data_mixin.py | 2 +-
astrophot/image/sip_image.py | 2 +-
astrophot/image/target_image.py | 4 ++--
astrophot/plots/diagnostic.py | 2 +-
astrophot/plots/image.py | 10 +++++-----
astrophot/plots/profile.py | 6 +++---
16 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/astrophot/fit/base.py b/astrophot/fit/base.py
index 393fa1a5..f4829d27 100644
--- a/astrophot/fit/base.py
+++ b/astrophot/fit/base.py
@@ -13,7 +13,7 @@ class BaseOptimizer:
"""
Base optimizer object that other optimizers inherit from. Ensures consistent signature for the classes.
- **Args:**
+ Args:
- `model`: an AstroPhot_Model object that will have its (unlocked) parameters optimized [AstroPhot_Model]
- `initial_state`: optional initialization for the parameters as a 1D tensor [tensor]
- `relative_tolerance`: tolerance for counting success steps as: $0 < (\\chi_2^2 - \\chi_1^2)/\\chi_1^2 < \\text{tol}$ [float]
diff --git a/astrophot/fit/gradient.py b/astrophot/fit/gradient.py
index 11ae29a3..45427435 100644
--- a/astrophot/fit/gradient.py
+++ b/astrophot/fit/gradient.py
@@ -25,7 +25,7 @@ class Grad(BaseOptimizer):
The optimizer is instantiated with a set of initial parameters and optimization options provided by the user.
The `fit` method performs the optimization, taking a series of gradient steps until a stopping criteria is met.
- **Args:**
+ Args:
- `likelihood` (str, optional): The likelihood function to use for the optimization. Defaults to "gaussian".
- `method` (str, optional): the optimization method to use for the update step. Defaults to "NAdam".
- `optim_kwargs` (dict, optional): a dictionary of keyword arguments to pass to the pytorch optimizer.
@@ -164,7 +164,7 @@ class Slalom(BaseOptimizer):
gradient descent algorithms, Slalom slows down considerably when trying to
achieve very high precision.
- **Args:**
+ Args:
- `S` (float, optional): The initial step size for the Slalom optimizer. Defaults to 1e-4.
- `likelihood` (str, optional): The likelihood function to use for the optimization. Defaults to "gaussian".
- `report_freq` (int, optional): Frequency of reporting the optimization progress. Defaults to 10 steps.
diff --git a/astrophot/fit/hmc.py b/astrophot/fit/hmc.py
index a072bc44..e1b3aa4c 100644
--- a/astrophot/fit/hmc.py
+++ b/astrophot/fit/hmc.py
@@ -31,7 +31,7 @@ def new_configure(self, mass_matrix_shape, adapt_mass_matrix=True, options={}):
"""
Sets up an initial mass matrix.
- **Args:**
+ Args:
- `mass_matrix_shape`: a dict that maps tuples of site names to the shape of
the corresponding mass matrix. Each tuple of site names corresponds to a block.
- `adapt_mass_matrix`: a flag to decide whether an adaptation scheme will be used.
@@ -70,7 +70,7 @@ class HMC(BaseOptimizer):
https://arxiv.org/abs/1701.02434, and
http://www.mcmchandbook.net/HandbookChapter5.pdf
- **Args:**
+ Args:
- `max_iter` (int, optional): The number of sampling steps to perform. Defaults to 1000.
- `epsilon` (float, optional): The length of the integration step to perform for each leapfrog iteration. The momentum update will be of order epsilon * score. Defaults to 1e-5.
- `leapfrog_steps` (int, optional): Number of steps to perform with leapfrog integrator per sample of the HMC. Defaults to 10.
@@ -122,7 +122,7 @@ def fit(
Records the chain for later examination.
- **Args:**
+ Args:
state (torch.Tensor, optional): Model parameters as a 1D tensor.
"""
diff --git a/astrophot/fit/iterative.py b/astrophot/fit/iterative.py
index a52384f3..cb05b5a3 100644
--- a/astrophot/fit/iterative.py
+++ b/astrophot/fit/iterative.py
@@ -36,7 +36,7 @@ class Iter(BaseOptimizer):
is not worthwhile for a single model to spend lots of time optimizing when
its neighbors havent converged.
- **Args:**
+ Args:
- `max_iter`: Maximum number of iterations, defaults to 100.
- `lm_kwargs`: Keyword arguments to pass to `LM` optimizer.
"""
diff --git a/astrophot/fit/lm.py b/astrophot/fit/lm.py
index 7eeeb158..f5146e58 100644
--- a/astrophot/fit/lm.py
+++ b/astrophot/fit/lm.py
@@ -82,7 +82,7 @@ class LM(BaseOptimizer):
by Henri Gavin on which much of the AstroPhot LM implementation is
based::
- ```{latex}
+ .. code-block:: bibtex
@article{Gavin2019,
title={The Levenberg-Marquardt algorithm for nonlinear least squares curve-fitting problems},
author={Gavin, Henri P},
@@ -90,12 +90,12 @@ class LM(BaseOptimizer):
volume={19},
year={2019}
}
- ```
+
as well as the paper on LM geodesic acceleration by Mark
Transtrum::
- ```{latex}
+ .. code-block:: bibtex
@article{Tanstrum2012,
author = {{Transtrum}, Mark K. and {Sethna}, James P.},
title = "{Improvements to the Levenberg-Marquardt algorithm for nonlinear least-squares minimization}",
@@ -103,7 +103,7 @@ class LM(BaseOptimizer):
doi = {10.48550/arXiv.1201.5885},
adsurl = {https://ui.adsabs.harvard.edu/abs/2012arXiv1201.5885T},
}
- ```
+
The damping factor $\\lambda$ is adjusted at each iteration:
it is effectively increased when we are far from the solution, and
diff --git a/astrophot/fit/mala.py b/astrophot/fit/mala.py
index fe2b7cce..2ae01bf8 100644
--- a/astrophot/fit/mala.py
+++ b/astrophot/fit/mala.py
@@ -23,7 +23,7 @@ class MALA(BaseOptimizer):
Which can be found fairly easily with the LM optimizer (see the fitting
methods tutorial).
- **Args:**
+ Args:
- `chains`: The number of MCMC chains to run in parallel. Default is 4.
- `epsilon`: The step size for the MALA sampler. Default is 1e-2.
- `mass_matrix`: The mass matrix for the MALA sampler. If None, the identity matrix is used.
diff --git a/astrophot/fit/mhmcmc.py b/astrophot/fit/mhmcmc.py
index 0ef9506b..a6d350b4 100644
--- a/astrophot/fit/mhmcmc.py
+++ b/astrophot/fit/mhmcmc.py
@@ -26,7 +26,7 @@ class MHMCMC(BaseOptimizer):
number of parameters by default, but can be made higher (not lower) if desired.
This is done by passing a 2D array of shape (nwalkers, ndim) to the `fit` method.
- **Args:**
+ Args:
- `likelihood`: The likelihood function to use for the MCMC sampling. Can be "gaussian" or "poisson". Default is "gaussian".
"""
diff --git a/astrophot/fit/scipy_fit.py b/astrophot/fit/scipy_fit.py
index 41031631..47870a1c 100644
--- a/astrophot/fit/scipy_fit.py
+++ b/astrophot/fit/scipy_fit.py
@@ -19,7 +19,7 @@ class ScipyFit(BaseOptimizer):
tasks. It supports a variety of methods, however only a subset allow users to
define boundaries for the parameters. This wrapper is only for those methods.
- **Args:**
+ Args:
- `model`: The model to fit, which should be an instance of `Model`.
- `initial_state`: Initial guess for the model parameters as a 1D tensor.
- `method`: The optimization method to use. Default is "Nelder-Mead", but can be set to any of: "Nelder-Mead", "L-BFGS-B", "TNC", "SLSQP", "Powell", or "trust-constr".
diff --git a/astrophot/image/func/wcs.py b/astrophot/image/func/wcs.py
index 8d811256..9d34cbba 100644
--- a/astrophot/image/func/wcs.py
+++ b/astrophot/image/func/wcs.py
@@ -12,13 +12,13 @@ def world_to_plane_gnomonic(ra, dec, ra0, dec0, x0=0.0, y0=0.0):
"""
Convert world coordinates (RA, Dec) to plane coordinates (x, y) using the gnomonic projection.
- **Args:**
+ Args:
- `ra`: (torch.Tensor) Right Ascension in degrees.
- `dec`: (torch.Tensor) Declination in degrees.
- `ra0`: (torch.Tensor) Reference Right Ascension in degrees.
- `dec0`: (torch.Tensor) Reference Declination in degrees.
- **Returns:**
+ Returns:
- `x`: (torch.Tensor) x coordinate in arcseconds.
- `y`: (torch.Tensor) y coordinate in arcseconds.
"""
@@ -44,14 +44,14 @@ def plane_to_world_gnomonic(x, y, ra0, dec0, x0=0.0, y0=0.0, s=1e-10):
"""
Convert plane coordinates (x, y) to world coordinates (RA, Dec) using the gnomonic projection.
- **Args:**
+ Args:
- `x`: (Tensor) x coordinate in arcseconds.
- `y`: (Tensor) y coordinate in arcseconds.
- `ra0`: (Tensor) Reference Right Ascension in degrees.
- `dec0`: (Tensor) Reference Declination in degrees.
- `s`: (float) Small constant to avoid division by zero.
- **Returns:**
+ Returns:
- `ra`: (Tensor) Right Ascension in degrees.
- `dec`: (Tensor) Declination in degrees.
"""
@@ -80,7 +80,7 @@ def pixel_to_plane_linear(i, j, i0, j0, CD, x0=0.0, y0=0.0):
Convert pixel coordinates to a tangent plane using the WCS information. This
matches the FITS convention for linear transformations.
- **Args:**
+ Args:
- `i` (Tensor): The first coordinate of the pixel in pixel units.
- `j` (Tensor): The second coordinate of the pixel in pixel units.
- `i0` (Tensor): The i reference pixel coordinate in pixel units.
@@ -90,7 +90,7 @@ def pixel_to_plane_linear(i, j, i0, j0, CD, x0=0.0, y0=0.0):
- `x0` (float): The x reference coordinate in arcseconds.
- `y0` (float): The y reference coordinate in arcseconds.
- **Returns:**
+ Returns:
- Tuple[Tensor, Tensor]: Tuple containing the x and y coordinates in arcseconds
"""
uv = backend.stack((i.flatten() - i0, j.flatten() - j0), dim=0)
@@ -160,7 +160,7 @@ def plane_to_pixel_linear(x, y, i0, j0, CD, x0=0.0, y0=0.0):
Convert tangent plane coordinates to pixel coordinates using the WCS
information. This matches the FITS convention for linear transformations.
- **Args:**
+ Args:
- `x`: (Tensor) The first coordinate of the pixel in arcsec.
- `y`: (Tensor) The second coordinate of the pixel in arcsec.
- `i0`: (Tensor) The i reference pixel coordinate in pixel units.
@@ -169,7 +169,7 @@ def plane_to_pixel_linear(x, y, i0, j0, CD, x0=0.0, y0=0.0):
- `x0`: (float) The x reference coordinate in arcsec.
- `y0`: (float) The y reference coordinate in arcsec.
- **Returns:**
+ Returns:
- Tuple[Tensor, Tensor]: Tuple containing the i and j pixel coordinates in pixel units.
"""
xy = backend.stack((x.flatten() - x0, y.flatten() - y0), dim=0)
diff --git a/astrophot/image/image_object.py b/astrophot/image/image_object.py
index 8e25e349..171e07a5 100644
--- a/astrophot/image/image_object.py
+++ b/astrophot/image/image_object.py
@@ -400,7 +400,7 @@ def reduce(self, scale: int, **kwargs):
pixels are condensed, but the pixel size is increased
correspondingly.
- **Args:**
+ Args:
- `scale` (int): The scale factor by which to reduce the image.
"""
if not isinstance(scale, int) and not (
diff --git a/astrophot/image/mixins/data_mixin.py b/astrophot/image/mixins/data_mixin.py
index feece985..ea2cfefb 100644
--- a/astrophot/image/mixins/data_mixin.py
+++ b/astrophot/image/mixins/data_mixin.py
@@ -17,7 +17,7 @@ class DataMixin:
This mixin provides functionality for handling variance and mask,
as well as other ancillary data.
- **Args:**
+ Args:
- `mask`: A boolean mask indicating which pixels to ignore.
- `std`: Standard deviation of the image pixels.
- `variance`: Variance of the image pixels.
diff --git a/astrophot/image/sip_image.py b/astrophot/image/sip_image.py
index 32de11b8..74c3c6b3 100644
--- a/astrophot/image/sip_image.py
+++ b/astrophot/image/sip_image.py
@@ -51,7 +51,7 @@ def reduce(self, scale: int, **kwargs):
pixels are condensed, but the pixel size is increased
correspondingly.
- **Args:**
+ Args:
- `scale`: factor by which to condense the image pixels. Each scale X scale region will be summed [int]
"""
diff --git a/astrophot/image/target_image.py b/astrophot/image/target_image.py
index e3f7db6b..a24b4845 100644
--- a/astrophot/image/target_image.py
+++ b/astrophot/image/target_image.py
@@ -33,7 +33,7 @@ class TargetImage(DataMixin, Image):
Basic usage:
- ```{python}
+ .. code-block:: python
import astrophot as ap
# Create target image
@@ -58,7 +58,7 @@ class TargetImage(DataMixin, Image):
# Make low resolution version
lowrez = image.reduce(2)
- ```
+
Some important information to keep in mind. First, providing an
`astropy WCS` object is the best way to keep track of coordinates
diff --git a/astrophot/plots/diagnostic.py b/astrophot/plots/diagnostic.py
index 1e0df730..605ce64f 100644
--- a/astrophot/plots/diagnostic.py
+++ b/astrophot/plots/diagnostic.py
@@ -21,7 +21,7 @@ def covariance_matrix(
"""
Create a covariance matrix plot. Creates a corner plot with ellipses representing the covariance between parameters.
- **Args:**
+ Args:
- `covariance_matrix` (np.ndarray): Covariance matrix of shape (n_params, n_params).
- `mean` (np.ndarray): Mean values of the parameters, shape (n_params,).
- `labels` (list, optional): Labels for the parameters.
diff --git a/astrophot/plots/image.py b/astrophot/plots/image.py
index 51c6aece..afe7b800 100644
--- a/astrophot/plots/image.py
+++ b/astrophot/plots/image.py
@@ -26,7 +26,7 @@ def target_image(fig, ax, target, window=None, **kwargs):
visibility of the image data for the faint areas of the image, while it uses
log scale normalization for the bright areas.
- **Args:**
+ Args:
- `fig` (matplotlib.figure.Figure): The figure object in which the target image will be displayed.
- `ax` (matplotlib.axes.Axes): The axes object on which the target image will be plotted.
- `target` (Image or Image_List): The image or list of images to be displayed.
@@ -113,7 +113,7 @@ def psf_image(
):
"""For plotting PSF images, or the output of a PSF model.
- **Args:**
+ Args:
- `fig` (matplotlib.figure.Figure): The figure object in which the PSF image will be displayed.
- `ax` (matplotlib.axes.Axes): The axes object on which the PSF image will be plotted.
- `psf` (PSFImage or PSFModel or PSFGroupModel): The PSF model or group model to be displayed.
@@ -181,7 +181,7 @@ def model_image(
"""
This function is used to generate a model image and display it using the provided figure and axes.
- **Args:**
+ Args:
- `fig` (matplotlib.figure.Figure): The figure object in which the image will be displayed.
- `ax` (matplotlib.axes.Axes): The axes object on which the image will be plotted.
- `model` (Model): The model object used to generate a model image if `sample_image` is not provided.
@@ -311,7 +311,7 @@ def residual_image(
This function is used to calculate and display the residuals of a model image with respect to a target image.
The residuals are calculated as the difference between the target image and the sample image and may be normalized by the standard deviation.
- **Args:**
+ Args:
- `fig` (matplotlib.figure.Figure): The figure object in which the residuals will be displayed.
- `ax` (matplotlib.axes.Axes): The axes object on which the residuals will be plotted.
- `model` (Model): The model object used to generate a model image if `sample_image` is not provided.
@@ -423,7 +423,7 @@ def model_window(fig, ax, model, target=None, rectangle_linewidth=2, **kwargs):
"""Used for plotting the window(s) of a model on a target image. These
windows bound the region that a model will be evaluated/fit to.
- **Args:**
+ Args:
- `fig` (matplotlib.figure.Figure): The figure object in which the model window will be displayed.
- `ax` (matplotlib.axes.Axes): The axes object on which the model window will be plotted.
- `model` (Model): The model object whose window will be displayed.
diff --git a/astrophot/plots/profile.py b/astrophot/plots/profile.py
index adcdd83b..09c0aa31 100644
--- a/astrophot/plots/profile.py
+++ b/astrophot/plots/profile.py
@@ -34,7 +34,7 @@ def radial_light_profile(
"""
Used to plot the brightness profile as a function of radius for models which define a `radial_model`.
- **Args:**
+ Args:
- `fig`: matplotlib figure object
- `ax`: matplotlib axis object
- `model` (Model): Model object from which to plot the radial profile.
@@ -98,7 +98,7 @@ def radial_median_profile(
representation of the image data if one were to simply average the
pixels along isophotes.
- **Args:**
+ Args:
- `fig`: matplotlib figure object
- `ax`: matplotlib axis object
- `model` (AstroPhot_Model): Model object from which to determine the radial binning. Also provides the target image to extract the data
@@ -195,7 +195,7 @@ def ray_light_profile(
"""
Used for plotting ray (wedge) type models which define a `iradial_model` method. These have multiple radial profiles.
- **Args:**
+ Args:
- `fig`: matplotlib figure object
- `ax`: matplotlib axis object
- `model` (Model): Model object from which to plot the radial profile.
From e4e59fd7062cf9b284e32750a94bd715dd1f15a3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Mar 2026 01:50:39 +0000
Subject: [PATCH 11/16] Use plain text code-block for LM citations
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/c48da40e-0846-464e-a2ea-c0274b9ae0f1
---
astrophot/fit/lm.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/astrophot/fit/lm.py b/astrophot/fit/lm.py
index f5146e58..adca7c97 100644
--- a/astrophot/fit/lm.py
+++ b/astrophot/fit/lm.py
@@ -82,7 +82,7 @@ class LM(BaseOptimizer):
by Henri Gavin on which much of the AstroPhot LM implementation is
based::
- .. code-block:: bibtex
+ .. code-block:: text
@article{Gavin2019,
title={The Levenberg-Marquardt algorithm for nonlinear least squares curve-fitting problems},
author={Gavin, Henri P},
@@ -95,7 +95,7 @@ class LM(BaseOptimizer):
as well as the paper on LM geodesic acceleration by Mark
Transtrum::
- .. code-block:: bibtex
+ .. code-block:: text
@article{Tanstrum2012,
author = {{Transtrum}, Mark K. and {Sethna}, James P.},
title = "{Improvements to the Levenberg-Marquardt algorithm for nonlinear least-squares minimization}",
From f105e6629045b448d4f02b7d14402de2cb9496c6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Mar 2026 12:47:26 +0000
Subject: [PATCH 12/16] Use RST param and returns fields in image fit plots
docs
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/06d20147-ecab-453e-9cbe-afad8be6827b
---
astrophot/fit/base.py | 15 ++--
astrophot/fit/gradient.py | 35 +++++---
astrophot/fit/hmc.py | 39 +++++----
astrophot/fit/iterative.py | 22 ++---
astrophot/fit/mala.py | 11 ++-
astrophot/fit/mhmcmc.py | 3 +-
astrophot/fit/scipy_fit.py | 9 +-
astrophot/image/func/wcs.py | 101 +++++++++++++---------
astrophot/image/image_object.py | 12 +--
astrophot/image/jacobian_image.py | 2 +-
astrophot/image/mixins/data_mixin.py | 17 ++--
astrophot/image/psf_image.py | 4 +-
astrophot/image/sip_image.py | 5 +-
astrophot/plots/diagnostic.py | 22 +++--
astrophot/plots/image.py | 124 +++++++++++++++++----------
astrophot/plots/profile.py | 60 +++++++------
16 files changed, 281 insertions(+), 200 deletions(-)
diff --git a/astrophot/fit/base.py b/astrophot/fit/base.py
index f4829d27..2d447a25 100644
--- a/astrophot/fit/base.py
+++ b/astrophot/fit/base.py
@@ -13,14 +13,13 @@ class BaseOptimizer:
"""
Base optimizer object that other optimizers inherit from. Ensures consistent signature for the classes.
- Args:
- - `model`: an AstroPhot_Model object that will have its (unlocked) parameters optimized [AstroPhot_Model]
- - `initial_state`: optional initialization for the parameters as a 1D tensor [tensor]
- - `relative_tolerance`: tolerance for counting success steps as: $0 < (\\chi_2^2 - \\chi_1^2)/\\chi_1^2 < \\text{tol}$ [float]
- - `verbose`: verbosity level for the optimizer [int]
- - `max_iter`: maximum allowed number of iterations [int]
- - `save_steps`: optional string for path to save the model at each step (fitter dependent), e.g. "model_step_{step}.hdf5" [str]
- - `fit_valid`: whether to fit while forcing parameters into valid range, or allow any value for each parameter. Default True [bool]
+ :param model: an AstroPhot_Model object that will have its (unlocked) parameters optimized [AstroPhot_Model]
+ :param initial_state: optional initialization for the parameters as a 1D Array [Array]
+ :param relative_tolerance: tolerance for counting success steps as: $0 < (\\chi_2^2 - \\chi_1^2)/\\chi_1^2 < \\text{tol}$ [float]
+ :param verbose: verbosity level for the optimizer [int]
+ :param max_iter: maximum allowed number of iterations [int]
+ :param save_steps: optional string for path to save the model at each step (fitter dependent), e.g. "model_step_{step}.hdf5" [str]
+ :param fit_valid: whether to fit while forcing parameters into valid range, or allow any value for each parameter. Default True [bool]
"""
diff --git a/astrophot/fit/gradient.py b/astrophot/fit/gradient.py
index 45427435..5cf8ef4c 100644
--- a/astrophot/fit/gradient.py
+++ b/astrophot/fit/gradient.py
@@ -25,12 +25,16 @@ class Grad(BaseOptimizer):
The optimizer is instantiated with a set of initial parameters and optimization options provided by the user.
The `fit` method performs the optimization, taking a series of gradient steps until a stopping criteria is met.
- Args:
- - `likelihood` (str, optional): The likelihood function to use for the optimization. Defaults to "gaussian".
- - `method` (str, optional): the optimization method to use for the update step. Defaults to "NAdam".
- - `optim_kwargs` (dict, optional): a dictionary of keyword arguments to pass to the pytorch optimizer.
- - `patience` (int, optional): number of steps with no improvement before stopping the optimization. Defaults to 10.
- - `report_freq` (int, optional): frequency of reporting the optimization progress. Defaults to 10 steps.
+ :param likelihood: The likelihood function to use for the optimization. Defaults to "gaussian".
+ :type likelihood: str, optional
+ :param method: the optimization method to use for the update step. Defaults to "NAdam".
+ :type method: str, optional
+ :param optim_kwargs: a dictionary of keyword arguments to pass to the pytorch optimizer.
+ :type optim_kwargs: dict, optional
+ :param patience: number of steps with no improvement before stopping the optimization. Defaults to 10.
+ :type patience: int, optional
+ :param report_freq: frequency of reporting the optimization progress. Defaults to 10 steps.
+ :type report_freq: int, optional
"""
def __init__(
@@ -164,13 +168,18 @@ class Slalom(BaseOptimizer):
gradient descent algorithms, Slalom slows down considerably when trying to
achieve very high precision.
- Args:
- - `S` (float, optional): The initial step size for the Slalom optimizer. Defaults to 1e-4.
- - `likelihood` (str, optional): The likelihood function to use for the optimization. Defaults to "gaussian".
- - `report_freq` (int, optional): Frequency of reporting the optimization progress. Defaults to 10 steps.
- - `relative_tolerance` (float, optional): The relative tolerance for convergence. Defaults to 1e-4.
- - `momentum` (float, optional): The momentum factor for the Slalom optimizer. Defaults to 0.5.
- - `max_iter` (int, optional): The maximum number of iterations for the optimizer. Defaults to 1000.
+ :param S: The initial step size for the Slalom optimizer. Defaults to 1e-4.
+ :type S: float, optional
+ :param likelihood: The likelihood function to use for the optimization. Defaults to "gaussian".
+ :type likelihood: str, optional
+ :param report_freq: Frequency of reporting the optimization progress. Defaults to 10 steps.
+ :type report_freq: int, optional
+ :param relative_tolerance: The relative tolerance for convergence. Defaults to 1e-4.
+ :type relative_tolerance: float, optional
+ :param momentum: The momentum factor for the Slalom optimizer. Defaults to 0.5.
+ :type momentum: float, optional
+ :param max_iter: The maximum number of iterations for the optimizer. Defaults to 1000.
+ :type max_iter: int, optional
"""
def __init__(
diff --git a/astrophot/fit/hmc.py b/astrophot/fit/hmc.py
index e1b3aa4c..bdaf0c33 100644
--- a/astrophot/fit/hmc.py
+++ b/astrophot/fit/hmc.py
@@ -31,11 +31,10 @@ def new_configure(self, mass_matrix_shape, adapt_mass_matrix=True, options={}):
"""
Sets up an initial mass matrix.
- Args:
- - `mass_matrix_shape`: a dict that maps tuples of site names to the shape of
+ :param mass_matrix_shape: a dict that maps tuples of site names to the shape of
the corresponding mass matrix. Each tuple of site names corresponds to a block.
- - `adapt_mass_matrix`: a flag to decide whether an adaptation scheme will be used.
- - `options`: tensor options to construct the initial mass matrix.
+ :param adapt_mass_matrix: a flag to decide whether an adaptation scheme will be used.
+ :param options: Array options to construct the initial mass matrix.
"""
inverse_mass_matrix = {}
for site_names, shape in mass_matrix_shape.items():
@@ -70,16 +69,24 @@ class HMC(BaseOptimizer):
https://arxiv.org/abs/1701.02434, and
http://www.mcmchandbook.net/HandbookChapter5.pdf
- Args:
- - `max_iter` (int, optional): The number of sampling steps to perform. Defaults to 1000.
- - `epsilon` (float, optional): The length of the integration step to perform for each leapfrog iteration. The momentum update will be of order epsilon * score. Defaults to 1e-5.
- - `leapfrog_steps` (int, optional): Number of steps to perform with leapfrog integrator per sample of the HMC. Defaults to 10.
- - `inv_mass` (float or array, optional): Inverse Mass matrix (covariance matrix) which can tune the behavior in each dimension to ensure better mixing when sampling. Defaults to the identity.
- - `progress_bar` (bool, optional): Whether to display a progress bar during sampling. Defaults to True.
- - `prior` (distribution, optional): Prior distribution for the parameters. Defaults to None.
- - `warmup` (int, optional): Number of warmup steps before actual sampling begins. Defaults to 100.
- - `hmc_kwargs` (dict, optional): Additional keyword arguments for the HMC sampler. Defaults to {}.
- - `mcmc_kwargs` (dict, optional): Additional keyword arguments for the MCMC process. Defaults to {}.
+ :param max_iter: The number of sampling steps to perform. Defaults to 1000.
+ :type max_iter: int, optional
+ :param epsilon: The length of the integration step to perform for each leapfrog iteration. The momentum update will be of order epsilon * score. Defaults to 1e-5.
+ :type epsilon: float, optional
+ :param leapfrog_steps: Number of steps to perform with leapfrog integrator per sample of the HMC. Defaults to 10.
+ :type leapfrog_steps: int, optional
+ :param inv_mass: Inverse Mass matrix (covariance matrix) which can tune the behavior in each dimension to ensure better mixing when sampling. Defaults to the identity.
+ :type inv_mass: float or array, optional
+ :param progress_bar: Whether to display a progress bar during sampling. Defaults to True.
+ :type progress_bar: bool, optional
+ :param prior: Prior distribution for the parameters. Defaults to None.
+ :type prior: distribution, optional
+ :param warmup: Number of warmup steps before actual sampling begins. Defaults to 100.
+ :type warmup: int, optional
+ :param hmc_kwargs: Additional keyword arguments for the HMC sampler. Defaults to {}.
+ :type hmc_kwargs: dict, optional
+ :param mcmc_kwargs: Additional keyword arguments for the MCMC process. Defaults to {}.
+ :type mcmc_kwargs: dict, optional
"""
@@ -122,8 +129,8 @@ def fit(
Records the chain for later examination.
- Args:
- state (torch.Tensor, optional): Model parameters as a 1D tensor.
+ :param state: Model parameters as a 1D Array.
+ :type state: Array, optional
"""
diff --git a/astrophot/fit/iterative.py b/astrophot/fit/iterative.py
index cb05b5a3..a3969358 100644
--- a/astrophot/fit/iterative.py
+++ b/astrophot/fit/iterative.py
@@ -36,9 +36,8 @@ class Iter(BaseOptimizer):
is not worthwhile for a single model to spend lots of time optimizing when
its neighbors havent converged.
- Args:
- - `max_iter`: Maximum number of iterations, defaults to 100.
- - `lm_kwargs`: Keyword arguments to pass to `LM` optimizer.
+ :param max_iter: Maximum number of iterations, defaults to 100.
+ :param lm_kwargs: Keyword arguments to pass to `LM` optimizer.
"""
def __init__(
@@ -165,14 +164,15 @@ class IterParam(BaseOptimizer):
likely better to optimize the full problem with LM as, when it works, LM is
faster than the IterParam method.
- Args:
- chunks (Union[int, tuple]): Specify how to break down the model
- parameters. If an integer, at each iteration the algorithm will break the
- parameters into groups of that size. If a tuple, should be a tuple of
- arrays of length num_dimensions which act as selectors for the parameters
- to fit (1 to include, 0 to exclude). Default: 50
- chunk_order (str): How to iterate through the chunks. Should be one of: random,
- sequential. Default: sequential
+ :param chunks: Specify how to break down the model parameters. If an integer,
+ at each iteration the algorithm will break the parameters into groups of
+ that size. If a tuple, it should be a tuple of arrays of length
+ num_dimensions which act as selectors for the parameters to fit (1 to
+ include, 0 to exclude). Default: 50.
+ :type chunks: Union[int, tuple]
+ :param chunk_order: How to iterate through the chunks. Should be one of:
+ ``"random"``, ``"sequential"``. Default: ``"sequential"``.
+ :type chunk_order: str
"""
def __init__(
diff --git a/astrophot/fit/mala.py b/astrophot/fit/mala.py
index 2ae01bf8..077480ab 100644
--- a/astrophot/fit/mala.py
+++ b/astrophot/fit/mala.py
@@ -23,12 +23,11 @@ class MALA(BaseOptimizer):
Which can be found fairly easily with the LM optimizer (see the fitting
methods tutorial).
- Args:
- - `chains`: The number of MCMC chains to run in parallel. Default is 4.
- - `epsilon`: The step size for the MALA sampler. Default is 1e-2.
- - `mass_matrix`: The mass matrix for the MALA sampler. If None, the identity matrix is used.
- - `progress_bar`: Whether to show a progress bar during sampling. Default is True.
- - `likelihood`: The likelihood function to use for the MCMC sampling. Can be "gaussian" or "poisson". Default is "gaussian".
+ :param chains: The number of MCMC chains to run in parallel. Default is 4.
+ :param epsilon: The step size for the MALA sampler. Default is 1e-2.
+ :param mass_matrix: The mass matrix for the MALA sampler. If None, the identity matrix is used.
+ :param progress_bar: Whether to show a progress bar during sampling. Default is True.
+ :param likelihood: The likelihood function to use for the MCMC sampling. Can be "gaussian" or "poisson". Default is "gaussian".
"""
def __init__(
diff --git a/astrophot/fit/mhmcmc.py b/astrophot/fit/mhmcmc.py
index a6d350b4..a9cd87b9 100644
--- a/astrophot/fit/mhmcmc.py
+++ b/astrophot/fit/mhmcmc.py
@@ -26,8 +26,7 @@ class MHMCMC(BaseOptimizer):
number of parameters by default, but can be made higher (not lower) if desired.
This is done by passing a 2D array of shape (nwalkers, ndim) to the `fit` method.
- Args:
- - `likelihood`: The likelihood function to use for the MCMC sampling. Can be "gaussian" or "poisson". Default is "gaussian".
+ :param likelihood: The likelihood function to use for the MCMC sampling. Can be "gaussian" or "poisson". Default is "gaussian".
"""
def __init__(
diff --git a/astrophot/fit/scipy_fit.py b/astrophot/fit/scipy_fit.py
index 47870a1c..5a96a8de 100644
--- a/astrophot/fit/scipy_fit.py
+++ b/astrophot/fit/scipy_fit.py
@@ -19,11 +19,10 @@ class ScipyFit(BaseOptimizer):
tasks. It supports a variety of methods, however only a subset allow users to
define boundaries for the parameters. This wrapper is only for those methods.
- Args:
- - `model`: The model to fit, which should be an instance of `Model`.
- - `initial_state`: Initial guess for the model parameters as a 1D tensor.
- - `method`: The optimization method to use. Default is "Nelder-Mead", but can be set to any of: "Nelder-Mead", "L-BFGS-B", "TNC", "SLSQP", "Powell", or "trust-constr".
- - `ndf`: Optional number of degrees of freedom for the fit. If not provided, it is calculated as the number of data points minus the number of parameters.
+ :param model: The model to fit, which should be an instance of `Model`.
+ :param initial_state: Initial guess for the model parameters as a 1D Array.
+ :param method: The optimization method to use. Default is "Nelder-Mead", but can be set to any of: "Nelder-Mead", "L-BFGS-B", "TNC", "SLSQP", "Powell", or "trust-constr".
+ :param ndf: Optional number of degrees of freedom for the fit. If not provided, it is calculated as the number of data points minus the number of parameters.
"""
def __init__(
diff --git a/astrophot/image/func/wcs.py b/astrophot/image/func/wcs.py
index 9d34cbba..b10a2916 100644
--- a/astrophot/image/func/wcs.py
+++ b/astrophot/image/func/wcs.py
@@ -12,15 +12,19 @@ def world_to_plane_gnomonic(ra, dec, ra0, dec0, x0=0.0, y0=0.0):
"""
Convert world coordinates (RA, Dec) to plane coordinates (x, y) using the gnomonic projection.
- Args:
- - `ra`: (torch.Tensor) Right Ascension in degrees.
- - `dec`: (torch.Tensor) Declination in degrees.
- - `ra0`: (torch.Tensor) Reference Right Ascension in degrees.
- - `dec0`: (torch.Tensor) Reference Declination in degrees.
-
- Returns:
- - `x`: (torch.Tensor) x coordinate in arcseconds.
- - `y`: (torch.Tensor) y coordinate in arcseconds.
+ :param ra: Right Ascension in degrees.
+ :type ra: Array
+ :param dec: Declination in degrees.
+ :type dec: Array
+ :param ra0: Reference Right Ascension in degrees.
+ :type ra0: Array
+ :param dec0: Reference Declination in degrees.
+ :type dec0: Array
+
+ :returns: ``x`` -- x coordinate in arcseconds.
+ :rtype: Array
+ :returns: ``y`` -- y coordinate in arcseconds.
+ :rtype: Array
"""
ra = ra * deg_to_rad
dec = dec * deg_to_rad
@@ -44,16 +48,21 @@ def plane_to_world_gnomonic(x, y, ra0, dec0, x0=0.0, y0=0.0, s=1e-10):
"""
Convert plane coordinates (x, y) to world coordinates (RA, Dec) using the gnomonic projection.
- Args:
- - `x`: (Tensor) x coordinate in arcseconds.
- - `y`: (Tensor) y coordinate in arcseconds.
- - `ra0`: (Tensor) Reference Right Ascension in degrees.
- - `dec0`: (Tensor) Reference Declination in degrees.
- - `s`: (float) Small constant to avoid division by zero.
-
- Returns:
- - `ra`: (Tensor) Right Ascension in degrees.
- - `dec`: (Tensor) Declination in degrees.
+ :param x: x coordinate in arcseconds.
+ :type x: Array
+ :param y: y coordinate in arcseconds.
+ :type y: Array
+ :param ra0: Reference Right Ascension in degrees.
+ :type ra0: Array
+ :param dec0: Reference Declination in degrees.
+ :type dec0: Array
+ :param s: Small constant to avoid division by zero.
+ :type s: float
+
+ :returns: ``ra`` -- Right Ascension in degrees.
+ :rtype: Array
+ :returns: ``dec`` -- Declination in degrees.
+ :rtype: Array
"""
x = (x - x0) * arcsec_to_rad
y = (y - y0) * arcsec_to_rad
@@ -80,18 +89,24 @@ def pixel_to_plane_linear(i, j, i0, j0, CD, x0=0.0, y0=0.0):
Convert pixel coordinates to a tangent plane using the WCS information. This
matches the FITS convention for linear transformations.
- Args:
- - `i` (Tensor): The first coordinate of the pixel in pixel units.
- - `j` (Tensor): The second coordinate of the pixel in pixel units.
- - `i0` (Tensor): The i reference pixel coordinate in pixel units.
- - `j0` (Tensor): The j reference pixel coordinate in pixel units.
- - `CD` (Tensor): The CD matrix in arcsec per pixel. This 2x2 matrix is used to convert
+ :param i: The first coordinate of the pixel in pixel units.
+ :type i: Array
+ :param j: The second coordinate of the pixel in pixel units.
+ :type j: Array
+ :param i0: The i reference pixel coordinate in pixel units.
+ :type i0: Array
+ :param j0: The j reference pixel coordinate in pixel units.
+ :type j0: Array
+ :param CD: The CD matrix in arcsec per pixel. This 2x2 matrix is used to convert
+ :type CD: Array
from pixel to arcsec units and also handles rotation/skew.
- - `x0` (float): The x reference coordinate in arcseconds.
- - `y0` (float): The y reference coordinate in arcseconds.
+ :param x0: The x reference coordinate in arcseconds.
+ :type x0: float
+ :param y0: The y reference coordinate in arcseconds.
+ :type y0: float
- Returns:
- - Tuple[Tensor, Tensor]: Tuple containing the x and y coordinates in arcseconds
+ :returns: Tuple containing the x and y coordinates in arcseconds
+ :rtype: tuple[Array, Array]
"""
uv = backend.stack((i.flatten() - i0, j.flatten() - j0), dim=0)
xy = CD @ uv
@@ -160,17 +175,23 @@ def plane_to_pixel_linear(x, y, i0, j0, CD, x0=0.0, y0=0.0):
Convert tangent plane coordinates to pixel coordinates using the WCS
information. This matches the FITS convention for linear transformations.
- Args:
- - `x`: (Tensor) The first coordinate of the pixel in arcsec.
- - `y`: (Tensor) The second coordinate of the pixel in arcsec.
- - `i0`: (Tensor) The i reference pixel coordinate in pixel units.
- - `j0`: (Tensor) The j reference pixel coordinate in pixel units.
- - `CD`: (Tensor) The CD matrix in arcsec per pixel.
- - `x0`: (float) The x reference coordinate in arcsec.
- - `y0`: (float) The y reference coordinate in arcsec.
-
- Returns:
- - Tuple[Tensor, Tensor]: Tuple containing the i and j pixel coordinates in pixel units.
+ :param x: The first coordinate of the pixel in arcsec.
+ :type x: Array
+ :param y: The second coordinate of the pixel in arcsec.
+ :type y: Array
+ :param i0: The i reference pixel coordinate in pixel units.
+ :type i0: Array
+ :param j0: The j reference pixel coordinate in pixel units.
+ :type j0: Array
+ :param CD: The CD matrix in arcsec per pixel.
+ :type CD: Array
+ :param x0: The x reference coordinate in arcsec.
+ :type x0: float
+ :param y0: The y reference coordinate in arcsec.
+ :type y0: float
+
+ :returns: Tuple containing the i and j pixel coordinates in pixel units.
+ :rtype: tuple[Array, Array]
"""
xy = backend.stack((x.flatten() - x0, y.flatten() - y0), dim=0)
uv = backend.linalg.inv(CD) @ xy
diff --git a/astrophot/image/image_object.py b/astrophot/image/image_object.py
index 171e07a5..794a400d 100644
--- a/astrophot/image/image_object.py
+++ b/astrophot/image/image_object.py
@@ -24,7 +24,7 @@ class Image(Module):
image boundaries. It also provides methods for determining the coordinate
locations of pixels
- :param data: The image data as a tensor of pixel values. If not provided, a tensor of zeros will be created.
+ :param data: The image data as a Array of pixel values. If not provided, a Array of zeros will be created.
:param zeropoint: The zeropoint of the image, which is used to convert from pixel flux to magnitude.
:param crpix: The reference pixel coordinates in the image, which is used to convert from pixel coordinates to tangent plane coordinates.
:param pixelscale: The side length of a pixel, used to create a simple diagonal CD matrix.
@@ -124,12 +124,12 @@ def identity(self):
@property
def data(self):
- """The image data, which is a tensor of pixel values."""
+ """The image data, which is a Array of pixel values."""
return backend.transpose(self._data, 1, 0)
@data.setter
def data(self, value: Optional[ArrayLike]):
- """Set the image data. If value is None, the data is initialized to an empty tensor."""
+ """Set the image data. If value is None, the data is initialized to an empty Array."""
if value is None:
self._data = backend.empty((0, 0), dtype=config.DTYPE, device=config.DEVICE)
else:
@@ -395,13 +395,13 @@ def reduce(self, scale: int, **kwargs):
"""This operation will downsample an image by the factor given. If
scale = 2 then 2x2 blocks of pixels will be summed together to
form individual larger pixels. A new image object will be
- returned with the appropriate pixelscale and data tensor. Note
+ returned with the appropriate pixelscale and data Array. Note
that the window does not change in this operation since the
pixels are condensed, but the pixel size is increased
correspondingly.
- Args:
- - `scale` (int): The scale factor by which to reduce the image.
+ :param scale: The scale factor by which to reduce the image.
+ :type scale: int
"""
if not isinstance(scale, int) and not (
isinstance(scale, ArrayLike) and scale.dtype is backend.int32
diff --git a/astrophot/image/jacobian_image.py b/astrophot/image/jacobian_image.py
index 7c6d0777..49b7b4cf 100644
--- a/astrophot/image/jacobian_image.py
+++ b/astrophot/image/jacobian_image.py
@@ -13,7 +13,7 @@ class JacobianImage(Image):
Image object which represents the evaluation of a jacobian on an
image. It takes the form of a 3D (Image x Nparameters)
- tensor. This object can be added other other Jacobian images to
+ Array. This object can be added other other Jacobian images to
build up a full jacobian for a complex model.
"""
diff --git a/astrophot/image/mixins/data_mixin.py b/astrophot/image/mixins/data_mixin.py
index ea2cfefb..23690176 100644
--- a/astrophot/image/mixins/data_mixin.py
+++ b/astrophot/image/mixins/data_mixin.py
@@ -17,11 +17,10 @@ class DataMixin:
This mixin provides functionality for handling variance and mask,
as well as other ancillary data.
- Args:
- - `mask`: A boolean mask indicating which pixels to ignore.
- - `std`: Standard deviation of the image pixels.
- - `variance`: Variance of the image pixels.
- - `weight`: Weights for the image pixels.
+ :param mask: A boolean mask indicating which pixels to ignore.
+ :param std: Standard deviation of the image pixels.
+ :param variance: Variance of the image pixels.
+ :param weight: Weights for the image pixels.
Note that only one of `std`, `variance`, or `weight` should be
provided at a time. If multiple are provided, an error will be raised.
@@ -67,7 +66,7 @@ def std(self):
"""Stores the standard deviation of the image pixels. This represents
the uncertainty in each pixel value. It should always have the
same shape as the image data. In the case where the standard
- deviation is not known, a tensor of ones will be created to
+ deviation is not known, a Array of ones will be created to
stand in as the standard deviation values.
The standard deviation is not stored directly, instead it is
@@ -91,7 +90,7 @@ def variance(self):
"""Stores the variance of the image pixels. This represents the
uncertainty in each pixel value. It should always have the
same shape as the image data. In the case where the variance
- is not known, a tensor of ones will be created to stand in as
+ is not known, a Array of ones will be created to stand in as
the variance values.
The variance is not stored directly, instead it is
@@ -120,7 +119,7 @@ def weight(self):
"""Stores the weight of the image pixels. This represents the
uncertainty in each pixel value. It should always have the
same shape as the image data. In the case where the weight
- is not known, a tensor of ones will be created to stand in as
+ is not known, a Array of ones will be created to stand in as
the weight values.
The weights are used to proprtionately scale residuals in the
@@ -170,7 +169,7 @@ def _weight(self, value):
@property
def mask(self):
- """The mask stores a tensor of boolean values which indicate any
+ """The mask stores a Array of boolean values which indicate any
pixels to be ignored. These pixels will be skipped in
likelihood evaluations and in parameter optimization. It is
common practice to mask pixels with pathological values such
diff --git a/astrophot/image/psf_image.py b/astrophot/image/psf_image.py
index 82a071af..08b0a265 100644
--- a/astrophot/image/psf_image.py
+++ b/astrophot/image/psf_image.py
@@ -70,12 +70,12 @@ def window(self) -> Window:
@property
def data(self):
- """The image data, which is a tensor of pixel values."""
+ """The image data, which is a Array of pixel values."""
return backend.transpose(self._data, 1, 0)
@data.setter
def data(self, value: Optional[ArrayLike]):
- """Set the image data. If value is None, the data is initialized to an empty tensor."""
+ """Set the image data. If value is None, the data is initialized to an empty Array."""
if value is None:
self._data = backend.ones((1, 1), dtype=config.DTYPE, device=config.DEVICE)
else:
diff --git a/astrophot/image/sip_image.py b/astrophot/image/sip_image.py
index 74c3c6b3..68bf66c6 100644
--- a/astrophot/image/sip_image.py
+++ b/astrophot/image/sip_image.py
@@ -46,13 +46,12 @@ def reduce(self, scale: int, **kwargs):
"""This operation will downsample an image by the factor given. If
scale = 2 then 2x2 blocks of pixels will be summed together to
form individual larger pixels. A new image object will be
- returned with the appropriate pixelscale and data tensor. Note
+ returned with the appropriate pixelscale and data Array. Note
that the window does not change in this operation since the
pixels are condensed, but the pixel size is increased
correspondingly.
- Args:
- - `scale`: factor by which to condense the image pixels. Each scale X scale region will be summed [int]
+ :param scale: factor by which to condense the image pixels. Each scale X scale region will be summed [int]
"""
if not isinstance(scale, int) and not (
diff --git a/astrophot/plots/diagnostic.py b/astrophot/plots/diagnostic.py
index 605ce64f..f006ce70 100644
--- a/astrophot/plots/diagnostic.py
+++ b/astrophot/plots/diagnostic.py
@@ -21,14 +21,20 @@ def covariance_matrix(
"""
Create a covariance matrix plot. Creates a corner plot with ellipses representing the covariance between parameters.
- Args:
- - `covariance_matrix` (np.ndarray): Covariance matrix of shape (n_params, n_params).
- - `mean` (np.ndarray): Mean values of the parameters, shape (n_params,).
- - `labels` (list, optional): Labels for the parameters.
- - `figsize` (tuple, optional): Size of the figure. Default is (10, 10).
- - `reference_values` (np.ndarray, optional): Reference values for the parameters, used to draw vertical and horizontal lines. Typically these are the true values of the parameters.
- - `ellipse_colors` (str or list, optional): Color for the ellipses. Default is `main_pallet["primary1"]`.
- - `showticks` (bool, optional): Whether to show ticks on the axes. Default is True.
+ :param covariance_matrix: Covariance matrix of shape (n_params, n_params).
+ :type covariance_matrix: np.ndarray
+ :param mean: Mean values of the parameters, shape (n_params,).
+ :type mean: np.ndarray
+ :param labels: Labels for the parameters.
+ :type labels: list, optional
+ :param figsize: Size of the figure. Default is (10, 10).
+ :type figsize: tuple, optional
+ :param reference_values: Reference values for the parameters, used to draw vertical and horizontal lines. Typically these are the true values of the parameters.
+ :type reference_values: np.ndarray, optional
+ :param ellipse_colors: Color for the ellipses. Default is `main_pallet["primary1"]`.
+ :type ellipse_colors: str or list, optional
+ :param showticks: Whether to show ticks on the axes. Default is True.
+ :type showticks: bool, optional
returns the fig and ax objects created to allow further customization by the user.
"""
diff --git a/astrophot/plots/image.py b/astrophot/plots/image.py
index afe7b800..caeecde5 100644
--- a/astrophot/plots/image.py
+++ b/astrophot/plots/image.py
@@ -26,13 +26,16 @@ def target_image(fig, ax, target, window=None, **kwargs):
visibility of the image data for the faint areas of the image, while it uses
log scale normalization for the bright areas.
- Args:
- - `fig` (matplotlib.figure.Figure): The figure object in which the target image will be displayed.
- - `ax` (matplotlib.axes.Axes): The axes object on which the target image will be plotted.
- - `target` (Image or Image_List): The image or list of images to be displayed.
- - `window` (Window, optional): The window through which the image is viewed. If `None`, the window of the
+ :param fig: The figure object in which the target image will be displayed.
+ :type fig: matplotlib.figure.Figure
+ :param ax: The axes object on which the target image will be plotted.
+ :type ax: matplotlib.axes.Axes
+ :param target: The image or list of images to be displayed.
+ :type target: Image or Image_List
+ :param window: The window through which the image is viewed. If `None`, the window of the
+ :type window: Window, optional
provided `target` is used. Defaults to `None`.
- - **kwargs: Arbitrary keyword arguments.
+ :param kwargs: Arbitrary keyword arguments.
Note:
If the `target` is an `Image_List`, this function will recursively call itself for each image in the list.
@@ -113,13 +116,18 @@ def psf_image(
):
"""For plotting PSF images, or the output of a PSF model.
- Args:
- - `fig` (matplotlib.figure.Figure): The figure object in which the PSF image will be displayed.
- - `ax` (matplotlib.axes.Axes): The axes object on which the PSF image will be plotted.
- - `psf` (PSFImage or PSFModel or PSFGroupModel): The PSF model or group model to be displayed.
- - `cmap_levels` (int, optional): The number of discrete levels to convert the continuous color map to. If not `None`, the color map is converted to a ListedColormap with the specified number of levels. Defaults to `None`.
- - `vmin` (float, optional): The minimum value for the color scale. Defaults to `None`.
- - `vmax` (float, optional): The maximum value for the color scale. Defaults to `None`.
+ :param fig: The figure object in which the PSF image will be displayed.
+ :type fig: matplotlib.figure.Figure
+ :param ax: The axes object on which the PSF image will be plotted.
+ :type ax: matplotlib.axes.Axes
+ :param psf: The PSF model or group model to be displayed.
+ :type psf: PSFImage or PSFModel or PSFGroupModel
+ :param cmap_levels: The number of discrete levels to convert the continuous color map to. If not `None`, the color map is converted to a ListedColormap with the specified number of levels. Defaults to `None`.
+ :type cmap_levels: int, optional
+ :param vmin: The minimum value for the color scale. Defaults to `None`.
+ :type vmin: float, optional
+ :param vmax: The maximum value for the color scale. Defaults to `None`.
+ :type vmax: float, optional
"""
if isinstance(psf, (PSFModel, PSFGroupModel)):
psf = psf()
@@ -181,20 +189,31 @@ def model_image(
"""
This function is used to generate a model image and display it using the provided figure and axes.
- Args:
- - `fig` (matplotlib.figure.Figure): The figure object in which the image will be displayed.
- - `ax` (matplotlib.axes.Axes): The axes object on which the image will be plotted.
- - `model` (Model): The model object used to generate a model image if `sample_image` is not provided.
- - `sample_image` (Image or Image_List, optional): The image or list of images to be displayed. If `None`, a model image is generated using the provided `model`. Defaults to `None`.
- - `window` (Window, optional): The window through which the image is viewed. If `None`, the window of the provided `model` is used. Defaults to `None`.
- - `target` (Target, optional): The target or list of targets for the image or image list. If `None`, the target of the `model` is used. Defaults to `None`.
- - `showcbar` (bool, optional): Whether to show the color bar. Defaults to `True`.
- - `target_mask` (bool, optional): Whether to apply the mask of the target. If `True` and if the target has a mask, the mask is applied to the image. Defaults to `False`.
- - `cmap_levels` (int, optional): The number of discrete levels to convert the continuous color map to. If not `None`, the color map is converted to a ListedColormap with the specified number of levels. Defaults to `None`.
- - `magunits` (bool, optional): Whether to convert the image to surface brightness units. If `True`, the zeropoint of the target is used to convert the image to surface brightness units. Defaults to `True`.
- - `vmin` (float, optional): The minimum value for the color scale. Defaults to `None`.
- - `vmax` (float, optional): The maximum value for the color scale. Defaults to `None`.
- - **kwargs: Arbitrary keyword arguments. These are used to override the default imshow_kwargs.
+ :param fig: The figure object in which the image will be displayed.
+ :type fig: matplotlib.figure.Figure
+ :param ax: The axes object on which the image will be plotted.
+ :type ax: matplotlib.axes.Axes
+ :param model: The model object used to generate a model image if `sample_image` is not provided.
+ :type model: Model
+ :param sample_image: The image or list of images to be displayed. If `None`, a model image is generated using the provided `model`. Defaults to `None`.
+ :type sample_image: Image or Image_List, optional
+ :param window: The window through which the image is viewed. If `None`, the window of the provided `model` is used. Defaults to `None`.
+ :type window: Window, optional
+ :param target: The target or list of targets for the image or image list. If `None`, the target of the `model` is used. Defaults to `None`.
+ :type target: Target, optional
+ :param showcbar: Whether to show the color bar. Defaults to `True`.
+ :type showcbar: bool, optional
+ :param target_mask: Whether to apply the mask of the target. If `True` and if the target has a mask, the mask is applied to the image. Defaults to `False`.
+ :type target_mask: bool, optional
+ :param cmap_levels: The number of discrete levels to convert the continuous color map to. If not `None`, the color map is converted to a ListedColormap with the specified number of levels. Defaults to `None`.
+ :type cmap_levels: int, optional
+ :param magunits: Whether to convert the image to surface brightness units. If `True`, the zeropoint of the target is used to convert the image to surface brightness units. Defaults to `True`.
+ :type magunits: bool, optional
+ :param vmin: The minimum value for the color scale. Defaults to `None`.
+ :type vmin: float, optional
+ :param vmax: The maximum value for the color scale. Defaults to `None`.
+ :type vmax: float, optional
+ :param kwargs: Arbitrary keyword arguments. These are used to override the default imshow_kwargs.
Note:
If the `sample_image` is an `Image_List`, this function will recursively call itself for each image in the list,
@@ -311,18 +330,27 @@ def residual_image(
This function is used to calculate and display the residuals of a model image with respect to a target image.
The residuals are calculated as the difference between the target image and the sample image and may be normalized by the standard deviation.
- Args:
- - `fig` (matplotlib.figure.Figure): The figure object in which the residuals will be displayed.
- - `ax` (matplotlib.axes.Axes): The axes object on which the residuals will be plotted.
- - `model` (Model): The model object used to generate a model image if `sample_image` is not provided.
- - `target` (Target or Image_List, optional): The target or list of targets for the image or image list. If `None`, the target of the `model` is used. Defaults to `None`.
- - `sample_image` (Image or Image_List, optional): The image or list of images from which residuals will be calculated. If `None`, a model image is generated using the provided `model`. Defaults to `None`.
- - `showcbar` (bool, optional): Whether to show the color bar. Defaults to `True`.
- - `window` (Window or Window_List, optional): The window through which the image is viewed. If `None`, the window of the provided `model` is used. Defaults to `None`.
- - `clb_label` (str, optional): The label for the colorbar. If `None`, a default label is used based on the normalization of the residuals. Defaults to `None`.
- - `normalize_residuals` (bool, optional): Whether to normalize the residuals. If `True`, residuals are divided by the square root of the variance of the target. Defaults to `False`.
- - `scaling` (str, optional): The scaling method for the residuals. Options are "arctan", "clip", or "none". arctan will show all residuals, though squish high values to make the fainter residuals more visible, clip will show the residuals in linear space but remove any values above/below 5 sigma, none does no scaling and simply shows the residuals in linear space. Defaults to "arctan".
- - `**kwargs`: Arbitrary keyword arguments. These are used to override the default imshow_kwargs.
+ :param fig: The figure object in which the residuals will be displayed.
+ :type fig: matplotlib.figure.Figure
+ :param ax: The axes object on which the residuals will be plotted.
+ :type ax: matplotlib.axes.Axes
+ :param model: The model object used to generate a model image if `sample_image` is not provided.
+ :type model: Model
+ :param target: The target or list of targets for the image or image list. If `None`, the target of the `model` is used. Defaults to `None`.
+ :type target: Target or Image_List, optional
+ :param sample_image: The image or list of images from which residuals will be calculated. If `None`, a model image is generated using the provided `model`. Defaults to `None`.
+ :type sample_image: Image or Image_List, optional
+ :param showcbar: Whether to show the color bar. Defaults to `True`.
+ :type showcbar: bool, optional
+ :param window: The window through which the image is viewed. If `None`, the window of the provided `model` is used. Defaults to `None`.
+ :type window: Window or Window_List, optional
+ :param clb_label: The label for the colorbar. If `None`, a default label is used based on the normalization of the residuals. Defaults to `None`.
+ :type clb_label: str, optional
+ :param normalize_residuals: Whether to normalize the residuals. If `True`, residuals are divided by the square root of the variance of the target. Defaults to `False`.
+ :type normalize_residuals: bool, optional
+ :param scaling: The scaling method for the residuals. Options are "arctan", "clip", or "none". arctan will show all residuals, though squish high values to make the fainter residuals more visible, clip will show the residuals in linear space but remove any values above/below 5 sigma, none does no scaling and simply shows the residuals in linear space. Defaults to "arctan".
+ :type scaling: str, optional
+ :param kwargs: Arbitrary keyword arguments. These are used to override the default imshow_kwargs.
Note:
If the `window`, `target`, or `sample_image` are lists, this function will recursively call itself for each element in the list,
@@ -423,13 +451,17 @@ def model_window(fig, ax, model, target=None, rectangle_linewidth=2, **kwargs):
"""Used for plotting the window(s) of a model on a target image. These
windows bound the region that a model will be evaluated/fit to.
- Args:
- - `fig` (matplotlib.figure.Figure): The figure object in which the model window will be displayed.
- - `ax` (matplotlib.axes.Axes): The axes object on which the model window will be plotted.
- - `model` (Model): The model object whose window will be displayed.
- - `target` (Target or Image_List, optional): The target or list of targets for the image or image list. If `None`, the target of the `model` is used. Defaults to `None`.
- - `rectangle_linewidth` (int, optional): The linewidth of the rectangle drawn around the model window. Defaults to 2.
- - **kwargs: Arbitrary keyword arguments. These are used to override the default rectangle properties.
+ :param fig: The figure object in which the model window will be displayed.
+ :type fig: matplotlib.figure.Figure
+ :param ax: The axes object on which the model window will be plotted.
+ :type ax: matplotlib.axes.Axes
+ :param model: The model object whose window will be displayed.
+ :type model: Model
+ :param target: The target or list of targets for the image or image list. If `None`, the target of the `model` is used. Defaults to `None`.
+ :type target: Target or Image_List, optional
+ :param rectangle_linewidth: The linewidth of the rectangle drawn around the model window. Defaults to 2.
+ :type rectangle_linewidth: int, optional
+ :param kwargs: Arbitrary keyword arguments. These are used to override the default rectangle properties.
"""
if target is None:
target = model.target
diff --git a/astrophot/plots/profile.py b/astrophot/plots/profile.py
index 09c0aa31..5c886e1f 100644
--- a/astrophot/plots/profile.py
+++ b/astrophot/plots/profile.py
@@ -34,15 +34,20 @@ def radial_light_profile(
"""
Used to plot the brightness profile as a function of radius for models which define a `radial_model`.
- Args:
- - `fig`: matplotlib figure object
- - `ax`: matplotlib axis object
- - `model` (Model): Model object from which to plot the radial profile.
- - `rad_unit` (str): The name of the radius units to plot. If you select "pixel" then the plot will work in pixel units (physical radii divided by pixelscale) if you choose any other string then it will remain in the physical units of the image and the axis label will be whatever you set the value to. Default: "arcsec". Options: "arcsec", "pixel"
- - `extend_profile` (float): The factor by which to extend the profile beyond the maximum radius of the model's window. Default: 1.0
- - `R0` (float): The starting radius for the profile. Default: 0.0
- - `resolution` (int): The number of points to use in the profile. Default: 1000
- - `plot_kwargs` (dict): Additional keyword arguments to pass to the plot function, such as `linewidth`, `color`, etc.
+ :param fig: matplotlib figure object
+ :param ax: matplotlib axis object
+ :param model: Model object from which to plot the radial profile.
+ :type model: Model
+ :param rad_unit: The name of the radius units to plot. If you select "pixel" then the plot will work in pixel units (physical radii divided by pixelscale) if you choose any other string then it will remain in the physical units of the image and the axis label will be whatever you set the value to. Default: "arcsec". Options: "arcsec", "pixel"
+ :type rad_unit: str
+ :param extend_profile: The factor by which to extend the profile beyond the maximum radius of the model's window. Default: 1.0
+ :type extend_profile: float
+ :param R0: The starting radius for the profile. Default: 0.0
+ :type R0: float
+ :param resolution: The number of points to use in the profile. Default: 1000
+ :type resolution: int
+ :param plot_kwargs: Additional keyword arguments to pass to the plot function, such as `linewidth`, `color`, etc.
+ :type plot_kwargs: dict
"""
xx = backend.linspace(
R0,
@@ -98,14 +103,18 @@ def radial_median_profile(
representation of the image data if one were to simply average the
pixels along isophotes.
- Args:
- - `fig`: matplotlib figure object
- - `ax`: matplotlib axis object
- - `model` (AstroPhot_Model): Model object from which to determine the radial binning. Also provides the target image to extract the data
- - `count_limit` (int): The limit of pixels in a bin, below which uncertainties are not computed. Default: 10
- - `return_profile` (bool): Instead of just returning the fig and ax object, will return the extracted profile formatted as: Rbins (the radial bin edges), medians (the median in each bin), scatter (the 16-84 quartile range / 2), count (the number of pixels in each bin). Default: False
- - `rad_unit` (str): The name of the radius units to plot. If you select "pixel" then the plot will work in pixel units (physical radii divided by pixelscale) if you choose any other string then it will remain in the physical units of the image and the axis label will be whatever you set the value to. Default: "arcsec". Options: "arcsec", "pixel"
- - `plot_kwargs` (dict): Additional keyword arguments to pass to the plot function, such as `linewidth`, `color`, etc.
+ :param fig: matplotlib figure object
+ :param ax: matplotlib axis object
+ :param model: Model object from which to determine the radial binning. Also provides the target image to extract the data
+ :type model: AstroPhot_Model
+ :param count_limit: The limit of pixels in a bin, below which uncertainties are not computed. Default: 10
+ :type count_limit: int
+ :param return_profile: Instead of just returning the fig and ax object, will return the extracted profile formatted as: Rbins (the radial bin edges), medians (the median in each bin), scatter (the 16-84 quartile range / 2), count (the number of pixels in each bin). Default: False
+ :type return_profile: bool
+ :param rad_unit: The name of the radius units to plot. If you select "pixel" then the plot will work in pixel units (physical radii divided by pixelscale) if you choose any other string then it will remain in the physical units of the image and the axis label will be whatever you set the value to. Default: "arcsec". Options: "arcsec", "pixel"
+ :type rad_unit: str
+ :param plot_kwargs: Additional keyword arguments to pass to the plot function, such as `linewidth`, `color`, etc.
+ :type plot_kwargs: dict
"""
@@ -195,13 +204,16 @@ def ray_light_profile(
"""
Used for plotting ray (wedge) type models which define a `iradial_model` method. These have multiple radial profiles.
- Args:
- - `fig`: matplotlib figure object
- - `ax`: matplotlib axis object
- - `model` (Model): Model object from which to plot the radial profile.
- - `rad_unit` (str): The name of the radius units to plot.
- - `extend_profile` (float): The factor by which to extend the profile beyond the maximum radius of the model's window. Default: 1.0
- - `resolution` (int): The number of points to use in the profile. Default: 1000
+ :param fig: matplotlib figure object
+ :param ax: matplotlib axis object
+ :param model: Model object from which to plot the radial profile.
+ :type model: Model
+ :param rad_unit: The name of the radius units to plot.
+ :type rad_unit: str
+ :param extend_profile: The factor by which to extend the profile beyond the maximum radius of the model's window. Default: 1.0
+ :type extend_profile: float
+ :param resolution: The number of points to use in the profile. Default: 1000
+ :type resolution: int
"""
xx = backend.linspace(
0,
From 3a90cabcd67f7abd872d4c9e1c05ab630cddcd4d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Mar 2026 12:50:09 +0000
Subject: [PATCH 13/16] Refine RST return fields and param formatting
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/06d20147-ecab-453e-9cbe-afad8be6827b
---
Test_AstroPhot.fits | Bin 0 -> 8640 bytes
Test_target_AstroPhot.fits | Bin 0 -> 31680 bytes
astrophot/image/func/wcs.py | 18 ++++++------------
astrophot/plots/image.py | 4 ++--
4 files changed, 8 insertions(+), 14 deletions(-)
create mode 100644 Test_AstroPhot.fits
create mode 100644 Test_target_AstroPhot.fits
diff --git a/Test_AstroPhot.fits b/Test_AstroPhot.fits
new file mode 100644
index 0000000000000000000000000000000000000000..9e9fe4069d6b0394ca6015747924dc38eec6dc8a
GIT binary patch
literal 8640
zcmeH{&2EA~6ovaJcjpSq4EVP&4F%eeC?QH3?WUm>6Bj}Qbm3d~5jtQSX}pO-Oc%|$
z3mJ#uJd$dsfcdrElW39zALEA=)sQ`RFrYLj`KCMUQONmQRpvOo;I))
zFV6FLPwTjhsocLOJmokW*h_z*{<8X{;-w$E*CeNG^F!Y5lC;=nX>o)!Mm10HJX1Cn
zUO23I>N!rI7+eTxEOVk&=+*jqb6eB2$PRjq+pUK+uh!RdJ?9F%`I9~6{1b+u8?EJ$
zQ}HdfQy30=*%EyoovmF*K!pVKg;
z_*HFbL=~@+!JLn7{o=}ReJ5Hv^A7s1v)`Hh_#CqPl|r{pG@qUD-5^>WdBPlz#(g<7
z&qLnlv=|*=mWh1S6K|p~@>%ZPln3HTuP|cS$
zF`$nxXmFi3=RCHL2tLGtJM^y|AuffYgyKT{m?ihKbh;4BnYePpKrEI~GKtcOqP?v8
z;D)|CR_fK;EvXl!Y4j{6(J~Ut=XtDFDQi7z><03!(mqq_B~R1uaVlo_f0ZAnak6-v
zC5uv|a+K>CYQ3geX}IHIt|!k^*=MwO6sa_G#-Zc&)p{bVG~Dsf4)1&?_qR5(>h*eP
zd9@u+RW{4@a(`=m$NmR;qtDj0x<49k8%h&4R@#}Kx<54ad78e
z+o$QT)KlB1r`I>WN%Q3Vkf%2qW@n{r>`LW7ZK)^CQ_VL``^-P~y||pVUSVJEZ_8*`
z%ZqDltr%K^ufEz}t?}aaz3{HoGn&0_@15Ccnw_3uYRtDhSZ(!!1`vP%1kR7Z`(JPJ
z!e2OK1Q-X51I7XKfH*)LAPx`*hy%m{;s9}gIB=eEpzw-U2tWV=5P-m831sO4fqUa!
zikd6e3S}mTsIKo{2zMGi#3KH=EV3fDeFIPaMoCB~f5W$LZatZ&p~?pljg@?rd6Y)e
zcp0baOqIfp!6rRpMeiY{
zg#ZK~009UbmcRk?Hw4e$*uD&LLirm*EBKT-ME=J1ZlwhTAOHafKmY<~MBuQW*0~x4
zAOHafKmY;|fB*y_009U<00Izz00bZa0SLSn0td|BIQsolL~s9vg-!dX=;$4L{>H5z
z$PIVaJRc<6C}YoJkJj!_B1CIXG1)xVQ}6$wrMGs!iLTkzdA>^J`6YgEmHS8j%l_TW
q84!Q~1Rwx`|4QIoe^-QG#U0?OaCj~EtM~~42tWV=5P-nx6Zj3O4{Le=
literal 0
HcmV?d00001
diff --git a/astrophot/image/func/wcs.py b/astrophot/image/func/wcs.py
index b10a2916..32ce104b 100644
--- a/astrophot/image/func/wcs.py
+++ b/astrophot/image/func/wcs.py
@@ -20,11 +20,8 @@ def world_to_plane_gnomonic(ra, dec, ra0, dec0, x0=0.0, y0=0.0):
:type ra0: Array
:param dec0: Reference Declination in degrees.
:type dec0: Array
-
- :returns: ``x`` -- x coordinate in arcseconds.
- :rtype: Array
- :returns: ``y`` -- y coordinate in arcseconds.
- :rtype: Array
+ :returns: Tuple containing ``x`` and ``y`` coordinates in arcseconds.
+ :rtype: tuple[Array, Array]
"""
ra = ra * deg_to_rad
dec = dec * deg_to_rad
@@ -58,11 +55,8 @@ def plane_to_world_gnomonic(x, y, ra0, dec0, x0=0.0, y0=0.0, s=1e-10):
:type dec0: Array
:param s: Small constant to avoid division by zero.
:type s: float
-
- :returns: ``ra`` -- Right Ascension in degrees.
- :rtype: Array
- :returns: ``dec`` -- Declination in degrees.
- :rtype: Array
+ :returns: Tuple containing ``ra`` and ``dec`` in degrees.
+ :rtype: tuple[Array, Array]
"""
x = (x - x0) * arcsec_to_rad
y = (y - y0) * arcsec_to_rad
@@ -97,9 +91,9 @@ def pixel_to_plane_linear(i, j, i0, j0, CD, x0=0.0, y0=0.0):
:type i0: Array
:param j0: The j reference pixel coordinate in pixel units.
:type j0: Array
- :param CD: The CD matrix in arcsec per pixel. This 2x2 matrix is used to convert
+ :param CD: The CD matrix in arcsec per pixel. This 2x2 matrix converts
+ from pixel to arcsec units and also handles rotation/skew.
:type CD: Array
- from pixel to arcsec units and also handles rotation/skew.
:param x0: The x reference coordinate in arcseconds.
:type x0: float
:param y0: The y reference coordinate in arcseconds.
diff --git a/astrophot/plots/image.py b/astrophot/plots/image.py
index caeecde5..0981b27c 100644
--- a/astrophot/plots/image.py
+++ b/astrophot/plots/image.py
@@ -32,9 +32,9 @@ def target_image(fig, ax, target, window=None, **kwargs):
:type ax: matplotlib.axes.Axes
:param target: The image or list of images to be displayed.
:type target: Image or Image_List
- :param window: The window through which the image is viewed. If `None`, the window of the
+ :param window: The window through which the image is viewed. If `None`,
+ the window of the provided `target` is used. Defaults to `None`.
:type window: Window, optional
- provided `target` is used. Defaults to `None`.
:param kwargs: Arbitrary keyword arguments.
Note:
From 8cb2ac28f7296588d6534cd8164929ed56900c3c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Mar 2026 12:50:20 +0000
Subject: [PATCH 14/16] Remove generated FITS artifacts from PR
Co-authored-by: ConnorStoneAstro <78555321+ConnorStoneAstro@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Autostronomy/AstroPhot/sessions/06d20147-ecab-453e-9cbe-afad8be6827b
---
Test_AstroPhot.fits | Bin 8640 -> 0 bytes
Test_target_AstroPhot.fits | Bin 31680 -> 0 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 Test_AstroPhot.fits
delete mode 100644 Test_target_AstroPhot.fits
diff --git a/Test_AstroPhot.fits b/Test_AstroPhot.fits
deleted file mode 100644
index 9e9fe4069d6b0394ca6015747924dc38eec6dc8a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 8640
zcmeH{&2EA~6ovaJcjpSq4EVP&4F%eeC?QH3?WUm>6Bj}Qbm3d~5jtQSX}pO-Oc%|$
z3mJ#uJd$dsfcdrElW39zALEA=)sQ`RFrYLj`KCMUQONmQRpvOo;I))
zFV6FLPwTjhsocLOJmokW*h_z*{<8X{;-w$E*CeNG^F!Y5lC;=nX>o)!Mm10HJX1Cn
zUO23I>N!rI7+eTxEOVk&=+*jqb6eB2$PRjq+pUK+uh!RdJ?9F%`I9~6{1b+u8?EJ$
zQ}HdfQy30=*%EyoovmF*K!pVKg;
z_*HFbL=~@+!JLn7{o=}ReJ5Hv^A7s1v)`Hh_#CqPl|r{pG@qUD-5^>WdBPlz#(g<7
z&qLnlv=|*=mWh1S6K|p~@>%ZPln3HTuP|cS$
zF`$nxXmFi3=RCHL2tLGtJM^y|AuffYgyKT{m?ihKbh;4BnYePpKrEI~GKtcOqP?v8
z;D)|CR_fK;EvXl!Y4j{6(J~Ut=XtDFDQi7z><03!(mqq_B~R1uaVlo_f0ZAnak6-v
zC5uv|a+K>CYQ3geX}IHIt|!k^*=MwO6sa_G#-Zc&)p{bVG~Dsf4)1&?_qR5(>h*eP
zd9@u+RW{4@a(`=m$NmR;qtDj0x<49k8%h&4R@#}Kx<54ad78e
z+o$QT)KlB1r`I>WN%Q3Vkf%2qW@n{r>`LW7ZK)^CQ_VL``^-P~y||pVUSVJEZ_8*`
z%ZqDltr%K^ufEz}t?}aaz3{HoGn&0_@15Ccnw_3uYRtDhSZ(!!1`vP%1kR7Z`(JPJ
z!e2OK1Q-X51I7XKfH*)LAPx`*hy%m{;s9}gIB=eEpzw-U2tWV=5P-m831sO4fqUa!
zikd6e3S}mTsIKo{2zMGi#3KH=EV3fDeFIPaMoCB~f5W$LZatZ&p~?pljg@?rd6Y)e
zcp0baOqIfp!6rRpMeiY{
zg#ZK~009UbmcRk?Hw4e$*uD&LLirm*EBKT-ME=J1ZlwhTAOHafKmY<~MBuQW*0~x4
zAOHafKmY;|fB*y_009U<00Izz00bZa0SLSn0td|BIQsolL~s9vg-!dX=;$4L{>H5z
z$PIVaJRc<6C}YoJkJj!_B1CIXG1)xVQ}6$wrMGs!iLTkzdA>^J`6YgEmHS8j%l_TW
q84!Q~1Rwx`|4QIoe^-QG#U0?OaCj~EtM~~42tWV=5P-nx6Zj3O4{Le=
From 185a256667a7b2829eeed9e5607c378fb01daa58 Mon Sep 17 00:00:00 2001
From: Connor Stone
Date: Wed, 25 Mar 2026 09:05:09 -0400
Subject: [PATCH 15/16] further documentation updates to match RST formatting
and better explain every method
---
astrophot/image/cmos_image.py | 5 ++++
astrophot/image/image_batch.py | 0
astrophot/image/image_object.py | 33 ++++++++++++++--------
astrophot/image/jacobian_image.py | 2 ++
astrophot/image/model_image.py | 4 +++
astrophot/image/psf_image.py | 2 ++
astrophot/image/sip_image.py | 3 ++
astrophot/image/target_image.py | 41 ++++++++++++++--------------
astrophot/models/mixins/sample.py | 22 +++++----------
astrophot/models/mixins/transform.py | 2 +-
astrophot/models/model_object.py | 2 +-
astrophot/utils/decorators.py | 15 +++-------
12 files changed, 71 insertions(+), 60 deletions(-)
delete mode 100644 astrophot/image/image_batch.py
diff --git a/astrophot/image/cmos_image.py b/astrophot/image/cmos_image.py
index fac27d21..35922bc6 100644
--- a/astrophot/image/cmos_image.py
+++ b/astrophot/image/cmos_image.py
@@ -5,12 +5,17 @@
from .mixins import CMOSMixin
from .model_image import ModelImage
from ..backend_obj import backend
+from ..utils.decorators import combine_docstrings
+__all__ = ("CMOSModelImage", "CMOSTargetImage")
+
+@combine_docstrings
class CMOSModelImage(CMOSMixin, ModelImage):
"""A ModelImage with CMOS-specific functionality."""
+@combine_docstrings
class CMOSTargetImage(CMOSMixin, TargetImage):
"""
A TargetImage with CMOS-specific functionality.
diff --git a/astrophot/image/image_batch.py b/astrophot/image/image_batch.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/astrophot/image/image_object.py b/astrophot/image/image_object.py
index 794a400d..6dd9b27c 100644
--- a/astrophot/image/image_object.py
+++ b/astrophot/image/image_object.py
@@ -24,17 +24,17 @@ class Image(Module):
image boundaries. It also provides methods for determining the coordinate
locations of pixels
+ :param crval: The reference coordinate of the image in degrees [RA, DEC]. [model param]
+ :param crtan: The tangent plane coordinate of the image in arcseconds [x, y]. [model param]
+ :param CD: The coordinate transformation matrix in arcseconds/pixel. [model param]
+ :param crpix: The reference pixel coordinates in the image, which is used to convert from pixel coordinates to tangent plane coordinates. This is not a model param and is fixed for a given image.
:param data: The image data as a Array of pixel values. If not provided, a Array of zeros will be created.
:param zeropoint: The zeropoint of the image, which is used to convert from pixel flux to magnitude.
- :param crpix: The reference pixel coordinates in the image, which is used to convert from pixel coordinates to tangent plane coordinates.
:param pixelscale: The side length of a pixel, used to create a simple diagonal CD matrix.
:param wcs: An optional Astropy WCS object to initialize the image.
:param filename: The filename to load the image from. If provided, the image will be loaded from the file.
:param hduext: The HDU extension to load from the FITS file specified in `filename`.
- :param identity: An optional identity string for the image.
- :param crval: The reference coordinate of the image in degrees [RA, DEC].
- :param crtan: The tangent plane coordinate of the image in arcseconds [x, y].
- :param CD: The coordinate transformation matrix in arcseconds/pixel.
+ :param identity: An optional identity string for the image (mostly used internally).
"""
expect_ctype = (("RA---TAN",), ("DEC--TAN",))
@@ -619,14 +619,23 @@ def __getitem__(self, *args):
return super().__getitem__(*args)
-# fixme, make image lists infinitely nestable, need to merge "index" and "match_indices" in some consistent way
class ImageList(Module):
+ """A class to represent a list of images.
+
+ This is useful for operations that involve multiple images, mostly for joint
+ modelling. The ImageList class provides methods for matching images based on
+ their identity, and for applying operations to all images in the list while
+ preserving their individual properties. For certain applications (the
+ ``flatten`` method) you can use ImageList and Image objects
+ interchangably/agnostically.
+ """
+
def __init__(self, images: list[Image], **kwargs):
super().__init__(**kwargs)
self.images = list(images)
if not all(isinstance(image, Image) for image in self.images):
raise InvalidImage(
- f"Image_List can only hold Image objects, not {tuple(type(image) for image in self.images)}"
+ f"ImageList can only hold Image objects, not {tuple(type(image) for image in self.images)}"
)
@property
@@ -675,7 +684,7 @@ def index(self, other: Image):
)
def match_indices(self, other: "ImageList"):
- """Match the indices of the images in this list with those in another Image_List."""
+ """Match the indices of the images in this list with those in another ImageList."""
indices = []
for other_image in other.images:
try:
@@ -705,7 +714,7 @@ def __sub__(self, other):
new_list.append(self_image - other_image)
return self.__class__(new_list)
else:
- raise ValueError("Subtraction of Image_List only works with another Image_List object!")
+ raise ValueError("Subtraction of ImageList only works with another ImageList object!")
def __add__(self, other):
if isinstance(other, ImageList):
@@ -719,7 +728,7 @@ def __add__(self, other):
new_list.append(self_image + other_image)
return self.__class__(new_list)
else:
- raise ValueError("Addition of Image_List only works with another Image_List object!")
+ raise ValueError("Addition of ImageList only works with another ImageList object!")
def __isub__(self, other):
if isinstance(other, ImageList):
@@ -733,7 +742,7 @@ def __isub__(self, other):
i = self.index(other)
self.images[i] -= other
else:
- raise ValueError("Subtraction of Image_List only works with another Image_List object!")
+ raise ValueError("Subtraction of ImageList only works with another ImageList object!")
return self
def __iadd__(self, other):
@@ -748,7 +757,7 @@ def __iadd__(self, other):
i = self.index(other)
self.images[i] += other
else:
- raise ValueError("Addition of Image_List only works with another Image_List object!")
+ raise ValueError("Addition of ImageList only works with another ImageList object!")
return self
def __getitem__(self, *args):
diff --git a/astrophot/image/jacobian_image.py b/astrophot/image/jacobian_image.py
index 49b7b4cf..5fb1d506 100644
--- a/astrophot/image/jacobian_image.py
+++ b/astrophot/image/jacobian_image.py
@@ -3,11 +3,13 @@
from .image_object import Image, ImageList, ImageBatchMixin
from ..errors import SpecificationConflict, InvalidImage
from ..backend_obj import backend
+from ..utils.decorators import combine_docstrings
__all__ = ("JacobianImage", "JacobianImageList")
######################################################################
+@combine_docstrings
class JacobianImage(Image):
"""Jacobian of a model evaluated in an image.
diff --git a/astrophot/image/model_image.py b/astrophot/image/model_image.py
index 034b08d0..52f1908a 100644
--- a/astrophot/image/model_image.py
+++ b/astrophot/image/model_image.py
@@ -1,10 +1,12 @@
from .image_object import Image, ImageList, ImageBatchMixin
from ..errors import InvalidImage
+from ..utils.decorators import combine_docstrings
__all__ = ["ModelImage", "ModelImageList"]
######################################################################
+@combine_docstrings
class ModelImage(Image):
"""Image object which represents the sampling of a model at the given
coordinates of the image. Extra arithmetic operations are
@@ -16,6 +18,7 @@ class ModelImage(Image):
######################################################################
+@combine_docstrings
class ModelImageList(ImageList):
"""A list of ModelImage objects."""
@@ -27,5 +30,6 @@ def __init__(self, *args, **kwargs):
)
+@combine_docstrings
class ModelImageBatch(ImageBatchMixin, ModelImageList):
pass
diff --git a/astrophot/image/psf_image.py b/astrophot/image/psf_image.py
index 08b0a265..d175d4cf 100644
--- a/astrophot/image/psf_image.py
+++ b/astrophot/image/psf_image.py
@@ -9,10 +9,12 @@
from .mixins import DataMixin
from .window import Window
from . import func
+from ..utils.decorators import combine_docstrings
__all__ = ("PSFImage",)
+@combine_docstrings
class PSFImage(DataMixin):
"""Image object which represents a model of PSF (Point Spread Function).
diff --git a/astrophot/image/sip_image.py b/astrophot/image/sip_image.py
index 68bf66c6..4d4bc29c 100644
--- a/astrophot/image/sip_image.py
+++ b/astrophot/image/sip_image.py
@@ -5,8 +5,10 @@
from .mixins import SIPMixin
from ..backend_obj import backend, ArrayLike
from .. import config
+from ..utils.decorators import combine_docstrings
+@combine_docstrings
class SIPModelImage(SIPMixin, ModelImage):
"""
A ModelImage with SIP distortion coefficients."""
@@ -95,6 +97,7 @@ def reduce(self, scale: int, **kwargs):
)
+@combine_docstrings
class SIPTargetImage(SIPMixin, TargetImage):
"""
A TargetImage with SIP distortion coefficients.
diff --git a/astrophot/image/target_image.py b/astrophot/image/target_image.py
index a24b4845..dfffba00 100644
--- a/astrophot/image/target_image.py
+++ b/astrophot/image/target_image.py
@@ -34,30 +34,30 @@ class TargetImage(DataMixin, Image):
Basic usage:
.. code-block:: python
- import astrophot as ap
-
- # Create target image
- image = ap.image.Target_Image(
- data="pixel data",
- wcs="astropy WCS object",
- variance="pixel uncertainties",
- psf="point spread function as PSF_Image object",
- mask="True for pixels to ignore",
- )
+ import astrophot as ap
+
+ # Create target image
+ image = ap.image.Target_Image(
+ data="pixel data",
+ wcs="astropy WCS object",
+ variance="pixel uncertainties",
+ psf="point spread function as PSF_Image object",
+ mask="True for pixels to ignore",
+ )
- # Display the data
- fig, ax = plt.subplots()
- ap.plots.target_image(fig, ax, image)
- plt.show()
+ # Display the data
+ fig, ax = plt.subplots()
+ ap.plots.target_image(fig, ax, image)
+ plt.show()
- # Save the image
- image.save("mytarget.fits")
+ # Save the image
+ image.save("mytarget.fits")
- # Load the image
- image2 = ap.image.Target_Image(filename="mytarget.fits")
+ # Load the image
+ image2 = ap.image.Target_Image(filename="mytarget.fits")
- # Make low resolution version
- lowrez = image.reduce(2)
+ # Make low resolution version
+ lowrez = image.reduce(2)
Some important information to keep in mind. First, providing an
@@ -241,6 +241,7 @@ def reduce(self, scale: int, **kwargs) -> "TargetImage":
)
+@combine_docstrings
class TargetImageList(ImageList):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
diff --git a/astrophot/models/mixins/sample.py b/astrophot/models/mixins/sample.py
index db15124e..f3448b0c 100644
--- a/astrophot/models/mixins/sample.py
+++ b/astrophot/models/mixins/sample.py
@@ -13,20 +13,12 @@
class SampleMixin:
"""
- :param sampling_mode: The method used to sample the model in image pixels. Options are:
- * `auto`: Automatically choose the sampling method based on the image size.
- * `midpoint`: Use midpoint sampling, evaluate the brightness at the center of each pixel.
- * `simpsons`: Use Simpson's rule for sampling integrating each pixel.
- * `quad:x`: Use quadrature sampling with order x, where x is a positive integer to integrate each pixel.
- :param integrate_mode: The method used to select pixels to integrate further where the model varies significantly. Options are:
- * `none`: No extra integration is performed (beyond the sampling_mode).
- * `bright`: Select the brightest pixels for further integration.
- * `threshold`: Select pixels which show signs of significant higher order derivatives.
- :param integrate_tolerance: The tolerance for selecting a pixel in the integration method. This is the total flux fraction that is integrated over the image.
- :param integrate_fraction: The fraction of the pixels to super sample during integration.
- :param integrate_max_depth: The maximum depth of the integration method.
- :param integrate_gridding: The gridding used for the integration method to super-sample a pixel at each iteration.
- :param integrate_quad_order: The order of the quadrature used for the integration method on the super sampled pixels.
+ :param sampling_mode: The method used to sample the model in image pixels. Options are: `auto`: Automatically choose the sampling method based on the image size (default). `midpoint`: Use midpoint sampling, evaluate the brightness at the center of each pixel. `simpsons`: Use Simpson's rule for sampling integrating each pixel. `upsample:x` upsample the pixel in a regular grid of size x (odd positive integer), generally less accurate than quad:x. `quad:x`: Use quadrature sampling with order x, where x is an odd positive integer to integrate each pixel.
+ :param integrate_mode: The method used to select pixels to integrate further where the model varies significantly. Options are: `none`: No extra integration is performed (beyond the sampling_mode). `bright`: Select the brightest pixels for further integration (default). `threshold`: Select pixels which show signs of significant higher order derivatives.
+ :param integrate_fraction: The fraction of the pixels to super sample during integration (default: 0.05).
+ :param integrate_max_depth: The maximum depth of the integration method (default: 2).
+ :param integrate_gridding: The gridding used for the integration method to super-sample a pixel at each iteration (default: 5).
+ :param integrate_quad_order: The order of the quadrature used for the integration method on the super sampled pixels (default: 3).
"""
integrate_fraction = 0.05 # fraction of the pixels to super sample
@@ -189,7 +181,7 @@ def integrate_mode(self, integrate_mode):
class GradMixin:
"""
- :param jacobian_maxparams: The maximum number of parameters before the Jacobian will be broken into smaller chunks. This is helpful for limiting the memory requirements to fit a model.
+ :param jacobian_maxparams: The maximum number of parameters before the Jacobian will be broken into smaller chunks to reduce memory consumption (int, default: 10).
"""
# Maximum size of parameter list before jacobian will be broken into smaller chunks, this is helpful for limiting the memory requirements to build a model, lower jacobian_chunksize is slower but uses less memory
diff --git a/astrophot/models/mixins/transform.py b/astrophot/models/mixins/transform.py
index 553be9ca..35ce6a42 100644
--- a/astrophot/models/mixins/transform.py
+++ b/astrophot/models/mixins/transform.py
@@ -104,7 +104,7 @@ def transform_coordinates(
class SuperEllipseMixin:
- """Generalizes the definition of radius and so modifies the evaluation of radial models.
+ """Uses a generalized definition of radius to make boxy/disky models.
A superellipse transformation allows for the expression of "boxy" and
"disky" modifications to traditional elliptical isophotes. This is a common
diff --git a/astrophot/models/model_object.py b/astrophot/models/model_object.py
index dddced13..d7c7e369 100644
--- a/astrophot/models/model_object.py
+++ b/astrophot/models/model_object.py
@@ -24,7 +24,7 @@ class ComponentModel(GradMixin, SampleMixin, Model):
determined by ``center`` and may or may not be convolved with a PSF to represent some data.
:param center: The center of the component in arcseconds [x, y] defined on the tangent plane.
- :param psf_convolve: Whether to convolve the model with a PSF. (bool)
+ :param psf_convolve: Whether to convolve the model with a PSF. (bool, default True)
"""
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index 7baf970a..bb8b02e0 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -96,20 +96,13 @@ def combine_docstrings(cls):
# Collect params from full MRO (base → derived so derived class wins)
all_params = {}
for klass in reversed(cls.__mro__):
- if klass is object:
- continue
- if not klass.__doc__:
+ if klass is object or not klass.__doc__:
continue
_, klass_params = _parse_docstring(cleandoc(klass.__doc__))
all_params.update(klass_params)
- # Build combined body: cls body + direct-base bodies
- try:
- main_body, _ = _parse_docstring(cleandoc(cls.__doc__))
- except (AttributeError, TypeError):
- main_body = ""
-
- for base in cls.__bases__:
+ main_body = ""
+ for base in cls.__mro__:
if base is object or not base.__doc__:
continue
base_body, _ = _parse_docstring(cleandoc(base.__doc__))
@@ -128,7 +121,7 @@ def combine_docstrings(cls):
options = {}
for name, desc in list(all_params.items()):
if name in model_params:
- params[name] = f"{desc} [model param]"
+ params[name] = f"{desc}" + ("" if "[model param]" in desc else " [model param]")
else:
options[name] = desc
main_body += (
From ff79912da95494206f0d28e7f4eb58751fb4b82f Mon Sep 17 00:00:00 2001
From: Connor Stone
Date: Wed, 25 Mar 2026 09:51:34 -0400
Subject: [PATCH 16/16] fix decorator, add basis model to ModelZoo
---
astrophot/utils/decorators.py | 8 +++--
docs/source/tutorials/ModelZoo.ipynb | 44 +++++++++++++++++++++++++---
2 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/astrophot/utils/decorators.py b/astrophot/utils/decorators.py
index bb8b02e0..84853e1d 100644
--- a/astrophot/utils/decorators.py
+++ b/astrophot/utils/decorators.py
@@ -101,8 +101,12 @@ def combine_docstrings(cls):
_, klass_params = _parse_docstring(cleandoc(klass.__doc__))
all_params.update(klass_params)
- main_body = ""
- for base in cls.__mro__:
+ try:
+ main_body, _ = _parse_docstring(cleandoc(cls.__doc__))
+ except (AttributeError, TypeError):
+ main_body = ""
+
+ for base in cls.__bases__:
if base is object or not base.__doc__:
continue
base_body, _ = _parse_docstring(cleandoc(base.__doc__))
diff --git a/docs/source/tutorials/ModelZoo.ipynb b/docs/source/tutorials/ModelZoo.ipynb
index 67a51946..86350343 100644
--- a/docs/source/tutorials/ModelZoo.ipynb
+++ b/docs/source/tutorials/ModelZoo.ipynb
@@ -8,9 +8,7 @@
"\n",
"In this notebook you will see every kind of model in AstroPhot. Printed in each cell will also be the list of parameters which the model looks for while fitting. Many models have unique capabilities and features, this will be introduced here, though fully taking advantage of them will be dependent on your science case.\n",
"\n",
- "For a family tree of all the AstroPhot models see [this link](https://github.com/Autostronomy/AstroPhot/blob/main/media/AstroPhotModelOrgchart.png) \n",
- "\n",
- "Note, we will not be covering `Group_Model` here as that requires a dedicated discussion. See the dedicated notebook for that."
+ "Note, we will not be covering `GroupModel` here as that requires a dedicated discussion. See the dedicated notebook for that."
]
},
{
@@ -231,7 +229,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Moffat PSF"
+ "### Moffat PSF\n",
+ "\n",
+ "A circular PSF model using a Moffat light profile \n",
+ "\n",
+ "**Note:** All of the radial profiles for GalaxyModel types (`sersic`, `ferrer`, `exponential`, `moffat`, `king`, `spline`, `gaussian`, `nuker`) are available for PSFModel's (including an `ellipse` counterpart)."
]
},
{
@@ -829,6 +831,40 @@
"plt.show()"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Basis Model\n",
+ "\n",
+ "This model is similar to the pixelated model, except instead of having the pixels as part of the model, you provide a series of pixelated images as a basis and the model parameters are scalar weights multiplied by the basis. Think eigen decomposition, or zernike polynomials, or wavelets/shapelets. This is just like the BasisPSF model except intended for extended sources.\n",
+ "\n",
+ "Currently just `zernike:n` is available as an option for automatic basis construction, but you can provide any set of images and use those instead!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "weights = [2, 0.0, 0.0, -0.5, 0.0, 2.0]\n",
+ "M = ap.Model(\n",
+ " model_type=\"basis model\",\n",
+ " basis=\"zernike:2\",\n",
+ " center=[50, 50],\n",
+ " weights=weights,\n",
+ " target=basic_target,\n",
+ ")\n",
+ "\n",
+ "M.initialize()\n",
+ "\n",
+ "fig, ax = plt.subplots(1, 1, figsize=(6, 6))\n",
+ "ap.plots.model_image(fig, ax, M, vmax=23)\n",
+ "ax.set_title(M.name)\n",
+ "plt.show()"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},