splusdata 5.49__tar.gz → 5.51__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {splusdata-5.49/splusdata.egg-info → splusdata-5.51}/PKG-INFO +2 -2
  2. {splusdata-5.49 → splusdata-5.51}/pyproject.toml +2 -2
  3. splusdata-5.51/splusdata/features/zeropoints/zp_map.py +271 -0
  4. {splusdata-5.49 → splusdata-5.51/splusdata.egg-info}/PKG-INFO +2 -2
  5. {splusdata-5.49 → splusdata-5.51}/splusdata.egg-info/requires.txt +1 -1
  6. splusdata-5.49/splusdata/features/zeropoints/zp_map.py +0 -145
  7. {splusdata-5.49 → splusdata-5.51}/LICENSE +0 -0
  8. {splusdata-5.49 → splusdata-5.51}/README.md +0 -0
  9. {splusdata-5.49 → splusdata-5.51}/setup.cfg +0 -0
  10. {splusdata-5.49 → splusdata-5.51}/splusdata/__init__.py +0 -0
  11. {splusdata-5.49 → splusdata-5.51}/splusdata/connect.py +0 -0
  12. {splusdata-5.49 → splusdata-5.51}/splusdata/core.py +0 -0
  13. {splusdata-5.49 → splusdata-5.51}/splusdata/features/__init__.py +0 -0
  14. {splusdata-5.49 → splusdata-5.51}/splusdata/features/extinction.py +0 -0
  15. {splusdata-5.49 → splusdata-5.51}/splusdata/features/filterbw.py +0 -0
  16. {splusdata-5.49 → splusdata-5.51}/splusdata/features/find_pointings.py +0 -0
  17. {splusdata-5.49 → splusdata-5.51}/splusdata/features/hipscat.py +0 -0
  18. {splusdata-5.49 → splusdata-5.51}/splusdata/features/io.py +0 -0
  19. {splusdata-5.49 → splusdata-5.51}/splusdata/features/zeropoints/__init__.py +0 -0
  20. {splusdata-5.49 → splusdata-5.51}/splusdata/features/zeropoints/zp_image.py +0 -0
  21. {splusdata-5.49 → splusdata-5.51}/splusdata/features/zeropointsdr4.py +0 -0
  22. {splusdata-5.49 → splusdata-5.51}/splusdata/models/__init__.py +0 -0
  23. {splusdata-5.49 → splusdata-5.51}/splusdata/models/star_gal_quasar.py +0 -0
  24. {splusdata-5.49 → splusdata-5.51}/splusdata/readconf.py +0 -0
  25. {splusdata-5.49 → splusdata-5.51}/splusdata/scripts/args.py +0 -0
  26. {splusdata-5.49 → splusdata-5.51}/splusdata/scripts/utils.py +0 -0
  27. {splusdata-5.49 → splusdata-5.51}/splusdata/scubes/__init__.py +0 -0
  28. {splusdata-5.49 → splusdata-5.51}/splusdata/scubes/core.py +0 -0
  29. {splusdata-5.49 → splusdata-5.51}/splusdata/scubes/read.py +0 -0
  30. {splusdata-5.49 → splusdata-5.51}/splusdata/scubes/scripts.py +0 -0
  31. {splusdata-5.49 → splusdata-5.51}/splusdata/vacs/__init__.py +0 -0
  32. {splusdata-5.49 → splusdata-5.51}/splusdata/vacs/pdfs.py +0 -0
  33. {splusdata-5.49 → splusdata-5.51}/splusdata/vacs/sqg.py +0 -0
  34. {splusdata-5.49 → splusdata-5.51}/splusdata/variability/__init__.py +0 -0
  35. {splusdata-5.49 → splusdata-5.51}/splusdata/vars.py +0 -0
  36. {splusdata-5.49 → splusdata-5.51}/splusdata.egg-info/SOURCES.txt +0 -0
  37. {splusdata-5.49 → splusdata-5.51}/splusdata.egg-info/dependency_links.txt +0 -0
  38. {splusdata-5.49 → splusdata-5.51}/splusdata.egg-info/entry_points.txt +0 -0
  39. {splusdata-5.49 → splusdata-5.51}/splusdata.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splusdata
