Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,23 @@ the full figure set. Every other producer tracks only `dataset.png` and `fit.png
everything else. Producers with several sub-datasets write one pair per sub-folder
(`multi_dataset` per band, the datacube per channel, `cluster` per point-source plane). Many
of these figures are the galaxy-scale plots and look poor on point / cluster / weak data —
bespoke figures are a follow-up through the Eyes dashboard. `cluster` calls the two
bespoke figures are a follow-up through the Eyes dashboard. `cluster` calls the
`PlotterPoint` methods directly instead of `VisualizerPoint`, skipping the untracked tracer and
galaxy figures; the "Fit Positions" panel still draws the critical curves, which cost ~2 min per
dataset on the 15-galaxy multi-plane lens (the PNGs match the visualizer's).
galaxy figures; the "Fit Positions" and point-solver panels still draw the critical curves, which
cost ~2 min per dataset on the 15-galaxy multi-plane lens (the PNGs match the visualizer's).

**Point solver.** `point_source_image_chi_squared` (via `visualize(quick_update=False)`) and
`cluster` (per plane) also keep `point_solver.png`: the model's real `PointSolver` refining onto
its images (`fit_point_dataset: subplot_point_solver`, on in this repo's `plots.yaml`, off in
the library). `point_source_image_chi_squared/images/visualization/teaching/` holds the same
figure on a coarse teaching grid from `aplt.plot_point_solver`, plus its looping animation
`point_solver.gif`.

**What is tracked.** PNG figures under `scripts/<domain>/images/**`, `GALLERY.md` and
`gallery/viz_manifest.yaml`. The FITS /
`gallery/viz_manifest.yaml`, plus the teaching GIF animation
(`point_source_image_chi_squared/images/visualization/teaching/point_solver.gif`). The manifest
and `GALLERY.md` list PNGs only (the PyAutoEyes read contract), so the GIF is tracked beside its
PNG still but is not a manifest entry; `render.yml` commits it with the PNGs. The FITS /
CSV / JSON data products the visualizers also write are gitignored (bulky, not viewable on
GitHub), as are `output/` and `dataset/**/lensed_source.fits`.

Expand Down
25 changes: 22 additions & 3 deletions GALLERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

<!-- Generated by gallery/gallery_build.py from scripts/<domain>/images/. Do not edit by hand: rerun `bash gallery/gallery_run.sh --all`. -->

Rendered with PyAutoLens `2026.8.17.1` · 68 figures.
Rendered with PyAutoLens `2026.8.17.1` · 72 figures.

Every figure below is what the PyAutoLens visualizers (`VisualizerImaging`, `VisualizerInterferometer`, `VisualizerPoint`, `VisualizerWeak`) write to a model-fit's `image/` folder, rendered on this repo's datasets with the true model. See [README.md](README.md) for how to improve one.

## Contents

- [cluster](#cluster)
- [visualization](#cluster--visualization) (4 figures)
- [visualization](#cluster--visualization) (6 figures)
- [point_0/](#cluster--visualization--point_0)
- [point_1/](#cluster--visualization--point_1)
- [group](#group)
Expand Down Expand Up @@ -38,8 +38,9 @@ Every figure below is what the PyAutoLens visualizers (`VisualizerImaging`, `Vis
- [visualization](#multi_galaxy--visualization) (2 figures)
- [top level](#multi_galaxy--visualization--top-level)
- [point_source_image_chi_squared](#point_source_image_chi_squared)
- [visualization](#point_source_image_chi_squared--visualization) (4 figures)
- [visualization](#point_source_image_chi_squared--visualization) (6 figures)
- [top level](#point_source_image_chi_squared--visualization--top-level)
- [teaching/](#point_source_image_chi_squared--visualization--teaching)
- [point_source_source_chi_squared](#point_source_source_chi_squared)
- [visualization](#point_source_source_chi_squared--visualization) (4 figures)
- [top level](#point_source_source_chi_squared--visualization--top-level)
Expand All @@ -61,6 +62,10 @@ Every figure below is what the PyAutoLens visualizers (`VisualizerImaging`, `Vis

![fit](scripts/cluster/images/visualization/point_0/fit.png)

##### point_solver

![point_solver](scripts/cluster/images/visualization/point_0/point_solver.png)

#### cluster / visualization / point_1/

##### dataset
Expand All @@ -71,6 +76,10 @@ Every figure below is what the PyAutoLens visualizers (`VisualizerImaging`, `Vis

![fit](scripts/cluster/images/visualization/point_1/fit.png)

##### point_solver

![point_solver](scripts/cluster/images/visualization/point_1/point_solver.png)

## group

### group / visualization
Expand Down Expand Up @@ -359,6 +368,16 @@ Every figure below is what the PyAutoLens visualizers (`VisualizerImaging`, `Vis

![image_with_points](scripts/point_source_image_chi_squared/images/visualization/image_with_points.png)

##### point_solver

![point_solver](scripts/point_source_image_chi_squared/images/visualization/point_solver.png)

#### point_source_image_chi_squared / visualization / teaching/

##### point_solver

![point_solver](scripts/point_source_image_chi_squared/images/visualization/teaching/point_solver.png)

## point_source_source_chi_squared

### point_source_source_chi_squared / visualization
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ mirroring `autolens_workspace` (a variant gets its own folder):
| `imaging` | `visualization.py` | full set: parametric + Delaunay source |
| `interferometer` | `visualization.py` | full set: parametric + Delaunay source |
| `interferometer_datacube` | `visualization.py` | `dataset.png` + `fit.png` per channel |
| `point_source_image_chi_squared` | `visualization.py` | `dataset.png` + `fit.png` |
| `point_source_image_chi_squared` | `visualization.py` | `dataset.png` + `fit.png` + image-with-points pair + `point_solver.png`; `teaching/point_solver.png` + `.gif` (coarse grid) |
| `point_source_source_chi_squared` | `visualization.py` | `dataset.png` + `fit.png` |
| `multi_galaxy` | `visualization.py` | `dataset.png` + `fit.png` |
| `group` | `visualization.py` | `dataset.png` + `fit.png` |
| `cluster` | `visualization.py` | `dataset.png` + `fit.png` per point-source plane |
| `cluster` | `visualization.py` | `dataset.png` + `fit.png` + `point_solver.png` per point-source plane |
| `multi_dataset` | `visualization.py` | `dataset.png` + `fit.png` per band |
| `weak` | `visualization.py` | `dataset.png` + `fit.png` |

Expand Down
16 changes: 9 additions & 7 deletions _viz_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,14 @@ def keep_dataset_and_fit(


def mirror_to_scratch(domains: list[str] | None = None) -> Path | None:
"""Copy freshly rendered PNGs to the opt-in Eyes scratch folder; return its lib folder.
"""Copy freshly rendered PNGs (and GIF animations) to the opt-in Eyes scratch folder.

Returns the scratch lib folder.

For on-the-fly figure review before any PR or CI. When ``$PYAUTO_EYES_SCRATCH`` is
unset this is a silent no-op returning ``None`` (so CI and other machines are
untouched). Otherwise each domain's ``$PYAUTO_EYES_SCRATCH/<EYES_LIB>/<domain>/`` is
deleted and refilled with every PNG under ``scripts/<domain>/images/`` (subpaths
deleted and refilled with every PNG and GIF under ``scripts/<domain>/images/`` (subpaths
below ``images/`` kept), so no stale figure survives a re-render. ``domains=None``
mirrors every domain that has an ``images/`` folder (``misc`` never does).
"""
Expand All @@ -243,12 +245,12 @@ def mirror_to_scratch(domains: list[str] | None = None) -> Path | None:
continue
dest = lib_dir / domain
shutil.rmtree(dest, ignore_errors=True)
pngs = sorted(images.rglob("*.png"))
for png in pngs:
target = dest / png.relative_to(images)
figures = sorted([*images.rglob("*.png"), *images.rglob("*.gif")])
for figure in figures:
target = dest / figure.relative_to(images)
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(png, target)
print(f" [eyes-scratch] {len(pngs)} PNGs -> {dest}")
shutil.copy2(figure, target)
print(f" [eyes-scratch] {len(figures)} figures (PNG/GIF) -> {dest}")
return lib_dir


Expand Down
3 changes: 2 additions & 1 deletion config/visualize/plots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ fit_interferometer: # Settings for plots of fits to inter
point_dataset: # Settings for plots of point source datasets (e.g. PointDatasetPlotter).
subplot_dataset: true # Plot subplot containing all dataset quantities (e.g. the data, noise-map, etc.)?

fit_point_dataset: {} # Settings for plots of fits to point source datasets (e.g. FitPointDatasetPlotter).
fit_point_dataset: # Settings for plots of fits to point source datasets (e.g. FitPointDatasetPlotter).
subplot_point_solver: true # PointSolver refinement steps at the best fit (point_solver.png); off by default in the library.

weak_dataset: # Settings for plots of weak lensing shear catalogues (e.g. PlotterWeak).
subplot_dataset: true # Plot subplot containing all dataset quantities (e.g. the shear field, noise-map, etc.)?
Expand Down
42 changes: 33 additions & 9 deletions gallery/viz_manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ rendered_with:
autogalaxy: 2026.8.17.1
autoarray: 2026.8.17.1
autofit: 2026.8.17.1
figure_count: 68
figure_count: 72
figures:
- file: scripts/cluster/images/visualization/point_0/dataset.png
producer: scripts/cluster/visualization.py
Expand All @@ -20,8 +20,14 @@ figures:
producer: scripts/cluster/visualization.py
domain: cluster
source: point_0
bytes: 68264
sha256: c330570f6373ef9055c8d4dd5b7be3fa8b3f096cdb0117d2aec4b3d5987e43fa
bytes: 68170
sha256: a77734d4569f512ec14657e5a6fb2c1308a1e49c7b2153e00bf83f2c83f9e860
- file: scripts/cluster/images/visualization/point_0/point_solver.png
producer: scripts/cluster/visualization.py
domain: cluster
source: point_0
bytes: 646052
sha256: b0f21b073ab19c91c629504940ecd8fb631dda85107edabfd6345c60e7fbc1b4
- file: scripts/cluster/images/visualization/point_1/dataset.png
producer: scripts/cluster/visualization.py
domain: cluster
Expand All @@ -32,8 +38,14 @@ figures:
producer: scripts/cluster/visualization.py
domain: cluster
source: point_1
bytes: 65979
sha256: aaea68e094f6ff3d142c9a24cb92e750781b43b7768c82f3ff527356150c0f35
bytes: 65871
sha256: 813846220f1a47d03f88084b92cb93507a91b6410ae72dd0138cf13eda54c667
- file: scripts/cluster/images/visualization/point_1/point_solver.png
producer: scripts/cluster/visualization.py
domain: cluster
source: point_1
bytes: 631672
sha256: 357d5dff2da880f3bd0908dba09624d2ee66d4211548f27dd79807452b153299
- file: scripts/group/images/visualization/dataset.png
producer: scripts/group/visualization.py
domain: group
Expand Down Expand Up @@ -368,8 +380,8 @@ figures:
producer: scripts/point_source_image_chi_squared/visualization.py
domain: point_source_image_chi_squared
source: ''
bytes: 59950
sha256: dcf7b7a60281c49244264678c6c15ab0a5636be9c66fd4e555bba2b9fdecab40
bytes: 59992
sha256: 75919308cfe263625a6d71450f2eb83acc2b13a0b08f1edc3ee97720c4f5f75a
- file: scripts/point_source_image_chi_squared/images/visualization/fit_image_with_points.png
producer: scripts/point_source_image_chi_squared/visualization.py
domain: point_source_image_chi_squared
Expand All @@ -382,6 +394,18 @@ figures:
source: ''
bytes: 66518
sha256: 2653419882e5f55d2afe24b067e8d5c9865081aee51517dc05520a12d1787468
- file: scripts/point_source_image_chi_squared/images/visualization/point_solver.png
producer: scripts/point_source_image_chi_squared/visualization.py
domain: point_source_image_chi_squared
source: ''
bytes: 809716
sha256: 92252350649f9d7a8698a775afcbf02cc0bc0291f842b5365f7ecea0fb4ec25a
- file: scripts/point_source_image_chi_squared/images/visualization/teaching/point_solver.png
producer: scripts/point_source_image_chi_squared/visualization.py
domain: point_source_image_chi_squared
source: teaching
bytes: 495158
sha256: 84f0312c1415db43b8d8b901a2977a24d706697df70523aef122744a7e00a451
- file: scripts/point_source_source_chi_squared/images/visualization/dataset.png
producer: scripts/point_source_source_chi_squared/visualization.py
domain: point_source_source_chi_squared
Expand All @@ -392,8 +416,8 @@ figures:
producer: scripts/point_source_source_chi_squared/visualization.py
domain: point_source_source_chi_squared
source: ''
bytes: 60925
sha256: b9af86e928d6a1e395cc81aca38cffc7b94bb5b3af82484180d37f989b245472
bytes: 60766
sha256: 386aaf5cf28aa8b69b71a53962a3edde8d5673769ab7eb7f7ae81f1fe2fe9399
- file: scripts/point_source_source_chi_squared/images/visualization/fit_image_with_points.png
producer: scripts/point_source_source_chi_squared/visualization.py
domain: point_source_source_chi_squared
Expand Down
Binary file modified scripts/cluster/images/visualization/point_0/fit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified scripts/cluster/images/visualization/point_1/fit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 25 additions & 8 deletions scripts/cluster/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Visualization: Cluster
======================

Renders the two figures ``VisualizerPoint`` writes for each point-source dataset of a
Renders the figures ``VisualizerPoint`` writes for each point-source dataset of a
multi-plane cluster fit (two point sources at z=1.0 and z=2.0 behind a cluster lens), so the
latest version of each lives in git (``GALLERY.md``). A cluster model-fit has one
``AnalysisPoint`` per point-source dataset (combined in a factor graph), each visualized
Expand All @@ -13,14 +13,18 @@

scripts/cluster/images/visualization/
point_0/dataset.png, point_0/fit.png <- PlotterPoint.dataset_point, PlotterPoint.fit_point
point_1/dataset.png, point_1/fit.png
point_0/point_solver.png <- PlotterPoint.point_solver (the model's real
multi-plane PointSolver refining onto this
source's images, steps 0, 1, 2 and final)
point_1/dataset.png, point_1/fit.png, point_1/point_solver.png

**Plotter, not Visualizer.** ``VisualizerPoint.visualize`` also renders the tracer and galaxy
figures this repo does not track, so this producer calls the same two ``PlotterPoint`` methods the
figures this repo does not track, so this producer calls the same ``PlotterPoint`` methods the
visualizer calls (``dataset_point(solver=...)`` in ``visualize_before_fit``;
``fit_point(quick_update=True)`` in ``visualize``), writing the figures the visualizer would. The
"Fit Positions" panel draws the tracer's critical curves, which ``fit_point`` computes on a 100x100
grid covering the solver grid: for this 15-galaxy multi-plane lens that costs ~2 min per dataset.
``fit_point(quick_update=True)`` and ``point_solver`` in ``visualize``), writing the figures the
visualizer would. The "Fit Positions" and point-solver panels draw the tracer's critical curves,
computed once per dataset (as the visualizer does) on a 100x100 grid covering the solver grid: for
this 15-galaxy multi-plane lens that costs ~2 min per dataset.

The point plotter writes ``dataset_point.png`` (renamed to ``dataset.png``); every other file
the visualizer writes is deleted.
Expand Down Expand Up @@ -62,6 +66,8 @@ def _repo_root() -> Path:

import autofit as af
import autolens as al
from autolens.imaging.plot.fit_imaging_plots import _compute_critical_curve_lines
from autolens.lens.plot.critical_curves import critical_curve_grid_from
from autolens.point.model.plotter import PlotterPoint

from _viz_cli import ensure_dataset, keep_dataset_and_fit
Expand Down Expand Up @@ -121,11 +127,22 @@ def _repo_root() -> Path:
t0 = time.perf_counter()
plotter = PlotterPoint(image_path=paths.image_path, title_prefix=analysis.title_prefix)
plotter.dataset_point(dataset=analysis.dataset, solver=analysis.solver)
fit = analysis.fit_for_visualization(instance=instance)
ip_lines, ip_colors, sp_lines, sp_colors = _compute_critical_curve_lines(
fit.tracer, critical_curve_grid_from(dataset=fit.dataset, solver=solver)
)
plotter.fit_point(
fit=analysis.fit_for_visualization(instance=instance),
fit=fit,
quick_update=True,
image_plane_lines=ip_lines if ip_lines is not None else [],
image_plane_line_colors=ip_colors if ip_lines is not None else [],
source_plane_lines=sp_lines,
source_plane_line_colors=sp_colors,
)
plotter.point_solver(fit=fit, image_plane_lines=ip_lines if ip_lines is not None else [])
keep_dataset_and_fit(
point_path, dataset_png="dataset_point.png", extra_pngs=("point_solver.png",)
)
keep_dataset_and_fit(point_path, dataset_png="dataset_point.png")
print(f"visualize [{dataset.name}]: {time.perf_counter() - t0:.1f}s")

n_png = len(list(image_path.rglob("*.png")))
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading