Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
631f98e
PR A1: Add autoarray/plot/plots/ direct-matplotlib module
claude Mar 17, 2026
1c46173
PR A2+A3: Switch all autoarray plotters to use direct-matplotlib func…
claude Mar 17, 2026
0828b60
PR A3: replace mat_plot_2d.plot_array in FitImagingPlotterMeta with p…
claude Mar 17, 2026
1d55dd2
Add missing test output directories to .gitignore
claude Mar 17, 2026
e99a05c
Fix plotting test regressions and add missing optional dependencies
claude Mar 17, 2026
9f74b31
Enable JAX 64-bit mode for tests
claude Mar 17, 2026
d13779c
Add refactoring plan for removing Visuals classes
claude Mar 17, 2026
896f752
Remove Visuals1D/Visuals2D classes; pass overlays directly to plotters
claude Mar 17, 2026
3bd00e5
Refactor plotting module: remove MatPlot1D/2D, multi_plotters, subplo…
claude Mar 19, 2026
e5f769d
Remove wrap module boilerplate; keep only Cmap, Colorbar, Output, Del…
claude Mar 20, 2026
b491a11
Remove all Plotter classes; replace with standalone matplotlib functions
claude Mar 21, 2026
ceea220
Move autoarray extraction into plot_array/plot_grid/plot_yx; remove a…
claude Mar 24, 2026
556e816
Remove DelaunayDrawer and Colorbar wrap classes
claude Mar 24, 2026
f88a1c7
Remove Cmap wrap class; add symmetric_cmap_from and set_with_color_va…
claude Mar 24, 2026
645ff31
Remove AutoLabels and auto_labels.py
claude Mar 24, 2026
4154479
Flatten plot module: remove plots/ and wrap/ subpackages
claude Mar 24, 2026
443fb54
Add docstrings to all plot functions; run black formatting
claude Mar 24, 2026
1519fb6
Add plot_visibilities_1d to autoarray plot utils
claude Mar 24, 2026
095f16c
Add private aliases in array.py; allow save_figure to accept multiple…
claude Mar 24, 2026
67fd418
Fix all Copilot review issues in plot module
claude Mar 24, 2026
6f48e13
Wire mat_plot font sizes and figsize from visualize/general.yaml
claude Mar 24, 2026
b48a3f8
black
Mar 24, 2026
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ test_autoarray/dataset/plot/files/
test_autoarray/fit/plot/files/
test_autoarray/structures/arrays/one_d/files/array/
test_autoarray/structures/plot/files/
test_autoarray/inversion/plot/files/
test_autoarray/plot/files/
test_autoarray/instruments/files/

.envr
Expand Down
207 changes: 207 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# Plan: Remove Visuals Classes and Pass Overlays Directly

## Current State

The codebase is in a *partial* refactoring state. Standalone `plot_array`, `plot_grid`,
`plot_yx`, `plot_inversion_reconstruction` functions already exist in
`autoarray/plot/plots/` and are called by the new-style plotters. However:

- `Visuals1D` and `Visuals2D` wrapper classes still exist
- Every plotter still accepts `visuals_2d` / `visuals_1d` constructor args and stores them
- Helper functions (`_lines_from_visuals`, `_positions_from_visuals`, `_mask_edge_from`,
`_grid_from_visuals`) bridge old Visuals → new standalone functions
- `MatPlot2D.plot_array/plot_grid/plot_mapper` and `MatPlot1D.plot_yx` still exist and
`InterferometerPlotter` still calls them directly
- `InversionPlotter.subplot_of_mapper` directly mutates `self.visuals_2d`

## Goal

Remove `Visuals1D`, `Visuals2D`, and `AbstractVisuals` entirely. Each plotter holds its
overlay data as plain attributes and passes them straight to the `plot_*` standalone
functions. Default overlays (e.g. mask derived from `array.mask`) are computed inline.

---

## Steps

### 1. Update `AbstractPlotter` (`abstract_plotters.py`)
- Remove `visuals_1d: Visuals1D` and `visuals_2d: Visuals2D` constructor parameters and
their default instantiation (`self.visuals_1d = visuals_1d or Visuals1D()`, etc.)
- Remove the imports of `Visuals1D` and `Visuals2D`