3
- Version: 5.49
3
+ Version: 5.51
4
4
  Summary: Download SPLUS catalogs, FITS and more
5
5
  Author-email: Gustavo Schwarz <gustavo.b.schwarz@gmail.com>
6
6
  License: Apache-2.0
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: Apache Software License
10
10
  Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: adss>=1.36
13
+ Requires-Dist: adss>=1.38
14
14
  Requires-Dist: requests
15
15
  Requires-Dist: astropy
16
16
  Requires-Dist: astroquery
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "splusdata"
7
- version = "5.49"
7
+ version = "5.51"
8
8
  description = "Download SPLUS catalogs, FITS and more"
9
9
  authors = [
10
10
  { name = "Gustavo Schwarz", email = "gustavo.b.schwarz@gmail.com" }
@@ -18,7 +18,7 @@ classifiers = [
18
18
  "License :: OSI Approved :: Apache Software License"
19
19
  ]
20
20
  dependencies = [
21
- "adss>=1.36",
21
+ "adss>=1.38",
22
22
  "requests",
23
23
  "astropy",
24
24
  "astroquery",
@@ -0,0 +1,271 @@
1
+ from scipy.interpolate import RegularGridInterpolator
2
+ import numpy as np
3
+
4
+ import numpy as np
5
+ import warnings
6
+ from scipy.interpolate import RegularGridInterpolator
7
+
8
+ def _reconstruct_centers_from_model(model, axis="ra", grid_len=None):
9
+ """
10
+ Rebuild centers to match the (possibly padded) grid length using the model's
11
+ ra_min/ra_max/dec_min/dec_max, bins, and padding.
12
+
13
+ The model saved edges with length `bins`, which yields B = bins-1 actual bins
14
+ before padding. After padding, the grid dimension is B + 2*padding.
15
+ Centers are midpoints of each (possibly padded) bin.
16
+
17
+ Parameters
18
+ ----------
19
+ model : dict
20
+ axis : str
21
+ "ra" or "dec"
22
+ grid_len : int
23
+ Target number of centers (should equal grid.shape[dim])
24
+
25
+ Returns
26
+ -------
27
+ np.ndarray
28
+ """
29
+ assert axis in ("ra", "dec")
30
+ amin = model[f"{axis}_min"]
31
+ amax = model[f"{axis}_max"]
32
+ bins = int(model.get("bins", 15))
33
+ padding = int(model.get("padding", 1))
34
+
35
+ # B is the number of *actual* bins before padding (because edges length = bins)
36
+ B = bins - 1
37
+ if B <= 0:
38
+ raise ValueError(f"Invalid bins in model: bins={bins}")
39
+
40
+ # native bin width (pre-padding)
41
+ dA = (amax - amin) / B
42
+
43
+ # original centers (length B)
44
+ centers_core = amin + (np.arange(B) + 0.5) * dA
45
+
46
+ # padded centers: extend by `padding` bins on both sides at same spacing
47
+ if padding > 0:
48
+ left = centers_core[0] - dA * np.arange(padding, 0, -1)
49
+ right = centers_core[-1] + dA * np.arange(1, padding + 1)
50
+ centers = np.concatenate([left, centers_core, right])
51
+ else:
52
+ centers = centers_core
53
+
54
+ if grid_len is not None and len(centers) != grid_len:
55
+ # If still mismatched, resample linearly across the padded span as a last resort.
56
+ warnings.warn(
57
+ f"{axis.upper()} centers length ({len(centers)}) != grid axis length ({grid_len}). "
58
+ "Resampling centers to match grid shape."
59
+ )
60
+ # Rebuild centers uniformly across the total span of the padded grid:
61
+ total_span = (amax - amin) + 2 * padding * dA
62
+ a_min_padded = amin - padding * dA
63
+ centers = a_min_padded + (np.arange(grid_len) + 0.5) * (total_span / grid_len)
64
+
65
+ return centers
66
+
67
+ def zp_at_coord(model, ra, dec, margin=0.1):
68
+ """
69
+ Get zero-point correction(s) for coordinate(s).
70
+
71
+ Accepts:
72
+ - ra: float or array-like
73
+ - dec: float or array-like
74
+
75
+ Supports broadcasting:
76
+ - scalar ra with array dec
77
+ - array ra with scalar dec
78
+ - array ra with array dec (same shape or broadcastable)
79
+
80
+ Returns:
81
+ - float if both inputs are scalar
82
+ - np.ndarray otherwise
83
+
84
+ Notes:
85
+ - Keeps your original behavior: if ANY point is out of bounds (with margin)
86
+ or interpolation yields NaN, it raises Exception (instead of partial fill).
87
+ """
88
+ global_median = float(model.get("global_median", 0.0))
89
+
90
+ # If no grid info, fallback
91
+ if not ("grid" in model and "ra_centers" in model and "dec_centers" in model):
92
+ if np.isscalar(ra) and np.isscalar(dec):
93
+ return global_median
94
+ ra_arr = np.asarray(ra, dtype=float)
95
+ dec_arr = np.asarray(dec, dtype=float)
96
+ ra_b, dec_b = np.broadcast_arrays(ra_arr, dec_arr)
97
+ return np.full(ra_b.shape, global_median, dtype=float)
98
+
99
+ # Load saved arrays
100
+ grid = np.asarray(model["grid"], dtype=float)
101
+ ra_centers = np.asarray(model.get("ra_centers", []), dtype=float)
102
+ dec_centers = np.asarray(model.get("dec_centers", []), dtype=float)
103
+
104
+ # Rebuild centers if needed (mismatch / empty)
105
+ need_rebuild = (
106
+ ra_centers.size == 0 or
107
+ dec_centers.size == 0 or
108
+ grid.ndim != 2 or
109
+ grid.shape[0] != ra_centers.size or
110
+ grid.shape[1] != dec_centers.size
111
+ )
112
+ if need_rebuild:
113
+ ra_centers = _reconstruct_centers_from_model(model, "ra", grid_len=grid.shape[0])
114
+ dec_centers = _reconstruct_centers_from_model(model, "dec", grid_len=grid.shape[1])
115
+
116
+ # Normalize inputs + broadcast
117
+ ra_is_scalar = np.isscalar(ra)
118
+ dec_is_scalar = np.isscalar(dec)
119
+
120
+ ra_arr = np.asarray(ra, dtype=float)
121
+ dec_arr = np.asarray(dec, dtype=float)
122
+ ra_b, dec_b = np.broadcast_arrays(ra_arr, dec_arr)
123
+
124
+ # Vectorized bounds check
125
+ ra_min, ra_max = float(np.min(ra_centers)), float(np.max(ra_centers))
126
+ dec_min, dec_max = float(np.min(dec_centers)), float(np.max(dec_centers))
127
+
128
+ in_bounds = (
129
+ (ra_b >= (ra_min - margin)) & (ra_b <= (ra_max + margin)) &
130
+ (dec_b >= (dec_min - margin)) & (dec_b <= (dec_max + margin))
131
+ )
132
+
133
+ if not np.all(in_bounds):
134
+ bad = np.argwhere(~in_bounds)
135
+ i0 = tuple(bad[0]) # first offending index
136
+ warnings.warn(
137
+ f"Some coordinates are outside the grid range RA=[{ra_min:.3f}, {ra_max:.3f}] "
138
+ f"Dec=[{dec_min:.3f}, {dec_max:.3f}] (margin={margin:.3f}). "
139
+ f"Example at index {i0}: (RA={ra_b[i0]:.3f}, Dec={dec_b[i0]:.3f}). "
140
+ "Falling back to global median (raising exception, per original behavior)."
141
+ )
142
+ raise Exception("Some coordinates are outside the grid range.")
143
+
144
+ # Build interpolator once
145
+ interpolator = RegularGridInterpolator(
146
+ (ra_centers, dec_centers),
147
+ grid,
148
+ bounds_error=False,
149
+ fill_value=np.nan,
150
+ )
151
+
152
+ # Interpolate all points
153
+ pts = np.column_stack([ra_b.ravel(), dec_b.ravel()]) # (N, 2)
154
+ zp = interpolator(pts).reshape(ra_b.shape)
155
+
156
+ if np.any(np.isnan(zp)):
157
+ bad = np.argwhere(np.isnan(zp))
158
+ i0 = tuple(bad[0])
159
+ warnings.warn(
160
+ f"Interpolation failed (NaN) for some coordinates. "
161
+ f"Example at index {i0}: (RA={ra_b[i0]:.3f}, Dec={dec_b[i0]:.3f}). "
162
+ "Returning global median (raising exception, per original behavior)."
163
+ )
164
+ raise Exception("Interpolation failed (NaN) for some coordinates.")
165
+
166
+ out = zp + global_median
167
+
168
+ # Return scalar if scalar inputs
169
+ if ra_is_scalar and dec_is_scalar:
170
+ return float(out)
171
+
172
+ return out
173
+ """
174
+ Vectorized zero-point correction lookup.
175
+
176
+ Accepts:
177
+ - ra: float or array-like
178
+ - dec: float or array-like
179
+ Supports broadcasting:
180
+ - ra scalar + dec array
181
+ - ra array + dec scalar
182
+ - ra array + dec array (same shape or broadcastable)
183
+
184
+ Returns:
185
+ - float if both inputs are scalar (and return_scalar_if_scalar=True)
186
+ - np.ndarray otherwise
187
+ """
188
+ global_median = float(model.get("global_median", 0.0))
189
+
190
+ # If no grid, always fallback
191
+ if not ("grid" in model and ("ra_centers" in model or True) and ("dec_centers" in model or True)):
192
+ # keep original behavior: return global median only
193
+ if np.isscalar(ra) and np.isscalar(dec) and return_scalar_if_scalar:
194
+ return global_median
195
+ ra_arr = np.asarray(ra, dtype=float)
196
+ dec_arr = np.asarray(dec, dtype=float)
197
+ ra_b, dec_b = np.broadcast_arrays(ra_arr, dec_arr)
198
+ return np.full(ra_b.shape, global_median, dtype=float)
199
+
200
+ # Load arrays
201
+ grid = np.asarray(model["grid"], dtype=float)
202
+ ra_centers = np.asarray(model.get("ra_centers", []), dtype=float)
203
+ dec_centers = np.asarray(model.get("dec_centers", []), dtype=float)
204
+
205
+ # Rebuild centers if needed
206
+ need_rebuild = (
207
+ ra_centers.size == 0 or
208
+ dec_centers.size == 0 or
209
+ grid.ndim != 2 or
210
+ grid.shape[0] != ra_centers.size or
211
+ grid.shape[1] != dec_centers.size
212
+ )
213
+ if need_rebuild:
214
+ ra_centers = _reconstruct_centers_from_model(model, "ra", grid_len=grid.shape[0])
215
+ dec_centers = _reconstruct_centers_from_model(model, "dec", grid_len=grid.shape[1])
216
+
217
+ # Interpolator (build once)
218
+ interpolator = RegularGridInterpolator(
219
+ (ra_centers, dec_centers),
220
+ grid,
221
+ bounds_error=False,
222
+ fill_value=np.nan,
223
+ )
224
+
225
+ # Normalize inputs to arrays + broadcast
226
+ ra_is_scalar = np.isscalar(ra)
227
+ dec_is_scalar = np.isscalar(dec)
228
+
229
+ ra_arr = np.asarray(ra, dtype=float)
230
+ dec_arr = np.asarray(dec, dtype=float)
231
+ ra_b, dec_b = np.broadcast_arrays(ra_arr, dec_arr)
232
+
233
+ # Bounds check (vectorized) with margin
234
+ ra_min, ra_max = float(np.min(ra_centers)), float(np.max(ra_centers))
235
+ dec_min, dec_max = float(np.min(dec_centers)), float(np.max(dec_centers))
236
+
237
+ in_bounds = (
238
+ (ra_b >= (ra_min - margin)) & (ra_b <= (ra_max + margin)) &
239
+ (dec_b >= (dec_min - margin)) & (dec_b <= (dec_max + margin))
240
+ )
241
+
242
+ if not np.all(in_bounds):
243
+ bad = np.argwhere(~in_bounds)
244
+ i0 = tuple(bad[0]) # first offending index
245
+ warnings.warn(
246
+ f"Some coordinates are outside the grid range (margin={margin} deg). "
247
+ f"Example at index {i0}: (RA={ra_b[i0]:.3f}, Dec={dec_b[i0]:.3f}) "
248
+ f"outside RA=[{ra_min:.3f}, {ra_max:.3f}], Dec=[{dec_min:.3f}, {dec_max:.3f}]."
249
+ )
250
+ raise Exception("Some coordinates are outside the grid range.")
251
+
252
+ # Evaluate interpolation for all points
253
+ pts = np.column_stack([ra_b.ravel(), dec_b.ravel()]) # shape (N, 2)
254
+ zp = interpolator(pts).reshape(ra_b.shape)
255
+
256
+ if np.any(np.isnan(zp)):
257
+ bad = np.argwhere(np.isnan(zp))
258
+ i0 = tuple(bad[0])
259
+ warnings.warn(
260
+ f"Interpolation returned NaN for some points. "
261
+ f"Example at index {i0}: (RA={ra_b[i0]:.3f}, Dec={dec_b[i0]:.3f})."
262
+ )
263
+ raise Exception("Interpolation failed (NaN) for some points.")
264
+
265
+ zp = zp + global_median
266
+
267
+ # Return float if scalar inputs
268
+ if return_scalar_if_scalar and ra_is_scalar and dec_is_scalar:
269
+ return float(zp)
270
+
271
+ return zp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splusdata
3
- Version: 5.49
3
+ Version: 5.51
4
4
  Summary: Download SPLUS catalogs, FITS and more
5
5
  Author-email: Gustavo Schwarz <gustavo.b.schwarz@gmail.com>
6
6
  License: Apache-2.0
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: Apache Software License
10
10
  Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: adss>=1.36
13
+ Requires-Dist: adss>=1.38
14
14
  Requires-Dist: requests
15
15
  Requires-Dist: astropy
16
16
  Requires-Dist: astroquery
@@ -1,4 +1,4 @@
1
- adss>=1.36
1
+ adss>=1.38
2
2
  requests
3
3
  astropy
4
4
  astroquery
@@ -1,145 +0,0 @@
1
- from scipy.interpolate import RegularGridInterpolator
2
- import numpy as np
3
-
4
- import numpy as np
5
- import warnings
6
- from scipy.interpolate import RegularGridInterpolator
7
-
8
- def _reconstruct_centers_from_model(model, axis="ra", grid_len=None):
9
- """
10
- Rebuild centers to match the (possibly padded) grid length using the model's
11
- ra_min/ra_max/dec_min/dec_max, bins, and padding.
12
-
13
- The model saved edges with length `bins`, which yields B = bins-1 actual bins
14
- before padding. After padding, the grid dimension is B + 2*padding.
15
- Centers are midpoints of each (possibly padded) bin.
16
-
17
- Parameters
18
- ----------
19
- model : dict
20
- axis : str
21
- "ra" or "dec"
22
- grid_len : int
23
- Target number of centers (should equal grid.shape[dim])
24
-
25
- Returns
26
- -------
27
- np.ndarray
28
- """
29
- assert axis in ("ra", "dec")
30
- amin = model[f"{axis}_min"]
31
- amax = model[f"{axis}_max"]
32
- bins = int(model.get("bins", 15))
33
- padding = int(model.get("padding", 1))
34
-
35
- # B is the number of *actual* bins before padding (because edges length = bins)
36
- B = bins - 1
37
- if B <= 0:
38
- raise ValueError(f"Invalid bins in model: bins={bins}")
39
-
40
- # native bin width (pre-padding)
41
- dA = (amax - amin) / B
42
-
43
- # original centers (length B)
44
- centers_core = amin + (np.arange(B) + 0.5) * dA
45
-
46
- # padded centers: extend by `padding` bins on both sides at same spacing
47
- if padding > 0:
48
- left = centers_core[0] - dA * np.arange(padding, 0, -1)
49
- right = centers_core[-1] + dA * np.arange(1, padding + 1)
50
- centers = np.concatenate([left, centers_core, right])
51
- else:
52
- centers = centers_core
53
-
54
- if grid_len is not None and len(centers) != grid_len:
55
- # If still mismatched, resample linearly across the padded span as a last resort.
56
- warnings.warn(
57
- f"{axis.upper()} centers length ({len(centers)}) != grid axis length ({grid_len}). "
58
- "Resampling centers to match grid shape."
59
- )
60
- # Rebuild centers uniformly across the total span of the padded grid:
61
- total_span = (amax - amin) + 2 * padding * dA
62
- a_min_padded = amin - padding * dA
63
- centers = a_min_padded + (np.arange(grid_len) + 0.5) * (total_span / grid_len)
64
-
65
- return centers
66
-
67
- def zp_at_coord(model, ra, dec, margin=0.1):
68
- """
69
- Get zero-point correction for a given coordinate.
70
-
71
- Parameters
72
- ----------
73
- model : dict
74
- Zero-point calibration model loaded from JSON.
75
- ra : float
76
- Right Ascension in degrees.
77
- dec : float
78
- Declination in degrees.
79
- margin : float, optional
80
- Allowed margin (in degrees) outside the grid before warning.
81
- Default = 0.1 deg.
82
-
83
- Returns
84
- -------
85
- float
86
- Zero-point correction value (mag).
87
- """
88
- global_median = model.get("global_median", 0.0)
89
-
90
-
91
- if "grid" in model and "ra_centers" in model and "dec_centers" in model:
92
- ra_centers = np.array(model["ra_centers"])
93
- dec_centers = np.array(model["dec_centers"])
94
- grid = np.array(model["grid"])
95
-
96
- need_rebuild = (
97
- ra_centers.size == 0 or
98
- dec_centers.size == 0 or
99
- grid.shape[0] != ra_centers.size or
100
- grid.shape[1] != dec_centers.size
101
- )
102
- if need_rebuild:
103
- ra_centers = _reconstruct_centers_from_model(model, "ra", grid_len=grid.shape[0])
104
- dec_centers = _reconstruct_centers_from_model(model, "dec", grid_len=grid.shape[1])
105
-
106
-
107
- ra_min, ra_max = ra_centers.min(), ra_centers.max()
108
- dec_min, dec_max = dec_centers.min(), dec_centers.max()
109
-
110
- # Check bounds with margin
111
- if not (ra_min - margin <= ra <= ra_max + margin and
112
- dec_min - margin <= dec <= dec_max + margin):
113
- warnings.warn(
114
- f"Coordinate (RA={ra:.3f}, Dec={dec:.3f}) is outside "
115
- f"the grid range RA=[{ra_min:.3f}, {ra_max:.3f}], "
116
- f"Dec=[{dec_min:.3f}, {dec_max:.3f}]. "
117
- "Falling back to global median."
118
- )
119
- raise Exception(
120
- f"Coordinate (RA={ra}, Dec={dec}) is outside the grid range."
121
- )
122
-
123
- # Interpolator
124
- interpolator = RegularGridInterpolator(
125
- (ra_centers, dec_centers), grid,
126
- bounds_error=False,
127
- fill_value=np.nan
128
- )
129
- zp_value = interpolator([[ra, dec]])[0]
130
-
131
- # If interpolator returns NaN, fallback
132
- if np.isnan(zp_value):
133
- warnings.warn(
134
- f"Interpolation failed at (RA={ra:.3f}, Dec={dec:.3f}). "
135
- "Returning global median."
136
- )
137
- raise Exception(
138
- f"Interpolation failed at (RA={ra}, Dec={dec}). "
139
- "Falling back to global median."
140
- )
141
-
142
- return float(zp_value) + global_median
143
-
144
- # Fallback if no grid in model
145
- return global_median
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes