Skip to content

Commit d13779c

Browse files
committed
Add refactoring plan for removing Visuals classes
Documents the 12-step plan to remove Visuals1D/Visuals2D and pass overlay objects directly to matplotlib plot functions. https://claude.ai/code/session_01B9sVEV54XWCa2LJw1C8gvv
1 parent 9f74b31 commit d13779c

File tree

1 file changed

+207
-0
lines changed

1 file changed

+207
-0
lines changed

PLAN.md

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# Plan: Remove Visuals Classes and Pass Overlays Directly
2+
3+
## Current State
4+
5+
The codebase is in a *partial* refactoring state. Standalone `plot_array`, `plot_grid`,
6+
`plot_yx`, `plot_inversion_reconstruction` functions already exist in
7+
`autoarray/plot/plots/` and are called by the new-style plotters. However:
8+
9+
- `Visuals1D` and `Visuals2D` wrapper classes still exist
10+
- Every plotter still accepts `visuals_2d` / `visuals_1d` constructor args and stores them
11+
- Helper functions (`_lines_from_visuals`, `_positions_from_visuals`, `_mask_edge_from`,
12+
`_grid_from_visuals`) bridge old Visuals → new standalone functions
13+
- `MatPlot2D.plot_array/plot_grid/plot_mapper` and `MatPlot1D.plot_yx` still exist and
14+
`InterferometerPlotter` still calls them directly
15+
- `InversionPlotter.subplot_of_mapper` directly mutates `self.visuals_2d`
16+
17+
## Goal
18+
19+
Remove `Visuals1D`, `Visuals2D`, and `AbstractVisuals` entirely. Each plotter holds its
20+
overlay data as plain attributes and passes them straight to the `plot_*` standalone
21+
functions. Default overlays (e.g. mask derived from `array.mask`) are computed inline.
22+
23+
---
24+
25+
## Steps
26+
27+
### 1. Update `AbstractPlotter` (`abstract_plotters.py`)
28+
- Remove `visuals_1d: Visuals1D` and `visuals_2d: Visuals2D` constructor parameters and
29+
their default instantiation (`self.visuals_1d = visuals_1d or Visuals1D()`, etc.)
30+
- Remove the imports of `Visuals1D` and `Visuals2D`
31+
32+
### 2. Update each Plotter constructor to accept individual overlay objects
33+
34+
Replace `visuals_2d: Visuals2D = None` with explicit per-overlay kwargs. Plotters store
35+
each overlay as a plain instance attribute (defaulting to `None`).
36+
37+
**`Array2DPlotter`** (`structures/plot/structure_plotters.py`):
38+
```python
39+
def __init__(self, array, mat_plot_2d=None,
40+
mask=None, origin=None, border=None, grid=None,
41+
positions=None, lines=None, vectors=None,
42+
patches=None, fill_region=None, array_overlay=None):
43+
```
44+
45+
**`Grid2DPlotter`**:
46+
```python
47+
def __init__(self, grid, mat_plot_2d=None, lines=None, positions=None):
48+
```
49+
50+
**`YX1DPlotter`**:
51+
```python
52+
def __init__(self, y, x=None, mat_plot_1d=None,
53+
shaded_region=None, vertical_line=None, points=None, ...):
54+
```
55+
56+
**`MapperPlotter`** (`inversion/plot/mapper_plotters.py`):
57+
```python
58+
def __init__(self, mapper, mat_plot_2d=None,
59+
lines=None, grid=None, positions=None):
60+
```
61+
62+
**`InversionPlotter`** (`inversion/plot/inversion_plotters.py`):
63+
```python
64+
def __init__(self, inversion, mat_plot_2d=None,
65+
lines=None, grid=None, positions=None,
66+
residuals_symmetric_cmap=True):
67+
```
68+
69+
**`ImagingPlotterMeta` / `ImagingPlotter`** (`dataset/plot/imaging_plotters.py`):
70+
```python
71+
def __init__(self, dataset, mat_plot_2d=None,
72+
mask=None, grid=None, positions=None, lines=None):
73+
```
74+
75+
**`FitImagingPlotterMeta` / `FitImagingPlotter`** (`fit/plot/fit_imaging_plotters.py`):
76+
```python
77+
def __init__(self, fit, mat_plot_2d=None,
78+
mask=None, grid=None, positions=None, lines=None,
79+
residuals_symmetric_cmap=True):
80+
```
81+
82+
**`InterferometerPlotter`** (`dataset/plot/interferometer_plotters.py`):
83+
```python
84+
def __init__(self, dataset, mat_plot_1d=None, mat_plot_2d=None, lines=None):
85+
```
86+
87+
### 3. Inline overlay logic inside each plotter's `_plot_*` / `figure_*` methods
88+
89+
Each plotter's internal plot helpers already call the standalone functions. Replace
90+
calls like:
91+
```python
92+
mask=_mask_edge_from(array, self.visuals_2d),
93+
lines=_lines_from_visuals(self.visuals_2d),
94+
```
95+
with direct access to the plotter's own attributes plus inline auto-extraction:
96+
```python
97+
mask=self.mask if self.mask is not None else _auto_mask_edge(array),
98+
lines=self.lines,
99+
```
100+
101+
Where `_auto_mask_edge(array)` is a tiny module-level helper (no Visuals dependency):
102+
```python
103+
def _auto_mask_edge(array):
104+
"""Return edge-pixel (y,x) coords from array.mask, or None."""
105+
try:
106+
if not array.mask.is_all_false:
107+
return np.array(array.mask.derive_grid.edge.array)
108+
except AttributeError:
109+
pass
110+
return None
111+
```
112+
113+
### 4. Fix `InversionPlotter.subplot_of_mapper` — drop the `visuals_2d` mutation
114+
115+
Currently this method does:
116+
```python
117+
self.visuals_2d += Visuals2D(mesh_grid=mapper.image_plane_mesh_grid)
118+
```
119+
Replace by passing `mesh_grid` directly to the specific `figures_2d_of_pixelization`
120+
call that needs it, or by temporarily storing `self.mesh_grid` on the plotter and
121+
checking it in `_plot_array`. The mutation and the `Visuals2D(...)` construction are
122+
both removed.
123+
124+
Similarly remove `self.visuals_2d.indexes = indexes` in `subplot_mappings` — store as
125+
`self._indexes` and pass through.
126+
127+
### 5. Update `InterferometerPlotter.figures_2d` — replace old MatPlot calls
128+
129+
`InterferometerPlotter` still calls `self.mat_plot_2d.plot_array(...)`,
130+
`self.mat_plot_2d.plot_grid(...)`, and `self.mat_plot_1d.plot_yx(...)`.
131+
132+
Replace each with the equivalent standalone function call, deriving `ax`, `output_path`,
133+
`filename`, `fmt` via `_output_for_mat_plot` (which already exists and has no Visuals
134+
dependency).
135+
136+
### 6. Remove `MatPlot2D.plot_array`, `plot_grid`, `plot_mapper` (and private helpers)
137+
138+
Once no caller uses them, delete these methods from `mat_plot/two_d.py`:
139+
- `plot_array`
140+
- `plot_grid`
141+
- `plot_mapper`
142+
- `_plot_rectangular_mapper`
143+
- `_plot_delaunay_mapper`
144+
145+
Remove the `from autoarray.plot.visuals.two_d import Visuals2D` import.
146+
147+
### 7. Remove `MatPlot1D.plot_yx`
148+
149+
Delete the method from `mat_plot/one_d.py` and remove the `Visuals1D` import.
150+
151+
### 8. Remove helper extraction functions from `structure_plotters.py`
152+
153+
Delete (no longer needed):
154+
- `_lines_from_visuals`
155+
- `_positions_from_visuals`
156+
- `_mask_edge_from`
157+
- `_grid_from_visuals`
158+
159+
Keep: `_zoom_array`, `_output_for_mat_plot` (neither depends on Visuals).
160+
161+
### 9. Delete `autoarray/plot/visuals/`
162+
163+
Remove:
164+
- `autoarray/plot/visuals/__init__.py`
165+
- `autoarray/plot/visuals/abstract.py`
166+
- `autoarray/plot/visuals/one_d.py`
167+
- `autoarray/plot/visuals/two_d.py`
168+
169+
### 10. Update `autoarray/plot/__init__.py`
170+
171+
Remove `Visuals1D` and `Visuals2D` exports (lines 45–46).
172+
173+
### 11. Check and update remaining plotters
174+
175+
Read and update:
176+
- `fit/plot/fit_interferometer_plotters.py`
177+
- `fit/plot/fit_vector_yx_plotters.py`
178+
179+
Both import `Visuals1D`/`Visuals2D`; apply the same pattern as above.
180+
181+
### 12. Run full test suite
182+
183+
```bash
184+
python -m pytest test_autoarray/ -q --tb=short
185+
```
186+
187+
Fix any failures before committing.
188+
189+
---
190+
191+
## Summary of files changed
192+
193+
| File | Change |
194+
|------|--------|
195+
| `autoarray/plot/abstract_plotters.py` | Remove `visuals_1d`, `visuals_2d` |
196+
| `autoarray/plot/mat_plot/one_d.py` | Remove `plot_yx`, remove Visuals1D import |
197+
| `autoarray/plot/mat_plot/two_d.py` | Remove `plot_array/grid/mapper` methods, remove Visuals2D import |
198+
| `autoarray/plot/visuals/` | **Delete entire directory** |
199+
| `autoarray/plot/__init__.py` | Remove Visuals exports |
200+
| `autoarray/structures/plot/structure_plotters.py` | Replace visuals args with individual kwargs; remove helper functions |
201+
| `autoarray/inversion/plot/mapper_plotters.py` | Replace visuals args with individual kwargs |
202+
| `autoarray/inversion/plot/inversion_plotters.py` | Replace visuals args; fix subplot_of_mapper mutation |
203+
| `autoarray/dataset/plot/imaging_plotters.py` | Replace visuals args with individual kwargs |
204+
| `autoarray/dataset/plot/interferometer_plotters.py` | Replace visuals args; replace old MatPlot calls |
205+
| `autoarray/fit/plot/fit_imaging_plotters.py` | Replace visuals args with individual kwargs |
206+
| `autoarray/fit/plot/fit_interferometer_plotters.py` | Replace visuals args |
207+
| `autoarray/fit/plot/fit_vector_yx_plotters.py` | Replace visuals args |

0 commit comments

Comments
 (0)