### 2. Update each Plotter constructor to accept individual overlay objects

Replace `visuals_2d: Visuals2D = None` with explicit per-overlay kwargs. Plotters store
each overlay as a plain instance attribute (defaulting to `None`).

**`Array2DPlotter`** (`structures/plot/structure_plotters.py`):
```python
def __init__(self, array, mat_plot_2d=None,
mask=None, origin=None, border=None, grid=None,
positions=None, lines=None, vectors=None,
patches=None, fill_region=None, array_overlay=None):
```

**`Grid2DPlotter`**:
```python
def __init__(self, grid, mat_plot_2d=None, lines=None, positions=None):
```

**`YX1DPlotter`**:
```python
def __init__(self, y, x=None, mat_plot_1d=None,
shaded_region=None, vertical_line=None, points=None, ...):
```

**`MapperPlotter`** (`inversion/plot/mapper_plotters.py`):
```python
def __init__(self, mapper, mat_plot_2d=None,
lines=None, grid=None, positions=None):
```

**`InversionPlotter`** (`inversion/plot/inversion_plotters.py`):
```python
def __init__(self, inversion, mat_plot_2d=None,
lines=None, grid=None, positions=None,
residuals_symmetric_cmap=True):
```

**`ImagingPlotterMeta` / `ImagingPlotter`** (`dataset/plot/imaging_plotters.py`):
```python
def __init__(self, dataset, mat_plot_2d=None,
mask=None, grid=None, positions=None, lines=None):
```

**`FitImagingPlotterMeta` / `FitImagingPlotter`** (`fit/plot/fit_imaging_plotters.py`):
```python
def __init__(self, fit, mat_plot_2d=None,
mask=None, grid=None, positions=None, lines=None,
residuals_symmetric_cmap=True):
```

**`InterferometerPlotter`** (`dataset/plot/interferometer_plotters.py`):
```python
def __init__(self, dataset, mat_plot_1d=None, mat_plot_2d=None, lines=None):
```

### 3. Inline overlay logic inside each plotter's `_plot_*` / `figure_*` methods

Each plotter's internal plot helpers already call the standalone functions. Replace
calls like:
```python
mask=_mask_edge_from(array, self.visuals_2d),
lines=_lines_from_visuals(self.visuals_2d),
```
with direct access to the plotter's own attributes plus inline auto-extraction:
```python
mask=self.mask if self.mask is not None else _auto_mask_edge(array),
lines=self.lines,
```

Where `_auto_mask_edge(array)` is a tiny module-level helper (no Visuals dependency):
```python
def _auto_mask_edge(array):
"""Return edge-pixel (y,x) coords from array.mask, or None."""
try:
if not array.mask.is_all_false:
return np.array(array.mask.derive_grid.edge.array)
except AttributeError:
pass
return None
```

### 4. Fix `InversionPlotter.subplot_of_mapper` — drop the `visuals_2d` mutation

Currently this method does:
```python
self.visuals_2d += Visuals2D(mesh_grid=mapper.image_plane_mesh_grid)
```
Replace by passing `mesh_grid` directly to the specific `figures_2d_of_pixelization`
call that needs it, or by temporarily storing `self.mesh_grid` on the plotter and
checking it in `_plot_array`. The mutation and the `Visuals2D(...)` construction are
both removed.

Similarly remove `self.visuals_2d.indexes = indexes` in `subplot_mappings` — store as
`self._indexes` and pass through.

### 5. Update `InterferometerPlotter.figures_2d` — replace old MatPlot calls

`InterferometerPlotter` still calls `self.mat_plot_2d.plot_array(...)`,
`self.mat_plot_2d.plot_grid(...)`, and `self.mat_plot_1d.plot_yx(...)`.

Replace each with the equivalent standalone function call, deriving `ax`, `output_path`,
`filename`, `fmt` via `_output_for_mat_plot` (which already exists and has no Visuals
dependency).

