Skip to content

Commit 46ad2a7

Browse files
committed
Remove MatPlot1D/MatPlot2D from all PyAutoLens plotters; use output=/cmap=/use_log10= API
Replace mat_plot_2d=/mat_plot_1d= constructor arguments across all plotter classes with the simplified output=/cmap=/use_log10= API. Eliminates MultiFigurePlotter, MultiYX1DPlotter dependencies and all MatPlot wrapper objects throughout autolens. Key changes: - All Plotter subclasses (TracerPlotter, FitImagingPlotter, FitInterferometerPlotter, FitPointDatasetPlotter, PointDatasetPlotter, SubhaloPlotter, SubhaloSensitivityPlotter) now accept output=, cmap=, use_log10= directly - SubhaloPlotter: replaced update_mat_plot_array_overlay with direct array_overlay= arg to Array2DPlotter; subplot methods use plt.subplots + _save_subplot pattern - SubhaloSensitivityPlotter: same pattern, sensitivity_to_fits uses Output directly - plotter_interface.py files updated: output_from() call (no quick_update arg), subplot filename fixed to subplot_fit_combined - FitInterferometerPlotter: removed invalid subplot delegation to meta plotter - Fixed variable shadowing bug in figures_2d(ax=None) for point plotters: standalone flag captured before positions block to avoid ax rebinding affecting fluxes block - All test files updated from mat_plot_2d=aplt.MatPlot2D(output=...) to output=... https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k
1 parent 9a1ad05 commit 46ad2a7

17 files changed

