asp-plot 1.12.1__tar.gz → 1.14.0__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.
- {asp_plot-1.12.1 → asp_plot-1.14.0}/.gitignore +1 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/CHANGELOG.md +37 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/PKG-INFO +1 -1
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/alignment.py +108 -2
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/altimetry.py +918 -191
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/cli/asp_plot.py +273 -2
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/report.py +246 -35
- {asp_plot-1.12.1 → asp_plot-1.14.0}/pyproject.toml +1 -1
- {asp_plot-1.12.1 → asp_plot-1.14.0}/.flake8 +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/.github/workflows/release.yml +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/.github/workflows/run-tests.yml +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/.pre-commit-config.yaml +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/.readthedocs.yaml +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/LICENSE +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/README.md +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/__init__.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/bundle_adjust.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/cli/__init__.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/cli/csm_camera_plot.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/cli/request_planetary_altimetry.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/cli/stereo_geom.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/csm_camera.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/processing_parameters.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/scenes.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/stereo.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/stereo_geometry.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/stereopair_metadata_parser.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/asp_plot/utils.py +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/conda-forge-recipe/meta.yaml +0 -0
- {asp_plot-1.12.1 → asp_plot-1.14.0}/environment.yml +0 -0
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.14.0] - 2026-04-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Automatic `pc_align` step in the planetary altimetry block** ([#119](https://github.com/uw-cryo/asp_plot/pull/119)). The existing `--pc_align` CLI flag now also runs against MOLA (Mars) and LOLA (Moon) — previously Earth/ICESat-2 only. Mirrors the Earth pipeline: a single alignment-report page on `insufficient_points` / `no_improvement`, plus a pre/post mapview and pre/post histogram on `success`.
|
|
12
|
+
- **`Altimetry.align_and_evaluate_planetary(...)`**: planetary sibling of `align_and_evaluate`. Returns the same `AlignmentResult` dataclass; defaults `max_displacement=500` m (per ASAP-Stereo's CTX cookbook) and `minimum_points=20` (planetary tracks are sparse).
|
|
13
|
+
- **`Alignment.pc_align_dem_to_planetary_csv(...)`**: invokes ASP `pc_align` with `--csv-format '1:lon 2:lat 3:radius_m'` and `--datum D_MARS`/`D_MOON` (aligned with the [ASP `next_steps` documentation on MOLA alignment](https://stereopipeline.readthedocs.io/en/latest/next_steps.html)).
|
|
14
|
+
- **`Altimetry.to_csv_for_pc_align_planetary()`**: writes `lon, lat, radius_m` from `self.planetary_points` to drive `pc_align`.
|
|
15
|
+
- **`plot_aligned` kwarg** on `Altimetry.mapview_plot_planetary_to_dem` and `Altimetry.histogram_planetary_to_dem`: pre/post panels share color/bin scales when an aligned DEM is available.
|
|
16
|
+
- **Module-level constants** `MARS_IAU_SPHERE_RADIUS = 3_396_190.0` and `MOON_IAU_SPHERE_RADIUS = 1_737_400.0` so callers can reconstruct ASP-style "height above sphere" without magic numbers.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **MOLA loader switched to `PLANET_RAD`**. `_load_mola_csv()` now reads the absolute planetary radius from the ODE GDS `*_pts_csv.csv` and computes `height = PLANET_RAD - 3,396,190` (IAU 2000 Mars sphere). The `*_topo_csv.csv` (TOPOGRAPHY only) is **rejected** with an explanatory error: TOPOGRAPHY is referenced to the **oblate** MOLA areoid while ASP DEMs use the **spherical** IAU 2000 datum, so dh from TOPOGRAPHY carries a latitude-dependent offset of up to ~10 km that `pc_align` cannot remove. Verified on the MOC NA tutorial scene at lat 34°N: signed median dh dropped from +6,000 m (TOPOGRAPHY path) → +99.74 m (PLANET_RAD path) → +3.13 m (after `pc_align`). Reference: [MOLA PEDR Software Interface Specification (PDS Geosciences)](https://pds-geosciences.wustl.edu/mgs/mgs-m-mola-3-pedr-l1a-v1/mgsl_21xx/document/pedrsis.pdf).
|
|
20
|
+
- **LOLA loader prefers `Pt_Radius` (km) when available**. The Point per Row LOLA RDR CSV (`results=p`) carries `Pt_Radius` in **kilometers**; the simple Topography CSV (`results=u`) carries Topography in meters. `_load_lola_csv()` auto-detects km by magnitude (< 10 000) and converts to meters, then writes both `height` (m above the IAU 1737.4 km lunar sphere) and `radius_m` to `self.planetary_points`. The Moon is essentially spherical (~1.4 km equatorial-vs-polar variation), so either CSV gives the same dh to ~1 m. Reference: [ODE GDS REST V2.0 manual](https://oderest.rsl.wustl.edu/GDS_REST_V2.0.pdf).
|
|
21
|
+
- **`Alignment.apply_dem_translation()` is body-aware**. Picks a body-centered geocentric "ECEF-equivalent" CRS from a new module-level `_GEOCENTRIC_PROJ` dict — Earth uses `EPSG:4978`; Mars/Moon use PROJ strings (`+proj=geocent +R=...`) because PROJ refuses to convert across celestial bodies. Without this fix, applying a `pc_align` translation to a Mars/Moon DEM raised `RuntimeError: Source and target ellipsoid do not belong to the same celestial body`.
|
|
22
|
+
- **`planetary_to_dem_dh()` also samples the aligned DEM** when `self.aligned_dem_fn` is set, populating `aligned_dem_height` and `altimetry_minus_aligned_dem` so pre/post plots share a single sample. Refactored shared interpolation into `_sample_dem_at_planetary_points()`.
|
|
23
|
+
|
|
24
|
+
### Documentation
|
|
25
|
+
- **MOC NA notebook consolidated** into `notebooks/Mars_MGS/mars_mgs_orbital_camera.ipynb` covering both stereo variants of the M0100115 / E0201461 pair (the `mars_mgs_orbital_camera_narrow_angle.ipynb` notebook for a different scene pair was removed). Mirrors the ASTER mapproj/non-mapproj layout. Stereo commands match this repo's WorldView convention (`parallel_stereo --stereo-algorithm asp_mgm --subpixel-mode 9 --processes 2 --threads 4`, `--alignment-method affineepipolar` for non-mapprojected, `--alignment-method none` for mapprojected via `cam2map4stereo.py`). The notebook intro includes a callout explaining the spherical-vs-oblate elevation-range surprise. Reports: `MOC-asp-plot-report.pdf` and `MOC_mapproj-asp-plot-report.pdf`.
|
|
26
|
+
- **LRO NAC notebook reprocessed on the full 5000×5000 cubes** in [`LRONAC_example.tar`](https://github.com/NeoGeographyToolkit/StereoPipelineSolvedExamples/releases/download/LRONAC/LRONAC_example.tar) instead of the 900×973 sub-window the ASP "lightning fast" tutorial uses. Resulting DEM is 4720×4510 at 1.04 m GSD (~4.7 km × 4.7 km, vs the old ~1 km × 1 km), 95.88% valid pixels. LOLA query expanded to match: 1539 of 2044 LOLA points overlap the DEM (vs 12 of 19 on the old crop), enough for a meaningful `pc_align` and to bring out spacecraft jitter in the disparity panels.
|
|
27
|
+
|
|
28
|
+
## [1.13.0] - 2026-04-20
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Automatic `pc_align` step in the Earth altimetry block**, gated by a new `--pc_align` CLI flag (default `True`; disabled automatically when `--plot_altimetry` / `--plot_icesat` is `False`). Runs `pc_align` against ICESat-2 ATL06-SR, evaluates whether the aligned DEM is worth keeping, and appends the outcome as one or more report pages:
|
|
32
|
+
- Always: an **alignment report page** with the parameters table, a single-row horizontal stats table (p16/p50/p84 beg/end, north/east/down shifts, translation magnitude, values to 2 sig figs), a description explaining what `pc_align` does and the meaning of every column in the tables above, and a bold status line for the outcome of this run.
|
|
33
|
+
- On success (p50 drops toward 0 by more than `improvement_threshold_pct`, default 5%, **and** `pc_align` actually wrote an aligned DEM): three additional full-page diagnostic figures against the aligned DEM — a pre-/post-alignment landcover histogram, the full profile, and the best/worst 1 km segments.
|
|
34
|
+
- On insufficient ATL06-SR coverage or no meaningful improvement: the aligned DEM on disk is cleaned up so its presence is a truthy signal that the alignment is worth using.
|
|
35
|
+
- **`Altimetry.align_and_evaluate(...)`** (new method) returning a plain `AlignmentResult` dataclass (`status ∈ {"insufficient_points", "no_improvement", "success"}`, `alignment_report_df`, `aligned_dem_fn`, `improvement_pct`, `message`, `parameters_used`). Does not import any `fpdf` / report dependencies, so it is safe to call from notebooks.
|
|
36
|
+
- **`plot_aligned` kwargs** on `Altimetry.histogram_by_landcover` and `Altimetry.plot_best_worst_segments`:
|
|
37
|
+
- `histogram_by_landcover(plot_aligned=True)` overlays the pre- and post-alignment distributions using shared bin edges and renders two vertically stacked per-landcover stats text boxes whose outline colors match the bar colors (color = legend).
|
|
38
|
+
- `plot_best_worst_segments(plot_aligned=True)` keeps segment selection fixed (based on the unaligned `dh` so segments are comparable), overlays aligned DEM heights on each segment, and appends aligned Median/NMAD to the segment titles.
|
|
39
|
+
- **`AlignmentReportPage`** dataclass in `asp_plot.report`: a report-section type that renders a kwargs table + single-row stats table + description + bold status line + optional figure with caption. Body text blocks render left-aligned to avoid justified word-spacing gaps.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
- **Processing Parameters is now page 2 of the PDF**, immediately after the DEM Summary on the title page, instead of the trailing appendix. Page order is now: title + DEM summary → processing parameters → diagnostic figures → (if any) alignment results.
|
|
43
|
+
- **`plot_atl06sr_dem_profile(plot_aligned=True)`**: the lower `dh` panel now plots the post-alignment residuals (`icesat_minus_aligned_dem`) with Med/NMAD recomputed against the aligned DEM, with the legend entry tagged `"(Aligned DEM)"`. The upper elevation panel still overlays both the unaligned and aligned DEM for comparison. `plot_aligned=False` behavior is unchanged.
|
|
44
|
+
|
|
8
45
|
## [1.12.1] - 2026-04-14
|
|
9
46
|
|
|
10
47
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: asp_plot
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.0
|
|
4
4
|
Summary: Package for plotting outputs Ames Stereo Pipeline processing
|
|
5
5
|
Project-URL: Homepage, https://github.com/uw-cryo/asp_plot
|
|
6
6
|
Project-URL: Documentation, https://asp-plot.readthedocs.io
|
|
@@ -5,7 +5,23 @@ import re
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from osgeo import gdal, osr
|
|
7
7
|
|
|
8
|
-
from asp_plot.utils import
|
|
8
|
+
from asp_plot.utils import (
|
|
9
|
+
Raster,
|
|
10
|
+
detect_planetary_body,
|
|
11
|
+
glob_file,
|
|
12
|
+
run_subprocess_command,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Body-centered geocentric ("ECEF-equivalent") CRS for each supported
|
|
16
|
+
# planet. Used by apply_dem_translation to convert pc_align's Cartesian
|
|
17
|
+
# translation vector into the DEM's projected coordinate system. The
|
|
18
|
+
# Earth case is keyed via EPSG; planets need a PROJ string because PROJ
|
|
19
|
+
# refuses to operate across celestial bodies.
|
|
20
|
+
_GEOCENTRIC_PROJ = {
|
|
21
|
+
"earth": None, # use EPSG:4978
|
|
22
|
+
"moon": "+proj=geocent +R=1737400 +units=m +no_defs",
|
|
23
|
+
"mars": "+proj=geocent +R=3396190 +units=m +no_defs",
|
|
24
|
+
}
|
|
9
25
|
|
|
10
26
|
logging.basicConfig(level=logging.WARNING)
|
|
11
27
|
logger = logging.getLogger(__name__)
|
|
@@ -134,6 +150,86 @@ class Alignment:
|
|
|
134
150
|
|
|
135
151
|
run_subprocess_command(command)
|
|
136
152
|
|
|
153
|
+
def pc_align_dem_to_planetary_csv(
|
|
154
|
+
self,
|
|
155
|
+
planetary_csv,
|
|
156
|
+
body,
|
|
157
|
+
max_displacement=500,
|
|
158
|
+
max_source_points=10000000,
|
|
159
|
+
alignment_method="point-to-point",
|
|
160
|
+
output_prefix="pc_align/pc_align",
|
|
161
|
+
):
|
|
162
|
+
"""
|
|
163
|
+
Align DEM to MOLA/LOLA point cloud using pc_align.
|
|
164
|
+
|
|
165
|
+
Parameters
|
|
166
|
+
----------
|
|
167
|
+
planetary_csv : str
|
|
168
|
+
Path to a CSV with ``lon``, ``lat``, ``radius_m`` columns
|
|
169
|
+
(planetary radius in meters from the body center). Produced by
|
|
170
|
+
:meth:`asp_plot.altimetry.Altimetry.to_csv_for_pc_align_planetary`.
|
|
171
|
+
body : str
|
|
172
|
+
``"moon"`` or ``"mars"`` — selects the ASP ``--datum`` flag.
|
|
173
|
+
max_displacement : float, optional
|
|
174
|
+
Maximum expected displacement in meters. ASAP-Stereo's CTX
|
|
175
|
+
cookbook recommends ~500 m as a generic default for planetary
|
|
176
|
+
stereo where absolute pointing is uncertain.
|
|
177
|
+
max_source_points : int, optional
|
|
178
|
+
Maximum number of source DEM points pc_align will sample.
|
|
179
|
+
alignment_method : str, optional
|
|
180
|
+
ASP alignment method. Default ``point-to-point``.
|
|
181
|
+
output_prefix : str, optional
|
|
182
|
+
Prefix for pc_align output files, relative to ``self.directory``.
|
|
183
|
+
|
|
184
|
+
Notes
|
|
185
|
+
-----
|
|
186
|
+
Uses ``--csv-format '1:lon 2:lat 3:radius_m'`` so pc_align reads
|
|
187
|
+
the absolute planetary radius and avoids any datum/areoid
|
|
188
|
+
ambiguity. ``--datum`` is set to ``D_MARS`` (3,396,190 m) or
|
|
189
|
+
``D_MOON`` (1,737,400 m) to match ASP DEM heights, which are
|
|
190
|
+
stored as ``radius - sphere``.
|
|
191
|
+
"""
|
|
192
|
+
if not os.path.exists(planetary_csv):
|
|
193
|
+
raise ValueError(
|
|
194
|
+
f"\nPlanetary altimetry CSV not found: {planetary_csv}\n"
|
|
195
|
+
"Use Altimetry.to_csv_for_pc_align_planetary() to create it.\n"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
datum = {"moon": "D_MOON", "mars": "D_MARS"}.get(body)
|
|
199
|
+
if datum is None:
|
|
200
|
+
raise ValueError(
|
|
201
|
+
f"Unsupported body for pc_align_dem_to_planetary_csv: {body}"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
pc_align_folder = os.path.join(self.directory, output_prefix)
|
|
205
|
+
|
|
206
|
+
print(
|
|
207
|
+
f"Running pc_align on {self.dem_fn} and {planetary_csv}\n"
|
|
208
|
+
f" --datum {datum}, --max-displacement {max_displacement}\n"
|
|
209
|
+
f"Writing to {pc_align_folder}*"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
command = [
|
|
213
|
+
"pc_align",
|
|
214
|
+
"--max-displacement",
|
|
215
|
+
str(max_displacement),
|
|
216
|
+
"--max-num-source-points",
|
|
217
|
+
str(max_source_points),
|
|
218
|
+
"--alignment-method",
|
|
219
|
+
alignment_method,
|
|
220
|
+
"--csv-format",
|
|
221
|
+
"1:lon 2:lat 3:radius_m",
|
|
222
|
+
"--datum",
|
|
223
|
+
datum,
|
|
224
|
+
"--compute-translation-only",
|
|
225
|
+
"--output-prefix",
|
|
226
|
+
pc_align_folder,
|
|
227
|
+
self.dem_fn,
|
|
228
|
+
planetary_csv,
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
run_subprocess_command(command)
|
|
232
|
+
|
|
137
233
|
def pc_align_report(self, output_prefix="pc_align/pc_align"):
|
|
138
234
|
"""
|
|
139
235
|
Extract alignment statistics from pc_align log files.
|
|
@@ -281,8 +377,18 @@ class Alignment:
|
|
|
281
377
|
llz_c = llz_c[i]
|
|
282
378
|
llz_shift = llz_shift[i]
|
|
283
379
|
|
|
380
|
+
# pc_align's Cartesian translation lives in the body-centered
|
|
381
|
+
# frame defined by --datum, so the source CRS must match the
|
|
382
|
+
# body of the DEM. PROJ refuses to convert between celestial
|
|
383
|
+
# bodies, so use a body-specific geocentric PROJ string for
|
|
384
|
+
# Mars/Moon and EPSG:4978 for Earth.
|
|
385
|
+
body = detect_planetary_body(self.dem_fn)
|
|
284
386
|
ecef_srs = osr.SpatialReference()
|
|
285
|
-
|
|
387
|
+
proj_string = _GEOCENTRIC_PROJ.get(body)
|
|
388
|
+
if proj_string is None:
|
|
389
|
+
ecef_srs.ImportFromEPSG(4978)
|
|
390
|
+
else:
|
|
391
|
+
ecef_srs.ImportFromProj4(proj_string)
|
|
286
392
|
|
|
287
393
|
s_srs = ecef_srs
|
|
288
394
|
src_c = ecef_c
|