### 6. Remove `MatPlot2D.plot_array`, `plot_grid`, `plot_mapper` (and private helpers)

Once no caller uses them, delete these methods from `mat_plot/two_d.py`:
- `plot_array`
- `plot_grid`
- `plot_mapper`
- `_plot_rectangular_mapper`
- `_plot_delaunay_mapper`

Remove the `from autoarray.plot.visuals.two_d import Visuals2D` import.

### 7. Remove `MatPlot1D.plot_yx`

Delete the method from `mat_plot/one_d.py` and remove the `Visuals1D` import.

### 8. Remove helper extraction functions from `structure_plotters.py`

Delete (no longer needed):
- `_lines_from_visuals`
- `_positions_from_visuals`
- `_mask_edge_from`
- `_grid_from_visuals`

Keep: `_zoom_array`, `_output_for_mat_plot` (neither depends on Visuals).

### 9. Delete `autoarray/plot/visuals/`

Remove:
- `autoarray/plot/visuals/__init__.py`
- `autoarray/plot/visuals/abstract.py`
- `autoarray/plot/visuals/one_d.py`
- `autoarray/plot/visuals/two_d.py`

### 10. Update `autoarray/plot/__init__.py`

Remove `Visuals1D` and `Visuals2D` exports (lines 45–46).

### 11. Check and update remaining plotters

Read and update:
- `fit/plot/fit_interferometer_plotters.py`
- `fit/plot/fit_vector_yx_plotters.py`

Both import `Visuals1D`/`Visuals2D`; apply the same pattern as above.

### 12. Run full test suite

```bash
python -m pytest test_autoarray/ -q --tb=short
```

Fix any failures before committing.

---

## Summary of files changed