Lines changed: 2407 additions & 3133 deletions
Lines changed: 184 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -1,184 +1,184 @@
1-
import ast
2-
import numpy as np
3-
from typing import Optional
4-
5-
from autoconf import conf
6-
from autoconf.fitsable import hdu_list_for_output_from
7-
8-
import autoarray as aa
9-
import autogalaxy as ag
10-
import autogalaxy.plot as aplt
11-
12-
from autogalaxy.analysis.plotter_interface import plot_setting
13-
14-
from autogalaxy.analysis.plotter_interface import PlotterInterface as AgPlotterInterface
15-
16-
from autolens.lens.tracer import Tracer
17-
from autolens.lens.plot.tracer_plotters import TracerPlotter
18-
19-
20-
class PlotterInterface(AgPlotterInterface):
21-
"""
22-
Visualizes the maximum log likelihood model of a model-fit, including components of the model and fit objects.
23-
24-
The methods of the `PlotterInterface` are called throughout a non-linear search using the `Analysis`
25-
classes `visualize` method.
26-
27-
The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml`.
28-
29-
Parameters
30-
----------
31-
image_path
32-
The path on the hard-disk to the `image` folder of the non-linear searches results.
33-
"""
34-
35-
def tracer(
36-
self,
37-
tracer: Tracer,
38-
grid: aa.type.Grid2DLike,
39-
):
40-
"""
41-
Visualizes a `Tracer` object.
42-
43-
Images are output to the `image` folder of the `image_path`. When used with a non-linear search the `image_path`
44-
points to the search's results folder and this function visualizes the maximum log likelihood `Tracer`
45-
inferred by the search so far.
46-
47-
Visualization includes a subplot of individual images of attributes of the tracer (e.g. its image, convergence,
48-
deflection angles) and .fits files containing its attributes grouped together.
49-
50-
The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml` under
51-
the `tracer` header.
52-
53-
Parameters
54-
----------
55-
tracer
56-
The maximum log likelihood `Tracer` of the non-linear search.
57-
grid
58-
A 2D grid of (y,x) arc-second coordinates used to perform ray-tracing, which is the masked grid tied to
59-
the dataset.
60-
"""
61-
62-
def should_plot(name):
63-
return plot_setting(section="tracer", name=name)
64-
65-
mat_plot_2d = self.mat_plot_2d_from()
66-
67-
tracer_plotter = TracerPlotter(
68-
tracer=tracer,
69-
grid=grid,
70-
mat_plot_2d=mat_plot_2d,
71-
)
72-
73-
if should_plot("subplot_galaxies_images"):
74-
tracer_plotter.subplot_galaxies_images()
75-
76-
if should_plot("fits_tracer"):
77-
78-
zoom = aa.Zoom2D(mask=grid.mask)
79-
mask = zoom.mask_2d_from(buffer=1)
80-
grid_zoom = aa.Grid2D.from_mask(mask=mask)
81-
82-
image_list = [
83-
tracer.convergence_2d_from(grid=grid_zoom).native,
84-
tracer.potential_2d_from(grid=grid_zoom).native,
85-
tracer.deflections_yx_2d_from(grid=grid_zoom).native[:, :, 0],
86-
tracer.deflections_yx_2d_from(grid=grid_zoom).native[:, :, 1],
87-
]
88-
89-
hdu_list = hdu_list_for_output_from(
90-
values_list=[image_list[0].mask.astype("float")] + image_list,
91-
ext_name_list=[
92-
"mask",
93-
"convergence",
94-
"potential",
95-
"deflections_y",
96-
"deflections_x",
97-
],
98-
header_dict=grid_zoom.mask.header_dict,
99-
)
100-
101-
hdu_list.writeto(self.image_path / "tracer.fits", overwrite=True)
102-
103-
if should_plot("fits_source_plane_images"):
104-
105-
shape_native = conf.instance["visualize"]["plots"]["tracer"][
106-
"fits_source_plane_shape"
107-
]
108-
shape_native = ast.literal_eval(shape_native)
109-
110-
zoom = aa.Zoom2D(mask=grid.mask)
111-
mask = zoom.mask_2d_from(buffer=1)
112-
grid_source_plane = aa.Grid2D.from_extent(
113-
extent=mask.geometry.extent, shape_native=tuple(shape_native)
114-
)
115-
116-
image_list = [grid_source_plane.mask.astype("float")]
117-
ext_name_list = ["mask"]
118-
119-
for i, plane in enumerate(tracer.planes[1:]):
120-
121-
if plane.has(cls=ag.LightProfile):
122-
123-
image = plane.image_2d_from(
124-
grid=grid_source_plane,
125-
).native
126-
127-
else:
128-
129-
image = np.zeros(grid_source_plane.shape_native)
130-
131-
image_list.append(image)
132-
ext_name_list.append(f"source_plane_image_{i+1}")
133-
134-
hdu_list = hdu_list_for_output_from(
135-
values_list=image_list,
136-
ext_name_list=ext_name_list,
137-
header_dict=grid_source_plane.mask.header_dict,
138-
)
139-
140-
hdu_list.writeto(
141-
self.image_path / "source_plane_images.fits", overwrite=True
142-
)
143-
144-
def image_with_positions(self, image: aa.Array2D, positions: aa.Grid2DIrregular):
145-
"""
146-
Visualizes the positions of a model-fit, where these positions are used to penalize lens models where
147-
the positions to do trace within an input threshold of one another in the source-plane.
148-
149-
Images are output to the `image` folder of the `image_path`. When used with a non-linear search the `image_path`
150-
is the output folder of the non-linear search.
151-
152-
The visualization is an image of the strong lens with the positions overlaid.
153-
154-
The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml` under the
155-
`positions` header.
156-
157-
Parameters
158-
----------
159-
imaging
160-
The imaging dataset whose image the positions are overlaid.
161-
positions
162-
The 2D (y,x) arc-second positions used to penalize inaccurate mass models.
163-
"""
164-
165-
def should_plot(name):
166-
return plot_setting(section=["positions"], name=name)
167-
168-
mat_plot_2d = self.mat_plot_2d_from()
169-
170-
if positions is not None:
171-
pos_arr = np.array(
172-
positions.array if hasattr(positions, "array") else positions
173-
)
174-
175-
image_plotter = aplt.Array2DPlotter(
176-
array=image,
177-
mat_plot_2d=mat_plot_2d,
178-
positions=[pos_arr],
179-
)
180-
181-
image_plotter.set_filename("image_with_positions")
182-
183-
if should_plot("image_with_positions"):
184-
image_plotter.figure_2d()
1+
import ast
2+
import numpy as np
3+
from typing import Optional
4+
5+
from autoconf import conf
6+
from autoconf.fitsable import hdu_list_for_output_from
7+
8+
import autoarray as aa
9+
import autogalaxy as ag
10+
import autogalaxy.plot as aplt
11+
12+
from autogalaxy.analysis.plotter_interface import plot_setting
13+
14+
from autogalaxy.analysis.plotter_interface import PlotterInterface as AgPlotterInterface
15+
16+
from autolens.lens.tracer import Tracer
17+
from autolens.lens.plot.tracer_plotters import TracerPlotter
18+
19+
20+
class PlotterInterface(AgPlotterInterface):
21+
"""
22+
Visualizes the maximum log likelihood model of a model-fit, including components of the model and fit objects.
23+
24+
The methods of the `PlotterInterface` are called throughout a non-linear search using the `Analysis`
25+
classes `visualize` method.
26+
27+
The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml`.
28+
29+
Parameters
30+
----------
31+
image_path
32+
The path on the hard-disk to the `image` folder of the non-linear searches results.
33+
"""
34+
35+
def tracer(
36+
self,
37+
tracer: Tracer,
38+
grid: aa.type.Grid2DLike,
39+
):
40+
"""
41+
Visualizes a `Tracer` object.
42+
43+
Images are output to the `image` folder of the `image_path`. When used with a non-linear search the `image_path`
44+
points to the search's results folder and this function visualizes the maximum log likelihood `Tracer`
45+
inferred by the search so far.
46+
47+
Visualization includes a subplot of individual images of attributes of the tracer (e.g. its image, convergence,
48+
deflection angles) and .fits files containing its attributes grouped together.
49+
50+
The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml` under
51+
the `tracer` header.
52+
53+
Parameters
54+
----------
55+
tracer
56+
The maximum log likelihood `Tracer` of the non-linear search.
57+
grid
58+
A 2D grid of (y,x) arc-second coordinates used to perform ray-tracing, which is the masked grid tied to
59+
the dataset.
60+
"""
61+
62+
def should_plot(name):
63+
return plot_setting(section="tracer", name=name)
64+
65+
output = self.output_from()
66+
67+
tracer_plotter = TracerPlotter(
68+
tracer=tracer,
69+
grid=grid,
70+
output=output,
71+
)
72+
73+
if should_plot("subplot_galaxies_images"):
74+
tracer_plotter.subplot_galaxies_images()
75+
76+
if should_plot("fits_tracer"):
77+
78+
zoom = aa.Zoom2D(mask=grid.mask)
79+
mask = zoom.mask_2d_from(buffer=1)
80+
grid_zoom = aa.Grid2D.from_mask(mask=mask)
81+
82+
image_list = [
83+
tracer.convergence_2d_from(grid=grid_zoom).native,
84+
tracer.potential_2d_from(grid=grid_zoom).native,
85+
tracer.deflections_yx_2d_from(grid=grid_zoom).native[:, :, 0],
86+
tracer.deflections_yx_2d_from(grid=grid_zoom).native[:, :, 1],
87+
]
88+
89+
hdu_list = hdu_list_for_output_from(
90+
values_list=[image_list[0].mask.astype("float")] + image_list,
91+
ext_name_list=[
92+
"mask",
93+
"convergence",
94+
"potential",
95+
"deflections_y",
96+
"deflections_x",
97+
],
98+
header_dict=grid_zoom.mask.header_dict,
99+
)
100+
101+
hdu_list.writeto(self.image_path / "tracer.fits", overwrite=True)
102+
103+
if should_plot("fits_source_plane_images"):
104+
105+
shape_native = conf.instance["visualize"]["plots"]["tracer"][
106+
"fits_source_plane_shape"
107+
]
108+
shape_native = ast.literal_eval(shape_native)
109+
110+
zoom = aa.Zoom2D(mask=grid.mask)
111+
mask = zoom.mask_2d_from(buffer=1)
112+
grid_source_plane = aa.Grid2D.from_extent(
113+
extent=mask.geometry.extent, shape_native=tuple(shape_native)
114+
)
115+
116+
image_list = [grid_source_plane.mask.astype("float")]
117+
ext_name_list = ["mask"]
118+
119+
for i, plane in enumerate(tracer.planes[1:]):
120+
121+
if plane.has(cls=ag.LightProfile):
122+
123+
image = plane.image_2d_from(
124+
grid=grid_source_plane,
125+
).native
126+
127+
else:
128+
129+
image = np.zeros(grid_source_plane.shape_native)
130+
131+
image_list.append(image)
132+
ext_name_list.append(f"source_plane_image_{i+1}")
133+
134+
hdu_list = hdu_list_for_output_from(
135+
values_list=image_list,
136+
ext_name_list=ext_name_list,
137+
header_dict=grid_source_plane.mask.header_dict,
138+
)
139+
140+
hdu_list.writeto(
141+
self.image_path / "source_plane_images.fits", overwrite=True
142+
)
143+
144+
def image_with_positions(self, image: aa.Array2D, positions: aa.Grid2DIrregular):
145+
"""
146+
Visualizes the positions of a model-fit, where these positions are used to penalize lens models where
147+
the positions to do trace within an input threshold of one another in the source-plane.
148+
149+
Images are output to the `image` folder of the `image_path`. When used with a non-linear search the `image_path`
150+
is the output folder of the non-linear search.
151+
152+
The visualization is an image of the strong lens with the positions overlaid.
153+
154+
The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml` under the
155+
`positions` header.
156+
157+
Parameters
158+
----------
159+
imaging
160+
The imaging dataset whose image the positions are overlaid.
161+
positions
162+
The 2D (y,x) arc-second positions used to penalize inaccurate mass models.
163+
"""
164+
165+
def should_plot(name):
166+
return plot_setting(section=["positions"], name=name)
167+
168+
output = self.output_from()
169+
170+
if positions is not None:
171+
pos_arr = np.array(
172+
positions.array if hasattr(positions, "array") else positions
173+
)
174+
175+
image_plotter = aplt.Array2DPlotter(
176+
array=image,
177+
output=output,
178+
positions=[pos_arr],
179+
)
180+
181+
image_plotter.set_filename("image_with_positions")
182+
183+
if should_plot("image_with_positions"):
184+
image_plotter.figure_2d()

0 commit comments

Comments
 (0)