Dev compare - #6
Merged
Merged
Conversation
… dedupe Moffat fitting background_subtracted() could silently upcast to float64 if photutils ever returned a float64 background model; Background2D relied on photutils' internal SigmaClip default and used the now-deprecated bkgrms_estimator keyword. Camera gain resolution (EGAIN > GAIN > CCDGAIN > GAINDB) existed in two places that could disagree for the same file - the GUI metadata panel and the SNR analyzer - now unified behind one shared helper. The 2D Moffat PSF fit was duplicated between psf_analyzer.py and halo_dialog.py with drifted plausibility bounds; extracted into analysis/moffat_fit.py and migrated off the deprecated LevMarLSQFitter to TRFLSQFitter with explicit bounds. PSF_FWHM_CLIP_NSIGMA was being applied to a raw (unscaled) MAD, clipping at ~2sigma despite its name; switched to mad_std so the multiplier means what it says. Also: guarded unguarded float() header parses, deduped the pixel-scale keyword table, removed dead code, and pinned astropy>=6.0/photutils>=3.0 in requirements files. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nfigurable The nebula/background mask used throughout Section 8 (Spatial Detail Analysis) was a hardcoded 2sigma cut with no way to capture dim/dark transition regions at nebula edges. Adds three GUI-configurable parameters (default 1.7sigma threshold, 3px dilation, 5px hole-fill) that flow from control_panel.py through analysis_thread.py into SpatialDetailAnalyzer, plus fixes the two-image shared mask combination (nebula: union instead of intersection, so either image's classification counts; background stays an intersection for a clean noise floor). Also fixes a bug surfaced while adding dilation: growing the mask with binary_dilation was amplifying scattered single-pixel noise-driven false positives (expected at a loose sigma cut) into large blobs, inflating the mask ~4x and diluting the noise-corrected contrast metrics. Small isolated objects are now stripped before dilation, matching the existing small-hole-fill treatment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…Section 8 Every Section 8 map figure already had a per-pixel correlation scatter except one: the raw "Original" panel had map/diff/correlation data computed but no figure was ever generated for it, so the reported "some correlation plots are missing" traces to this single gap. Adds a full Original Image family (A/B map-pair, log-ratio, cross-section, histogram, correlation scatter) using the same _plot_side_by_side/_plot_metric_correlation machinery as every other family. When a cross-section line is set in the viewer, its position is now overlaid directly on the Image A/B panels (semi-transparent line, XS_LINE_ALPHA) in every family's map figure, not just as a separate profile chart panel. New SpatialDetailAnalyzer._crosshair_to_cropped_px() converts the line into each map's already border-cropped pixel frame; the view is explicitly locked before plotting so a line near an image edge doesn't add blank autoscale padding. Reorganized Section 8 to open with the raw image (8b), then group detail-based families (LoG, Wavelet, Gradient) ahead of contrast-based families (Local sigma, Weber), with the cross-method overview last. This also fixed a pre-existing duplicate "8a" heading and required sweeping ~28 literal subsection cross-references scattered through captions/info-boxes to the new lettering (a documented CLAUDE.md pitfall). Along the way, fixed a real bug behind "kernel sizes appear out of order": figs_for()'s sorted(figs) was a lexicographic string sort, rendering nrm_std_10px before nrm_std_3px/5px. Replaced with _family_nrm_figs(), which iterates the already numerically-ordered _SPATIAL_CORR_ROWS list. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…od error bars Section 8 previously only compared Image A vs B over two coarse regions (Nebula/Background) per metric/scale, with no way to see whether their differences concentrate near sharp local features (stars, edges, bright knots) rather than being spread uniformly across the nebula. New Section 8j detects a scale-adaptive local-maxima mask independently for each of the 14 metric/scale combinations (std, LoG, gradient, wavelet, Weber) and reports, per row: mean +/- SD magnitude for each image, the geometric-mean A/B ratio, a Mann-Whitney U + Cliff's delta significance test, and a violin+box distribution figure of the underlying masked A/B pixel populations. The mask itself uses maximum_filter non-max suppression + a percentile prominence threshold + pre-smoothing (suppresses noise-driven false peaks) + binary_dilation region growth, with every parameter expressed relative to that row's own characteristic scale rather than a fixed pixel count. The previous single-scale (|LoG| sigma=3px) illustrative mask figure is replaced with a full grid — one row per metric family, columns = kernel/scale smallest to largest — showing every row's actual mask, not just an example. Both cross-method overview plots (8i, 8j) gained error bars: exact for 8j (std of the pixel-paired per-pixel log-ratio population within each mask), approximate coefficient-of-variation propagation for 8i (no pixel-paired population exists there — explicitly captioned as an approximation, not a formal confidence interval). Removed Section 8c's Nebula-vs-Background log-ratio violin figure, whose visual technique is now reused for 8j's A/B pixel-value distribution figure; fixed a latent bug where 8c's mask illustration was accidentally gated on that removed figure's own output and would have disappeared right along with it. Extracted core/stats_utils.py's Mann-Whitney + Cliff's delta helper using the exact O(n log n) identity (delta = 2U/(n1*n2) - 1) in place of an O(n*m) pairwise sign matrix, which would have been a multi-gigabyte memory blowup on Section 8j's much larger per-pixel populations (Section 4's PSF table, with only per-star counts, never hit this — but shares the fix). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…j ratio in log space Section 8's five metric families (8d-8h) and Section 4's PSF test-chart image sequence each embedded 6-9 composite figures with no way to collapse them, making the report long and hard to navigate. Reused the existing _info_box <details>/<summary> pattern (previously text-only) to wrap each family's map/correlation/noise-normalised figures and the test-chart image sequence in closed-by-default collapsible boxes, keeping headings, methodology, and tables visible outside. Section 8j's local-maxima mask overlay changed from darkorange (poor contrast against bright nebula regions) to magenta. The mask itself was undersampling broad bright plateaus that never register as a sharp local maximum, so a new top-N%-brightness mask (SECTION8_LOCALMAX_TOP_PERCENT, default 5%, GUI-configurable) is unioned into the peak mask via a shared _combined_localmax_mask helper -- used identically by the table stats and the mask-grid figure so both always agree on what's masked. 8j's "Ratio A/B" column was already sampled directly from the log-ratio image within the mask, but displayed as a linear ratio with no visible spread, and the cross-method overview plot converted the log-space error into linear units via a delta-method approximation. Both now work natively in log10 space: the table shows "log ratio A/B (geo. mean +/- SD)" shaded a neutral blue (not a red/green comparison), a new per-scale log-ratio distribution figure sits alongside the existing Image A vs B one, and the overview plot's y-axis and error bars are exact by construction, no conversion needed. Removed a duplicate Contrast Retention Detail table from Section 9 -- _psf_simulation_html called _psf_retention_table(sim) twice with identical arguments purely to populate a cache attribute re-spliced into the summary section later. CLAUDE.md gained a new "Collapsible figure blocks" convention, extended the local-maxima and ratio-uncertainty conventions for the OR-mask and log-space presentation patterns, and two new pitfalls (percentile threshold on a flat array, cached render-to-attribute duplication). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…auto-reset The Parameters group had grown to 13 rows in a single QFormLayout, forcing Metrics and Output & Run to carry a lot of dead space since none of the three control-panel boxes had a stretch factor. Split Parameters into two semantically-grouped columns (General/PSF | Nebula & Local-Maxima), number the three group boxes to read as workflow steps, and retune the panel's height cap and default window width from measured QGroupBox.sizeHint()s instead of the old per-row guess. Add a slim toolbar above the image panels (Open A/B | Select ROI/Line | Run Analysis) so the load -> select-region -> run sequence has a visible left-to-right order. Toolbar actions share QActions with the existing menu items and proxy clicks to the real control-panel buttons rather than duplicating their toggle state. Also close a gap noted in CLAUDE.md's stale-ROI pitfall: loading a new image into either panel now resets the ROI and cross-section line (and their visual overlays) instead of only catching an out-of-bounds ROI reactively at Run time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Section 4: drop redundant per-star FWHM/eccentricity histograms, relabel the PSF-simulation test-chart dropdown, and switch the contrast-retention figure from a 3-row stack to a 2x2 grid. Section 6: add EDGE_N_TOP_EDGES to core/models.py so the number of auto-detected edges is configurable (default 3), fix the gradient-map overview to show only the edges actually analyzed instead of every searched candidate (was silently showing 9 boxes against a "three selected" caption), and add a directional start marker to the edge ROI and ESF/LSF profile figures. Section 8: remove the per-family plain tables (SNR, contrast ratio, Weber 99th-pct) and consolidate the five noise-corrected tables previously duplicated under 8d-8h into one combined table in 8j. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tion 6 edge width bug Section 8 (Spatial Detail): remove the Weber fraction contrast metric and add a Local Entropy family (map, contrast ratio, noise-corrected score) reusing the existing shared NC/contrast helpers. Reuses Weber's former 8h letter slot so no cross-reference renumbering is needed. Fix a matplotlib mathtext ParseException race condition: pyparsing's packrat cache (enabled globally by matplotlib's mathtext grammar) is not thread-safe, and this app renders figures from multiple analyzer threads concurrently. Serialize all savefig() calls through a lock in core/fig_utils.py and remove report_builder.py's duplicate, unprotected copy of fig_to_b64. Vectorize the new local entropy map (per-bin uniform_filter box sums instead of a per-pixel generic_filter callback) after it was found to regress the test suite runtime ~2x. Section 6 (Edge Analysis): fix two bugs in EdgeAnalyzer._extract_esf. The "Scan start" marker was drawn through the Sobel-detected gradient peak instead of the ROI's own array center, which is the actual pivot rotate() uses -- the marker could land off the scan-direction line. Separately, the rotation angle formula aligned edges horizontally instead of vertically, so the ESF's column-wise averaging integrated across the transition instead of along it, inflating measured edge widths by 7-14x since the feature's introduction. Add a ground-truth width-accuracy test (checking measured width against the analytically known erf-profile width of a Gaussian-blurred synthetic edge), since the existing tests only checked monotonicity/shape and never caught this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Splash screen now loads resources/AstroImageLabSplash.png instead of a procedurally-painted QPixmap; the whole resources/ dir is already bundled by AstroImageLab.spec, so no packaging changes were needed. The prior mathtext ParseException fix only locked fig_to_b64()'s savefig() call, but fig.tight_layout() triggers the same draw pass and was left unprotected -- PowerSpectrumAnalyzer runs image A/B concurrently in a ThreadPoolExecutor, so an unlocked tight_layout() in one thread could still corrupt the shared pyparsing packrat cache mid-parse in another, reproducing the exact "ParseException: ... (at char 0)" failure on Section 7. Added finalize_layout() to core/fig_utils.py to route tight_layout() through the same lock as savefig(), and switched every call site that can run concurrently with other figure-building code. report_builder.py's tight_layout() calls were left as-is since report generation runs strictly serially after all analyzer threads join. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t-xdist The "not slow" CI job was hitting its 20-minute timeout. Root cause was dozens of tests across 7 files re-running the same expensive analyze()/ build() call with identical inputs instead of sharing a fixture (worst case: one parametrized test in test_spatial_detail.py ran a full two-image SpatialDetailAnalyzer.analyze() 15x to check one absent key). Collapsed same-input calls into class/module-scoped fixtures and added pytest-xdist (-n auto) for parallelism. Documented the pattern and the incident in CLAUDE.md so it doesn't regress as the suite grows. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
significant changes to spatial detail calculation
Update of Unit Test suite
GUI enhancements