Skip to content

Commit 366c736

Browse files
authored
Merge pull request #236 from Jammy2211/claude/refactor-plotting-module-s6Zq1
Claude/refactor plotting module s6 zq1
2 parents 9b81be7 + b48a3f8 commit 366c736

140 files changed

Lines changed: 3740 additions & 9579 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ test_autoarray/dataset/plot/files/
1212
test_autoarray/fit/plot/files/
1313
test_autoarray/structures/arrays/one_d/files/array/
1414
test_autoarray/structures/plot/files/
15+
test_autoarray/inversion/plot/files/
16+
test_autoarray/plot/files/
1517
test_autoarray/instruments/files/
1618

1719
.envr

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 |
Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1-
general:
2-
backend: default # The matploblib backend used for visualization. `default` uses the system default, can specifiy specific backend (e.g. TKAgg, Qt5Agg, WXAgg).
3-
imshow_origin: upper # The `origin` input of `imshow`, determining if pixel values are ascending or descending on the y-axis.
4-
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).
5-
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).
6-
zoom_around_mask: true # If True, plots of data structures with a mask automatically zoom in the masked region.
7-
inversion:
8-
reconstruction_vmax_factor: 0.5
9-
total_mappings_pixels : 8 # The number of source pixels used when plotting the subplot_mappings of a pixelization.
10-
zoom:
11-
plane_percent: 0.01
12-
inversion_percent: 0.01 # Plots of an Inversion's reconstruction use the reconstructed data's bright value multiplied by this factor.
13-
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)).
14-
1: (1, 1) # The shape of subplots for a figure with 1 subplot.
15-
2: (1, 2) # The shape of subplots for a figure with 2 subplots.
16-
4: (2, 2) # The shape of subplots for a figure with 4 (or less than the above value) of subplots.
17-
6: (2, 3) # The shape of subplots for a figure with 6 (or less than the above value) of subplots.
18-
9: (3, 3) # The shape of subplots for a figure with 9 (or less than the above value) of subplots.
19-
12: (3, 4) # The shape of subplots for a figure with 12 (or less than the above value) of subplots.
20-
16: (4, 4) # The shape of subplots for a figure with 16 (or less than the above value) of subplots.
21-
20: (4, 5) # The shape of subplots for a figure with 20 (or less than the above value) of subplots.
22-
36: (6, 6) # The shape of subplots for a figure with 36 (or less than the above value) of subplots.
23-
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).
24-
units:
25-
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.
26-
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.
27-
scaled_symbol: '"' # The symbol used when plotting spatial coordinates computed via the pixel_scale (e.g. for Astronomy data this is arc-seconds).
28-
unscaled_symbol: pix # The symbol used when plotting spatial coordinates in unscaled pixel units.
1+
general:
2+
backend: default # The matplotlib backend used for visualization. `default` uses the system default, can specify specific backend (e.g. TKAgg, Qt5Agg, WXAgg).
3+
imshow_origin: upper # The `origin` input of `imshow`, determining if pixel values are ascending or descending on the y-axis.
4+
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).
5+
log10_max_value: 1.0e99 # If positive values are being plotted on a log10 scale, values above this value are rounded down to it.
6+
zoom_around_mask: true # If True, plots of data structures with a mask automatically zoom in the masked region.
7+
inversion:
8+
reconstruction_vmax_factor: 0.5
9+
total_mappings_pixels: 8 # The number of source pixels used when plotting the subplot_mappings of a pixelization.
10+
zoom:
11+
plane_percent: 0.01
12+
inversion_percent: 0.01 # Plots of an Inversion's reconstruction use the reconstructed data's bright value multiplied by this factor.
13+
units:
14+
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.
15+
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.
16+
scaled_symbol: '"' # The symbol used when plotting spatial coordinates computed via the pixel_scale (e.g. for Astronomy data this is arc-seconds).
17+
unscaled_symbol: pix # The symbol used when plotting spatial coordinates in unscaled pixel units.
18+
mat_plot:
19+
figure:
20+
figsize: (7, 7) # Default figure size. Override via aplt.Figure(figsize=(...)).
21+
yticks:
22+
fontsize: 22 # Default y-tick font size. Override via aplt.YTicks(fontsize=...).
23+
xticks:
24+
fontsize: 22 # Default x-tick font size. Override via aplt.XTicks(fontsize=...).
25+
title:
26+
fontsize: 24 # Default title font size. Override via aplt.Title(fontsize=...).
27+
ylabel:
28+
fontsize: 16 # Default y-label font size. Override via aplt.YLabel(fontsize=...).
29+
xlabel:
30+
fontsize: 16 # Default x-label font size. Override via aplt.XLabel(fontsize=...).

0 commit comments

Comments
 (0)