| File | Change |
|------|--------|
| `autoarray/plot/abstract_plotters.py` | Remove `visuals_1d`, `visuals_2d` |
| `autoarray/plot/mat_plot/one_d.py` | Remove `plot_yx`, remove Visuals1D import |
| `autoarray/plot/mat_plot/two_d.py` | Remove `plot_array/grid/mapper` methods, remove Visuals2D import |
| `autoarray/plot/visuals/` | **Delete entire directory** |
| `autoarray/plot/__init__.py` | Remove Visuals exports |
| `autoarray/structures/plot/structure_plotters.py` | Replace visuals args with individual kwargs; remove helper functions |
| `autoarray/inversion/plot/mapper_plotters.py` | Replace visuals args with individual kwargs |
| `autoarray/inversion/plot/inversion_plotters.py` | Replace visuals args; fix subplot_of_mapper mutation |
| `autoarray/dataset/plot/imaging_plotters.py` | Replace visuals args with individual kwargs |
| `autoarray/dataset/plot/interferometer_plotters.py` | Replace visuals args; replace old MatPlot calls |
| `autoarray/fit/plot/fit_imaging_plotters.py` | Replace visuals args with individual kwargs |
| `autoarray/fit/plot/fit_interferometer_plotters.py` | Replace visuals args |
| `autoarray/fit/plot/fit_vector_yx_plotters.py` | Replace visuals args |
58 changes: 30 additions & 28 deletions autoarray/config/visualize/general.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
general:
backend: default # The matploblib backend used for visualization. `default` uses the system default, can specifiy specific backend (e.g. TKAgg, Qt5Agg, WXAgg).
imshow_origin: upper # The `origin` input of `imshow`, determining if pixel values are ascending or descending on the y-axis.
log10_min_value: 1.0e-4 # If negative values are being plotted on a log10 scale, values below this value are rounded up to it (e.g. to remove negative values).
log10_max_value: 1.0e99 # If positive values are being plotted on a log10 scale, values above this value are rounded down to it (e.g. to prevent white blobs).
zoom_around_mask: true # If True, plots of data structures with a mask automatically zoom in the masked region.
inversion:
reconstruction_vmax_factor: 0.5
total_mappings_pixels : 8 # The number of source pixels used when plotting the subplot_mappings of a pixelization.
zoom:
plane_percent: 0.01
inversion_percent: 0.01 # Plots of an Inversion's reconstruction use the reconstructed data's bright value multiplied by this factor.
subplot_shape: # The shape of a subplots for figures with an input number of subplots (e.g. for a figure with 4 subplots, the shape is (2, 2)).
1: (1, 1) # The shape of subplots for a figure with 1 subplot.
2: (1, 2) # The shape of subplots for a figure with 2 subplots.
4: (2, 2) # The shape of subplots for a figure with 4 (or less than the above value) of subplots.
6: (2, 3) # The shape of subplots for a figure with 6 (or less than the above value) of subplots.
9: (3, 3) # The shape of subplots for a figure with 9 (or less than the above value) of subplots.
12: (3, 4) # The shape of subplots for a figure with 12 (or less than the above value) of subplots.
16: (4, 4) # The shape of subplots for a figure with 16 (or less than the above value) of subplots.
20: (4, 5) # The shape of subplots for a figure with 20 (or less than the above value) of subplots.
36: (6, 6) # The shape of subplots for a figure with 36 (or less than the above value) of subplots.
subplot_shape_to_figsize_factor: (6, 6) # The factors by which the subplot_shape is multiplied to determine the figsize of a subplot (e.g. if the subplot_shape is (2,2), the figsize will be (2*6, 2*6).
units:
use_scaled: true # Whether to plot spatial coordinates in scaled units computed via the pixel_scale (e.g. arc-seconds) or pixel units by default.
cb_unit: $\,\,\mathrm{e^{-}}\,\mathrm{s^{-1}}$ # The string or latex unit label used for the colorbar of the image, for example electrons per second.
scaled_symbol: '"' # The symbol used when plotting spatial coordinates computed via the pixel_scale (e.g. for Astronomy data this is arc-seconds).
unscaled_symbol: pix # The symbol used when plotting spatial coordinates in unscaled pixel units.
general:
backend: default # The matplotlib backend used for visualization. `default` uses the system default, can specify specific backend (e.g. TKAgg, Qt5Agg, WXAgg).
imshow_origin: upper # The `origin` input of `imshow`, determining if pixel values are ascending or descending on the y-axis.
log10_min_value: 1.0e-4 # If negative values are being plotted on a log10 scale, values below this value are rounded up to it (e.g. to remove negative values).
log10_max_value: 1.0e99 # If positive values are being plotted on a log10 scale, values above this value are rounded down to it.
zoom_around_mask: true # If True, plots of data structures with a mask automatically zoom in the masked region.
inversion:
reconstruction_vmax_factor: 0.5
total_mappings_pixels: 8 # The number of source pixels used when plotting the subplot_mappings of a pixelization.
zoom:
plane_percent: 0.01
inversion_percent: 0.01 # Plots of an Inversion's reconstruction use the reconstructed data's bright value multiplied by this factor.
units:
use_scaled: true # Whether to plot spatial coordinates in scaled units computed via the pixel_scale (e.g. arc-seconds) or pixel units by default.
cb_unit: $\,\,\mathrm{e^{-}}\,\mathrm{s^{-1}}$ # The string or latex unit label used for the colorbar of the image, for example electrons per second.
scaled_symbol: '"' # The symbol used when plotting spatial coordinates computed via the pixel_scale (e.g. for Astronomy data this is arc-seconds).
unscaled_symbol: pix # The symbol used when plotting spatial coordinates in unscaled pixel units.
mat_plot:
figure:
figsize: (7, 7) # Default figure size. Override via aplt.Figure(figsize=(...)).
yticks:
fontsize: 22 # Default y-tick font size. Override via aplt.YTicks(fontsize=...).
xticks:
fontsize: 22 # Default x-tick font size. Override via aplt.XTicks(fontsize=...).
title:
fontsize: 24 # Default title font size. Override via aplt.Title(fontsize=...).
ylabel:
fontsize: 16 # Default y-label font size. Override via aplt.YLabel(fontsize=...).
xlabel:
fontsize: 16 # Default x-label font size. Override via aplt.XLabel(fontsize=...).
Loading
Loading