Skip to content

Commit b316313

Browse files
authored
Merge pull request #179 from transientskp/Fix_176
Fix 176
2 parents 408dff9 + 7308daa commit b316313

9 files changed

Lines changed: 81 additions & 44 deletions

File tree

docs/source/cli.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Command-line interface
2+
======================
3+
4+
.. argparse::
5+
:module: sourcefinder.utility.cli
6+
:func: construct_argument_parser
7+
:prog: pyse

docs/source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"numpydoc",
4040
"autoapi.extension",
4141
"enum_tools.autoenum",
42+
"sphinxarg.ext",
4243
]
4344

4445
autodoc_typehints = "both"

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Welcome to PySE's documentation!
66

77
README
88
sourceparams
9+
cli
910

1011

1112
Indices and tables

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ docs = [
3535
"pydata-sphinx-theme",
3636
"sphinx",
3737
"sphinx-autoapi",
38+
"sphinx-argparse",
3839
]
3940

4041
[project.urls]

sourcefinder/deconv.py

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def covariance_matrix(sigma_maj, sigma_min, theta): # pragma: no cover
123123
-------
124124
Sigma : (2,2) ndarray
125125
Covariance matrix.
126+
126127
"""
127128
c, s = np.cos(theta), np.sin(theta)
128129
R = np.array([[-s, -c], [c, -s]])
@@ -142,20 +143,26 @@ def covariance_matrix(sigma_maj, sigma_min, theta): # pragma: no cover
142143
@njit
143144
def J_S_from_stddevs_and_pa(sigma_maj, sigma_min, theta): # pragma: no cover
144145
"""
145-
Jacobian d(sxx, syy, sxy)/d(sigma_maj, sigma_min, theta).
146+
Jacobian ``d(sxx, syy, sxy) / d(sigma_maj, sigma_min, theta)``.
146147
147-
Parameters:
148+
Parameters
148149
----------
149-
sigma_maj, sigma_min : float
150-
standard-deviations along the elliptical axes
151-
theta : float
152-
angle in radians, CCW from +Y axis
153-
154-
Returns:
155-
J : (3,3) ndarray
156-
rows [dsxx/d*, dsyy/d*, dsxy/d*] and columns corresponding to [
157-
sigma_maj, sigma_min, theta].
150+
sigma_maj : float
151+
Standard deviation along the major axis of the ellipse.
152+
sigma_min : float
153+
Standard deviation along the minor axis of the ellipse.
154+
theta : float
155+
Major axis position angle in radians, counter-clockwise from the +Y
156+
axis.
157+
158+
Returns
159+
-------
160+
J : ndarray of shape (3, 3)
161+
Jacobian matrix. Rows correspond to ``[dsxx/d*, dsyy/d*, dsxy/d*]`` and
162+
columns to ``[sigma_maj, sigma_min, theta]``.
163+
158164
"""
165+
159166
phi = theta + np.pi / 2.0 # convert to math convention (CCW from +x)
160167

161168
c = np.cos(phi)
@@ -205,13 +212,14 @@ def cov_p_to_cov_S(C_p, sigma_maj, sigma_min, theta): # pragma: no cover
205212
206213
Parameters
207214
----------
208-
C_p : (3,3) ndarray (covariance in order [sigma_maj, sigma_min, theta])
209-
sigma_maj, sigma_min: float
210-
theta: float (radians)
215+
C_p : (3,3) ndarray (covariance in order [sigma_maj, sigma_min, theta])
216+
sigma_maj, sigma_min: float
217+
theta: float (radians)
211218
212219
Returns
213220
-------
214-
C_S : (3,3) ndarray (covariance on [sxx, syy, sxy])
221+
C_S : (3,3) ndarray (covariance on [sxx, syy, sxy])
222+
215223
"""
216224
J = J_S_from_stddevs_and_pa(sigma_maj, sigma_min, theta)
217225
C_S = np.empty((3, 3))
@@ -243,15 +251,19 @@ def sigma_to_stddevs_pa_and_jacobian(sxx, syy, sxy): # pragma: no cover
243251
sxx, syy, sxy : float
244252
Covariance matrix elements: if sigma_maj is major axis stddev,
245253
sigma_min is minor axis stddev, and theta the position angle (CCW
246-
from +Y), then
254+
from +Y), then::
255+
247256
S = [[sxx, sxy],
248257
[sxy, syy]] = R @ [[sigma_maj^2, 0],
249258
[0, sigma_min^2]] @ R.T
250-
where R = [[-sin(theta), -cos(theta)],
251-
[ cos(theta), -sin(theta)]]
252-
i.e. sxx = sigma_maj^2 sin^2(theta) + sigma_min^2 cos^2(theta)
253-
syy = sigma_maj^2 cos^2(theta) + sigma_min^2 sin^2(theta)
254-
sxy = -(sigma_maj^2 - sigma_min^2) sin(theta) cos(theta)
259+
260+
where R = [[-sin(theta), -cos(theta)],
261+
[ cos(theta), -sin(theta)]]
262+
263+
i.e. sxx = sigma_maj^2 sin^2(theta) + sigma_min^2 cos^2(theta)
264+
syy = sigma_maj^2 cos^2(theta) + sigma_min^2 sin^2(theta)
265+
sxy = -(sigma_maj^2 - sigma_min^2) sin(theta) cos(theta)
266+
255267
Returns
256268
-------
257269
sigma_maj : float
@@ -264,6 +276,7 @@ def sigma_to_stddevs_pa_and_jacobian(sxx, syy, sxy): # pragma: no cover
264276
Jacobian d[a,b,phi]/d[sxx,syy,sxy]
265277
ok : bool
266278
True if conversion succeeded (Sigma positive definite), else False.
279+
267280
"""
268281
# helpers
269282
m = 0.5 * (sxx + syy)
@@ -363,6 +376,7 @@ def cov_S_to_cov_r(S_dec, C_S_dec): # pragma: no cover
363376
Covariance matrix on (a_dec, b_dec, phi_dec)
364377
ok : bool
365378
True if conversion succeeded (Sigma_dec positive definite), else False.
379+
366380
"""
367381
sxx, syy, sxy = S_dec
368382
a_dec, b_dec, phi_dec, J, ok = sigma_to_stddevs_pa_and_jacobian(

sourcefinder/image.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,8 @@ def fit_fixed_positions(
825825
List of identifiers. If not None, must match the length and order of
826826
the requested fits.
827827
828-
Note
829-
----
828+
Notes
829+
-----
830830
boxsize is in pixel coordinates, not in sky coordinates.
831831
832832
Returns

sourcefinder/testutil/convolve.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def gaussian_from_Sigma_matrix(x, y, I0, mu, Sigma):
1111
"""
1212
Evaluate a 2D anisotropic Gaussian defined by its covariance matrix.
1313
14-
The Gaussian is given by
14+
The Gaussian is given by::
1515
1616
G(x, y) = I₀ * exp[-½ (r - μ)ᵀ Σ⁻¹ (r - μ)],
1717
@@ -59,6 +59,7 @@ def gaussian_from_Sigma_matrix(x, y, I0, mu, Sigma):
5959
>>> G = gaussian_from_Sigma_matrix(x, y, I0=1.0, mu=mu, Sigma=Sigma)
6060
>>> G.shape
6161
(101, 101)
62+
6263
"""
6364
pos = np.stack((x - mu[0], y - mu[1]), axis=0)
6465
invSigma = np.linalg.inv(Sigma)
@@ -77,11 +78,13 @@ def convolve_gaussians(I1, mu1, Sigma1, I2, mu2, Sigma2):
7778
"""
7879
Analytically convolve two 2D anisotropic Gaussian profiles.
7980
80-
The convolution of two Gaussians
81-
G₁(r) = I₁ exp[-½ (r − μ₁)ᵀ Σ₁⁻¹ (r − μ₁)]
82-
and
83-
G₂(r) = I₂ exp[-½ (r − μ₂)ᵀ Σ₂⁻¹ (r − μ₂)]
84-
yields another Gaussian with parameters:
81+
The convolution of two Gaussians::
82+
83+
G₁(r) = I₁ exp[-½ (r − μ₁)ᵀ Σ₁⁻¹ (r − μ₁)]
84+
and
85+
G₂(r) = I₂ exp[-½ (r − μ₂)ᵀ Σ₂⁻¹ (r − μ₂)]
86+
87+
yields another Gaussian with parameters::
8588
8689
Σ_H = Σ₁ + Σ₂
8790
μ_H = μ₁ + μ₂
@@ -125,8 +128,9 @@ def convolve_gaussians(I1, mu1, Sigma1, I2, mu2, Sigma2):
125128
>>> I2, mu2, Sigma2 = 1.0, np.array([0.3, -0.2]), np.diag([1.5, 0.5])
126129
>>> I_H, mu_H, Sigma_H = convolve_gaussians(I1, mu1, Sigma1, I2, mu2, Sigma2)
127130
>>> I_H, mu_H, Sigma_H
128-
(0.707..., array([ 0.3, -0.2]), array([[3.5, 0. ],
129-
[0. , 1.5]]))
131+
(0.707..., array([ 0.3, -0.2]), array([[3.5, 0.],
132+
[0., 1.5]]))
133+
130134
"""
131135
Sigma_H = Sigma1 + Sigma2
132136
mu_H = mu1 + mu2
@@ -148,8 +152,7 @@ def convolve_gaussians(I1, mu1, Sigma1, I2, mu2, Sigma2):
148152
def params_from_sigma(Sigma):
149153
"""
150154
From covariance matrix Sigma (2x2) return (sigma_maj, sigma_min,
151-
theta) with
152-
sigma_maj>=sigma_min>=0.
155+
theta) with sigma_maj>=sigma_min>=0.
153156
154157
Parameters
155158
----------
@@ -158,15 +161,19 @@ def params_from_sigma(Sigma):
158161
ellipse. Must be symmetric.
159162
Covariance matrix elements: if sigma_maj is major axis stddev,
160163
sigma_min is minor axis stddev, and theta the position angle (CCW
161-
from +Y), then
164+
from +Y), then::
165+
162166
S = [[sxx, sxy],
163167
[sxy, syy]] = R @ [[sigma_maj^2, 0],
164168
[0, sigma_min^2]] @ R.T
165-
where R = [[-sin(theta), -cos(theta)],
166-
[ cos(theta), -sin(theta)]]
167-
i.e. sxx = sigma_maj^2 sin^2(theta) + sigma_min^2 cos^2(theta)
168-
syy = sigma_maj^2 cos^2(theta) + sigma_min^2 sin^2(theta)
169-
sxy = -(sigma_maj^2 - sigma_min^2) sin(theta) cos(theta)
169+
170+
where R = [[-sin(theta), -cos(theta)],
171+
[ cos(theta), -sin(theta)]]
172+
173+
i.e. sxx = sigma_maj^2 sin^2(theta) + sigma_min^2 cos^2(theta)
174+
syy = sigma_maj^2 cos^2(theta) + sigma_min^2 sin^2(theta)
175+
sxy = -(sigma_maj^2 - sigma_min^2) sin(theta) cos(theta)
176+
170177
Returns
171178
-------
172179
sigma_maj : float
@@ -176,6 +183,7 @@ def params_from_sigma(Sigma):
176183
theta : float
177184
Position angle of the major axis in radians, in [0, pi).
178185
Measured from the positive y-axis toward the negative-axis.
186+
179187
Notes
180188
-----
181189
- The covariance matrix Sigma is related to the ellipse parameters
@@ -184,6 +192,7 @@ def params_from_sigma(Sigma):
184192
eigenvalues of Sigma.
185193
- The position angle theta is derived from the eigenvector
186194
corresponding to the largest eigenvalue.
195+
187196
"""
188197
# Symmetrize for numerical safety
189198
S = 0.5 * (Sigma + Sigma.T)

sourcefinder/utility/cli.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,19 @@ def construct_argument_parser():
160160
"--structuring-element",
161161
type=ast.literal_eval,
162162
help="""
163-
Structuring element for morphological operations, provided as a Python-style nested list (e.g. '[[1,1,1],[1,1,1],[1,1,1]]').
164-
This is used for defining the connectivity in source detection.
163+
Structuring element for morphological operations, provided as a
164+
Python-style nested list, e.g. '[[1,1,1], [1,1,1], [1,1,1]]' for
165+
8-connectivity and '[[0,1,0], [1,1,1], [0,1,0]]' for 4-connectivity.
166+
This is used for defining the connectivity in connected-component
167+
labelling.
165168
""",
166169
)
167170

168171
image_group.add_argument(
169172
"--vectorized",
170173
action="store_true",
171-
help="Use vectorized operations where applicable.",
174+
help="Measure sources vectorized, this implies using 'tweaked "
175+
"moments' instead of Gaussian fits.",
172176
)
173177

174178
image_group.add_argument(

sourcefinder/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,8 @@ def complement_gaussian_args(initial_params, fixed_params, fit_params):
722722
either a fixed value or an initial value from `initial_params`.
723723
len(gaussian_args) == 6.
724724
725-
Example
726-
-------
725+
Examples
726+
--------
727727
>>> initial_parms = np.array([1.0, 4.0, 5.0, 6.0])
728728
>>> fixed_parms = {'center_x': 2.5, 'center_y': 3.5}
729729
>>> fit_parms = ('peak', 'center_x', 'center_y', 'semi-major axis',

0 commit comments

Comments
 (0)