From be84d80a94eb066bb7c8c12c93d424125a958382 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Wed, 25 Mar 2026 12:05:54 +0000 Subject: [PATCH 1/2] fixes to plotting --- PLOT_REFACTOR_PLAN.md | 24 +-- autolens/imaging/plot/fit_imaging_plots.py | 2 +- autolens/plot/__init__.py | 2 +- docs/index.rst | 2 +- ...all-autoarray-plotters-to-use-direct.patch | 148 ++++++------- ...t_plot_2d.plot_array-in-FitImagingPl.patch | 54 ++--- ...-mat_plot_2d.plot_array-with-_plot_a.patch | 202 +++++++++--------- 7 files changed, 217 insertions(+), 217 deletions(-) diff --git a/PLOT_REFACTOR_PLAN.md b/PLOT_REFACTOR_PLAN.md index 00ca380f0..0aff33bef 100644 --- a/PLOT_REFACTOR_PLAN.md +++ b/PLOT_REFACTOR_PLAN.md @@ -46,7 +46,7 @@ Problems: describes the workaround as a "nasty hack" - The config system switches every wrap object between `figure:` and `subplot:` sections based on whether `subplot_index is not None`, adding hidden state to every config lookup -- Nested plotters (FitImagingPlotter → TracerPlotter → InversionPlotter) share one +- Nested plotters (FitImaging → Tracer → InversionPlotter) share one mat_plot object so their indices accumulate in the same global counter The fix is to use matplotlib's native `plt.subplots()` and pass `ax` objects directly. @@ -272,7 +272,7 @@ constructor accepts `output_path` and `output_filename` strings. --- -#### PR A3 · Update `ImagingPlotter`, `InversionPlotter`, `MapperPlotter`, `InterferometerPlotter` +#### PR A3 · Update `Imaging`, `InversionPlotter`, `MapperPlotter`, `Interferometer` Same `ax`-passing pattern. Mixed 1D/2D subplots (e.g. interferometer) use: @@ -365,13 +365,13 @@ They have no config dependency. --- -#### PR G2 · Update `LightProfilePlotter`, `MassProfilePlotter`, `GalaxyPlotter`, `GalaxiesPlotter` +#### PR G2 · Update `LightProfile`, `MassProfilePlotter`, `Galaxy`, `Galaxies` Each plotter computes its own overlay data from its galaxy/profile then passes it to `plot_array`: ```python -class GalaxiesPlotter(AbstractPlotter): +class Galaxies(AbstractPlotter): def figure_image(self, ax=None): owns = ax is None if owns: @@ -390,7 +390,7 @@ Remove autogalaxy `MatPlot2D` subclass and autogalaxy `Visuals2D` subclass. --- -#### PR G3 · Update autogalaxy `FitImagingPlotter` and `FitInterferometerPlotter` +#### PR G3 · Update autogalaxy `FitImaging` and `FitInterferometer` ```python def subplot_fit(self): @@ -420,13 +420,13 @@ Update `autogalaxy/plot/__init__.py`. --- -#### PR L1 · Update `TracerPlotter` +#### PR L1 · Update `Tracer` The plotter computes critical curves / caustics itself from the tracer, then passes them as `lines` to `plot_array`: ```python -class TracerPlotter(AbstractPlotter): +class Tracer(AbstractPlotter): def figure_convergence(self, ax=None): owns = ax is None if owns: @@ -464,7 +464,7 @@ Add `show_critical_curves: bool = True`, `show_caustics: bool = True`. --- -#### PR L2 · Update `FitImagingPlotter` +#### PR L2 · Update `FitImaging` Largest single plotter. The 12-panel `subplot_fit` becomes: @@ -511,7 +511,7 @@ def subplot_of_planes(self): --- -#### PR L3 · Update `FitInterferometerPlotter`, `PointDatasetPlotter`, `FitPointDatasetPlotter` +#### PR L3 · Update `FitInterferometer`, `PointDatasetPlotter`, `FitPointDatasetPlotter` **PointDatasetPlotter** — mixed 1D/2D, which was the "nasty hack" case: @@ -566,15 +566,15 @@ plot_array( |---|---|---|---| | A1 | autoarray | Add `plots/` module | New unit tests | | A2 | autoarray | Rewrite Array2D/Grid2DPlotter | Update existing | -| A3 | autoarray | Rewrite Imaging/Inversion/Mapper/InterferometerPlotter | Update existing | +| A3 | autoarray | Rewrite Imaging/Inversion/Mapper/Interferometer | Update existing | | A4 | autoarray | Delete mat_plot/, wrap/, visuals/ | Delete wrap tests | | A5 | autoarray | Config cleanup, finalise helpers | Smoke tests | | G1 | autogalaxy | Add overlay helpers | New unit tests | | G2 | autogalaxy | Rewrite Galaxy/Mass/LightProfile plotters | Update existing | | G3 | autogalaxy | Rewrite FitImaging/FitInterferometer plotters | Update existing | | G4 | autogalaxy | Delete MatPlot2D/Visuals2D extensions | Delete wrap tests | -| L1 | autolens | Rewrite TracerPlotter | Update existing | -| L2 | autolens | Rewrite FitImagingPlotter | Update existing | +| L1 | autolens | Rewrite Tracer | Update existing | +| L2 | autolens | Rewrite FitImaging | Update existing | | L3 | autolens | Rewrite FitInterferometer/Point plotters | Update existing | | L4 | autolens | Rewrite Subhalo plotters, clean abstract_plotters | Update existing | diff --git a/autolens/imaging/plot/fit_imaging_plots.py b/autolens/imaging/plot/fit_imaging_plots.py index 5e60443a7..934f07f8e 100644 --- a/autolens/imaging/plot/fit_imaging_plots.py +++ b/autolens/imaging/plot/fit_imaging_plots.py @@ -581,7 +581,7 @@ def subplot_tracer_from_fit( ) tan_cc, rad_cc = _critical_curves_from(tracer, grid) - image_plane_lines = _to_lines(list(tan_cc) + list(rad_cc)) + image_plane_lines = _to_lines(list(tan_cc) + (list(rad_cc) if rad_cc is not None else [])) traced_grids = tracer.traced_grid_2d_list_from(grid=grid) lens_galaxies = ag.Galaxies(galaxies=tracer.planes[0]) diff --git a/autolens/plot/__init__.py b/autolens/plot/__init__.py index f1f26923c..14c29ba46 100644 --- a/autolens/plot/__init__.py +++ b/autolens/plot/__init__.py @@ -9,7 +9,7 @@ from autoarray.plot.grid import plot_grid from autoarray.dataset.plot.imaging_plots import ( - subplot_imaging, + subplot_imaging_dataset, subplot_imaging_dataset_list, ) from autoarray.dataset.plot.interferometer_plots import subplot_interferometer_dirty_images diff --git a/docs/index.rst b/docs/index.rst index 721e2d812..651d49b8d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -109,7 +109,7 @@ below shows this in action: We can use the Grid2D and Tracer to perform many lensing calculations, for example plotting the image of the lensed source. """ - tracer_plotter = aplt.TracerPlotter(tracer=tracer, grid=grid) + tracer_plotter = aplt.Tracer(tracer=tracer, grid=grid) tracer_plotter.figures_2d(image=True) To perform lens modeling, **PyAutoLens** adopts the probabilistic programming diff --git a/patches/autoarray/0002-PR-A2-A3-Switch-all-autoarray-plotters-to-use-direct.patch b/patches/autoarray/0002-PR-A2-A3-Switch-all-autoarray-plotters-to-use-direct.patch index d5736e18e..1952fe1c7 100644 --- a/patches/autoarray/0002-PR-A2-A3-Switch-all-autoarray-plotters-to-use-direct.patch +++ b/patches/autoarray/0002-PR-A2-A3-Switch-all-autoarray-plotters-to-use-direct.patch @@ -1,41 +1,41 @@ -From 9c1ab66b47873a906733f393d04e87ea25254c49 Mon Sep 17 00:00:00 2001 -From: Claude -Date: Mon, 16 Mar 2026 14:19:37 +0000 -Subject: [PATCH 2/3] PR A2+A3: Switch all autoarray plotters to use - direct-matplotlib functions - -Array2DPlotter, Grid2DPlotter, YX1DPlotter (structure_plotters.py): -- figure_2d() / figure_1d() now call plot_array() / plot_grid() / plot_yx() -- Subplot mode bridged: setup_subplot() positions the panel, ax passed to plot fn -- Overlay data extracted from Visuals2D to typed numpy arrays via helpers -- _output_for_mat_plot() bridges mat_plot.output to path/filename/format args - -ImagingPlotterMeta (imaging_plotters.py): -- figures_2d() uses new _plot_array() helper calling plot_array() directly -- subplot_dataset() unchanged: open/close subplot still via old mechanism - -MapperPlotter (mapper_plotters.py): -- figure_2d(), figure_2d_image(), plot_source_from() use plot_inversion_reconstruction() - and plot_array() respectively - -InversionPlotter (inversion_plotters.py): -- Added _plot_array() helper; all mat_plot_2d.plot_array() calls replaced - -All integration tests pass. - -https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k ---- - autoarray/dataset/plot/imaging_plotters.py | 192 ++++-------- - .../inversion/plot/inversion_plotters.py | 113 +++---- - autoarray/inversion/plot/mapper_plotters.py | 157 +++++----- - .../structures/plot/structure_plotters.py | 277 +++++++++++------- - 4 files changed, 374 insertions(+), 365 deletions(-) - -diff --git a/autoarray/dataset/plot/imaging_plotters.py b/autoarray/dataset/plot/imaging_plotters.py -index ac1f23de..afc2cff5 100644 ---- a/autoarray/dataset/plot/imaging_plotters.py -+++ b/autoarray/dataset/plot/imaging_plotters.py -@@ -1,10 +1,19 @@ +From 9c1ab66b47873a906733f393d04e87ea25254c49 Mon Sep 17 00:00:00 2001 +From: Claude +Date: Mon, 16 Mar 2026 14:19:37 +0000 +Subject: [PATCH 2/3] PR A2+A3: Switch all autoarray plotters to use + direct-matplotlib functions + +Array2DPlotter, Grid2DPlotter, YX1DPlotter (structure_plotters.py): +- figure_2d() / figure_1d() now call plot_array() / plot_grid() / plot_yx() +- Subplot mode bridged: setup_subplot() positions the panel, ax passed to plot fn +- Overlay data extracted from Visuals2D to typed numpy arrays via helpers +- _output_for_mat_plot() bridges mat_plot.output to path/filename/format args + +ImagingMeta (imaging_plotters.py): +- figures_2d() uses new _plot_array() helper calling plot_array() directly +- subplot_dataset() unchanged: open/close subplot still via old mechanism + +MapperPlotter (mapper_plotters.py): +- figure_2d(), figure_2d_image(), plot_source_from() use plot_inversion_reconstruction() + and plot_array() respectively + +InversionPlotter (inversion_plotters.py): +- Added _plot_array() helper; all mat_plot_2d.plot_array() calls replaced + +All integration tests pass. + +https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k +--- + autoarray/dataset/plot/imaging_plotters.py | 192 ++++-------- + .../inversion/plot/inversion_plotters.py | 113 +++---- + autoarray/inversion/plot/mapper_plotters.py | 157 +++++----- + .../structures/plot/structure_plotters.py | 277 +++++++++++------- + 4 files changed, 374 insertions(+), 365 deletions(-) + +diff --git a/autoarray/dataset/plot/imaging_plotters.py b/autoarray/dataset/plot/imaging_plotters.py +index ac1f23de..afc2cff5 100644 +--- a/autoarray/dataset/plot/imaging_plotters.py ++++ b/autoarray/dataset/plot/imaging_plotters.py +@@ -1,10 +1,19 @@ import copy +import numpy as np from typing import Callable, Optional @@ -55,7 +55,7 @@ index ac1f23de..afc2cff5 100644 from autoarray.dataset.imaging.dataset import Imaging -@@ -15,35 +24,49 @@ class ImagingPlotterMeta(AbstractPlotter): +@@ -15,35 +24,49 @@ class ImagingMeta(AbstractPlotter): mat_plot_2d: MatPlot2D = None, visuals_2d: Visuals2D = None, ): @@ -127,7 +127,7 @@ index ac1f23de..afc2cff5 100644 def figures_2d( self, data: bool = False, -@@ -54,86 +77,47 @@ class ImagingPlotterMeta(AbstractPlotter): +@@ -54,86 +77,47 @@ class ImagingMeta(AbstractPlotter): over_sample_size_pixelization: bool = False, title_str: Optional[str] = None, ): @@ -232,7 +232,7 @@ index ac1f23de..afc2cff5 100644 ) def subplot( -@@ -146,30 +130,6 @@ class ImagingPlotterMeta(AbstractPlotter): +@@ -146,30 +130,6 @@ class ImagingMeta(AbstractPlotter): over_sampling_pixelization: bool = False, auto_filename: str = "subplot_dataset", ): @@ -263,7 +263,7 @@ index ac1f23de..afc2cff5 100644 self._subplot_custom_plot( data=data, noise_map=noise_map, -@@ -181,9 +141,6 @@ class ImagingPlotterMeta(AbstractPlotter): +@@ -181,9 +141,6 @@ class ImagingMeta(AbstractPlotter): ) def subplot_dataset(self): @@ -273,7 +273,7 @@ index ac1f23de..afc2cff5 100644 use_log10_original = self.mat_plot_2d.use_log10 self.open_subplot_figure(number_subplots=9) -@@ -199,7 +156,6 @@ class ImagingPlotterMeta(AbstractPlotter): +@@ -199,7 +156,6 @@ class ImagingMeta(AbstractPlotter): self.mat_plot_2d.contour = contour_original self.figures_2d(noise_map=True) @@ -281,7 +281,7 @@ index ac1f23de..afc2cff5 100644 self.figures_2d(psf=True) self.mat_plot_2d.use_log10 = True -@@ -207,7 +163,6 @@ class ImagingPlotterMeta(AbstractPlotter): +@@ -207,7 +163,6 @@ class ImagingMeta(AbstractPlotter): self.mat_plot_2d.use_log10 = False self.figures_2d(signal_to_noise_map=True) @@ -289,7 +289,7 @@ index ac1f23de..afc2cff5 100644 self.figures_2d(over_sample_size_lp=True) self.figures_2d(over_sample_size_pixelization=True) -@@ -224,27 +179,6 @@ class ImagingPlotter(AbstractPlotter): +@@ -224,27 +179,6 @@ class Imaging(AbstractPlotter): mat_plot_2d: MatPlot2D = None, visuals_2d: Visuals2D = None, ): @@ -317,11 +317,11 @@ index ac1f23de..afc2cff5 100644 super().__init__(mat_plot_2d=mat_plot_2d, visuals_2d=visuals_2d) self.dataset = dataset -diff --git a/autoarray/inversion/plot/inversion_plotters.py b/autoarray/inversion/plot/inversion_plotters.py -index ef2ae6ea..586eabc7 100644 ---- a/autoarray/inversion/plot/inversion_plotters.py -+++ b/autoarray/inversion/plot/inversion_plotters.py -@@ -7,9 +7,17 @@ from autoarray.plot.abstract_plotters import AbstractPlotter +diff --git a/autoarray/inversion/plot/inversion_plotters.py b/autoarray/inversion/plot/inversion_plotters.py +index ef2ae6ea..586eabc7 100644 +--- a/autoarray/inversion/plot/inversion_plotters.py ++++ b/autoarray/inversion/plot/inversion_plotters.py +@@ -7,9 +7,17 @@ from autoarray.plot.abstract_plotters import AbstractPlotter from autoarray.plot.visuals.two_d import Visuals2D from autoarray.plot.mat_plot.two_d import MatPlot2D from autoarray.plot.auto_labels import AutoLabels @@ -339,7 +339,7 @@ index ef2ae6ea..586eabc7 100644 class InversionPlotter(AbstractPlotter): -@@ -66,35 +74,53 @@ class InversionPlotter(AbstractPlotter): +@@ -66,35 +74,53 @@ class InversionPlotter(AbstractPlotter): visuals_2d=self.visuals_2d, ) @@ -412,7 +412,7 @@ index ef2ae6ea..586eabc7 100644 ) def figures_2d_of_pixelization( -@@ -153,19 +179,13 @@ class InversionPlotter(AbstractPlotter): +@@ -153,19 +179,13 @@ class InversionPlotter(AbstractPlotter): mapper_plotter = self.mapper_plotter_from(mapper_index=pixelization_index) if data_subtracted: @@ -436,7 +436,7 @@ index ef2ae6ea..586eabc7 100644 ) except AttributeError: pass -@@ -182,13 +202,10 @@ class InversionPlotter(AbstractPlotter): +@@ -182,13 +202,10 @@ class InversionPlotter(AbstractPlotter): mapper_plotter.mapper ] @@ -453,7 +453,7 @@ index ef2ae6ea..586eabc7 100644 ) if reconstruction: -@@ -271,29 +288,19 @@ class InversionPlotter(AbstractPlotter): +@@ -271,29 +288,19 @@ class InversionPlotter(AbstractPlotter): values=mapper_plotter.mapper.over_sampler.sub_size, mask=self.inversion.dataset.mask, ) @@ -491,11 +491,11 @@ index ef2ae6ea..586eabc7 100644 ) except Exception: pass -diff --git a/autoarray/inversion/plot/mapper_plotters.py b/autoarray/inversion/plot/mapper_plotters.py -index b9a44679..47617e1e 100644 ---- a/autoarray/inversion/plot/mapper_plotters.py -+++ b/autoarray/inversion/plot/mapper_plotters.py -@@ -1,12 +1,20 @@ +diff --git a/autoarray/inversion/plot/mapper_plotters.py b/autoarray/inversion/plot/mapper_plotters.py +index b9a44679..47617e1e 100644 +--- a/autoarray/inversion/plot/mapper_plotters.py ++++ b/autoarray/inversion/plot/mapper_plotters.py +@@ -1,12 +1,20 @@ import numpy as np +import logging @@ -518,7 +518,7 @@ index b9a44679..47617e1e 100644 logger = logging.getLogger(__name__) -@@ -18,80 +26,70 @@ class MapperPlotter(AbstractPlotter): +@@ -18,80 +26,70 @@ class MapperPlotter(AbstractPlotter): mat_plot_2d: MatPlot2D = None, visuals_2d: Visuals2D = None, ): @@ -649,7 +649,7 @@ index b9a44679..47617e1e 100644 self.mat_plot_2d.output.subplot_to_figure( auto_filename="subplot_image_and_mapper" ) -@@ -103,26 +101,29 @@ class MapperPlotter(AbstractPlotter): +@@ -103,26 +101,29 @@ class MapperPlotter(AbstractPlotter): zoom_to_brightest: bool = True, auto_labels: AutoLabels = AutoLabels(), ): @@ -695,11 +695,11 @@ index b9a44679..47617e1e 100644 ) except ValueError: logger.info( -diff --git a/autoarray/structures/plot/structure_plotters.py b/autoarray/structures/plot/structure_plotters.py -index 7e7cf655..e05c19f9 100644 ---- a/autoarray/structures/plot/structure_plotters.py -+++ b/autoarray/structures/plot/structure_plotters.py -@@ -7,12 +7,115 @@ from autoarray.plot.visuals.two_d import Visuals2D +diff --git a/autoarray/structures/plot/structure_plotters.py b/autoarray/structures/plot/structure_plotters.py +index 7e7cf655..e05c19f9 100644 +--- a/autoarray/structures/plot/structure_plotters.py ++++ b/autoarray/structures/plot/structure_plotters.py +@@ -7,12 +7,115 @@ from autoarray.plot.visuals.two_d import Visuals2D from autoarray.plot.mat_plot.one_d import MatPlot1D from autoarray.plot.mat_plot.two_d import MatPlot2D from autoarray.plot.auto_labels import AutoLabels @@ -815,7 +815,7 @@ index 7e7cf655..e05c19f9 100644 class Array2DPlotter(AbstractPlotter): def __init__( self, -@@ -20,38 +123,35 @@ class Array2DPlotter(AbstractPlotter): +@@ -20,38 +123,35 @@ class Array2DPlotter(AbstractPlotter): mat_plot_2d: MatPlot2D = None, visuals_2d: Visuals2D = None, ): @@ -879,7 +879,7 @@ index 7e7cf655..e05c19f9 100644 ) -@@ -62,28 +162,7 @@ class Grid2DPlotter(AbstractPlotter): +@@ -62,28 +162,7 @@ class Grid2DPlotter(AbstractPlotter): mat_plot_2d: MatPlot2D = None, visuals_2d: Visuals2D = None, ): @@ -908,7 +908,7 @@ index 7e7cf655..e05c19f9 100644 self.grid = grid def figure_2d( -@@ -92,27 +171,24 @@ class Grid2DPlotter(AbstractPlotter): +@@ -92,27 +171,24 @@ class Grid2DPlotter(AbstractPlotter): plot_grid_lines: bool = False, plot_over_sampled_grid: bool = False, ): @@ -953,7 +953,7 @@ index 7e7cf655..e05c19f9 100644 ) -@@ -129,29 +205,6 @@ class YX1DPlotter(AbstractPlotter): +@@ -129,29 +205,6 @@ class YX1DPlotter(AbstractPlotter): plot_yx_dict=None, auto_labels=AutoLabels(), ): @@ -983,7 +983,7 @@ index 7e7cf655..e05c19f9 100644 if isinstance(y, list): y = Array1D.no_mask(values=y, pixel_scales=1.0) -@@ -169,17 +222,31 @@ class YX1DPlotter(AbstractPlotter): +@@ -169,17 +222,31 @@ class YX1DPlotter(AbstractPlotter): self.auto_labels = auto_labels def figure_1d(self): @@ -1028,6 +1028,6 @@ index 7e7cf655..e05c19f9 100644 + output_filename=filename, + output_format=fmt, ) --- -2.43.0 - +-- +2.43.0 + diff --git a/patches/autoarray/0003-PR-A3-replace-mat_plot_2d.plot_array-in-FitImagingPl.patch b/patches/autoarray/0003-PR-A3-replace-mat_plot_2d.plot_array-in-FitImagingPl.patch index f41d9d003..019e489b8 100644 --- a/patches/autoarray/0003-PR-A3-replace-mat_plot_2d.plot_array-in-FitImagingPl.patch +++ b/patches/autoarray/0003-PR-A3-replace-mat_plot_2d.plot_array-in-FitImagingPl.patch @@ -1,23 +1,23 @@ -From ebbb315cdd0eee0a3cc4e7c2ea0600859cc95330 Mon Sep 17 00:00:00 2001 -From: Claude -Date: Mon, 16 Mar 2026 17:31:52 +0000 -Subject: [PATCH 3/3] PR A3: replace mat_plot_2d.plot_array in - FitImagingPlotterMeta with plot_array() - -Bridge FitImagingPlotterMeta.figures_2d() to use the new direct-matplotlib -plot_array() function via a _plot_array() helper method, eliminating the -MatWrap system for fit imaging plots. - -https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k ---- - autoarray/fit/plot/fit_imaging_plotters.py | 72 +++++++++++++++++----- - 1 file changed, 55 insertions(+), 17 deletions(-) - -diff --git a/autoarray/fit/plot/fit_imaging_plotters.py b/autoarray/fit/plot/fit_imaging_plotters.py -index 86aa0d34..20552945 100644 ---- a/autoarray/fit/plot/fit_imaging_plotters.py -+++ b/autoarray/fit/plot/fit_imaging_plotters.py -@@ -1,10 +1,19 @@ +From ebbb315cdd0eee0a3cc4e7c2ea0600859cc95330 Mon Sep 17 00:00:00 2001 +From: Claude +Date: Mon, 16 Mar 2026 17:31:52 +0000 +Subject: [PATCH 3/3] PR A3: replace mat_plot_2d.plot_array in + FitImagingMeta with plot_array() + +Bridge FitImagingMeta.figures_2d() to use the new direct-matplotlib +plot_array() function via a _plot_array() helper method, eliminating the +MatWrap system for fit imaging plots. + +https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k +--- + autoarray/fit/plot/fit_imaging_plotters.py | 72 +++++++++++++++++----- + 1 file changed, 55 insertions(+), 17 deletions(-) + +diff --git a/autoarray/fit/plot/fit_imaging_plotters.py b/autoarray/fit/plot/fit_imaging_plotters.py +index 86aa0d34..20552945 100644 +--- a/autoarray/fit/plot/fit_imaging_plotters.py ++++ b/autoarray/fit/plot/fit_imaging_plotters.py +@@ -1,10 +1,19 @@ +import numpy as np from typing import Callable @@ -36,8 +36,8 @@ index 86aa0d34..20552945 100644 +) - class FitImagingPlotterMeta(AbstractPlotter): -@@ -43,6 +52,44 @@ class FitImagingPlotterMeta(AbstractPlotter): + class FitImagingMeta(AbstractPlotter): +@@ -43,6 +52,44 @@ class FitImagingMeta(AbstractPlotter): self.fit = fit self.residuals_symmetric_cmap = residuals_symmetric_cmap @@ -82,7 +82,7 @@ index 86aa0d34..20552945 100644 def figures_2d( self, data: bool = False, -@@ -82,57 +129,50 @@ class FitImagingPlotterMeta(AbstractPlotter): +@@ -82,57 +129,50 @@ class FitImagingMeta(AbstractPlotter): """ if data: @@ -146,7 +146,7 @@ index 86aa0d34..20552945 100644 auto_labels=AutoLabels( title="Normalized Residual Map", filename=f"normalized_residual_map{suffix}", -@@ -142,18 +182,16 @@ class FitImagingPlotterMeta(AbstractPlotter): +@@ -142,18 +182,16 @@ class FitImagingMeta(AbstractPlotter): self.mat_plot_2d.cmap = cmap_original if chi_squared_map: @@ -167,6 +167,6 @@ index 86aa0d34..20552945 100644 auto_labels=AutoLabels( title="Residual Flux Fraction Map", filename=f"residual_flux_fraction_map{suffix}", --- -2.43.0 - +-- +2.43.0 + diff --git a/patches/autogalaxy/0001-PR-G1-G2-replace-mat_plot_2d.plot_array-with-_plot_a.patch b/patches/autogalaxy/0001-PR-G1-G2-replace-mat_plot_2d.plot_array-with-_plot_a.patch index 22f7069d7..de7542f3a 100644 --- a/patches/autogalaxy/0001-PR-G1-G2-replace-mat_plot_2d.plot_array-with-_plot_a.patch +++ b/patches/autogalaxy/0001-PR-G1-G2-replace-mat_plot_2d.plot_array-with-_plot_a.patch @@ -1,40 +1,40 @@ -From 01763ab468688ef6222694f14dbc073755ac268f Mon Sep 17 00:00:00 2001 -From: Claude -Date: Mon, 16 Mar 2026 17:32:12 +0000 -Subject: [PATCH] PR G1-G2: replace mat_plot_2d.plot_array with _plot_array() - bridge in all plotters - -- Add autogalaxy/plot/plots/overlays.py with helpers to extract critical - curves, caustics, and profile centres from Visuals2D as plain arrays -- Add _plot_array() and _plot_grid() bridge methods to the Plotter base class - that route to the new direct-matplotlib plot_array()/plot_grid() functions -- Update all autogalaxy plotters to use self._plot_array() instead of - self.mat_plot_2d.plot_array(), covering: LightProfilePlotter, BasisPlotter, - MassPlotter, GalaxyPlotter, GalaxiesPlotter, AdaptPlotter, - FitImagingPlotter, FitEllipsePlotter, FitEllipsePDFPlotter - -https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k ---- - .../ellipse/plot/fit_ellipse_plotters.py | 4 +- - autogalaxy/galaxy/plot/adapt_plotters.py | 4 +- - autogalaxy/galaxy/plot/galaxies_plotters.py | 6 +- - autogalaxy/galaxy/plot/galaxy_plotters.py | 2 +- - .../imaging/plot/fit_imaging_plotters.py | 11 +-- - autogalaxy/plot/abstract_plotters.py | 80 +++++++++++++++ - autogalaxy/plot/mass_plotter.py | 15 +-- - autogalaxy/plot/plots/__init__.py | 6 ++ - autogalaxy/plot/plots/overlays.py | 98 +++++++++++++++++++ - autogalaxy/profiles/plot/basis_plotters.py | 2 +- - .../profiles/plot/light_profile_plotters.py | 2 +- - 11 files changed, 201 insertions(+), 29 deletions(-) - create mode 100644 autogalaxy/plot/plots/__init__.py - create mode 100644 autogalaxy/plot/plots/overlays.py - -diff --git a/autogalaxy/ellipse/plot/fit_ellipse_plotters.py b/autogalaxy/ellipse/plot/fit_ellipse_plotters.py -index 0bb67a21..0506f810 100644 ---- a/autogalaxy/ellipse/plot/fit_ellipse_plotters.py -+++ b/autogalaxy/ellipse/plot/fit_ellipse_plotters.py -@@ -89,7 +89,7 @@ class FitEllipsePlotter(Plotter): +From 01763ab468688ef6222694f14dbc073755ac268f Mon Sep 17 00:00:00 2001 +From: Claude +Date: Mon, 16 Mar 2026 17:32:12 +0000 +Subject: [PATCH] PR G1-G2: replace mat_plot_2d.plot_array with _plot_array() + bridge in all plotters + +- Add autogalaxy/plot/plots/overlays.py with helpers to extract critical + curves, caustics, and profile centres from Visuals2D as plain arrays +- Add _plot_array() and _plot_grid() bridge methods to the Plotter base class + that route to the new direct-matplotlib plot_array()/plot_grid() functions +- Update all autogalaxy plotters to use self._plot_array() instead of + self.mat_plot_2d.plot_array(), covering: LightProfile, BasisPlotter, + MassPlotter, Galaxy, Galaxies, AdaptPlotter, + FitImaging, FitEllipsePlotter, FitEllipsePDFPlotter + +https://claude.ai/code/session_01CzJBy8KvFXiNchoNdk5i9k +--- + .../ellipse/plot/fit_ellipse_plotters.py | 4 +- + autogalaxy/galaxy/plot/adapt_plotters.py | 4 +- + autogalaxy/galaxy/plot/galaxies_plotters.py | 6 +- + autogalaxy/galaxy/plot/galaxy_plotters.py | 2 +- + .../imaging/plot/fit_imaging_plotters.py | 11 +-- + autogalaxy/plot/abstract_plotters.py | 80 +++++++++++++++ + autogalaxy/plot/mass_plotter.py | 15 +-- + autogalaxy/plot/plots/__init__.py | 6 ++ + autogalaxy/plot/plots/overlays.py | 98 +++++++++++++++++++ + autogalaxy/profiles/plot/basis_plotters.py | 2 +- + .../profiles/plot/light_profile_plotters.py | 2 +- + 11 files changed, 201 insertions(+), 29 deletions(-) + create mode 100644 autogalaxy/plot/plots/__init__.py + create mode 100644 autogalaxy/plot/plots/overlays.py + +diff --git a/autogalaxy/ellipse/plot/fit_ellipse_plotters.py b/autogalaxy/ellipse/plot/fit_ellipse_plotters.py +index 0bb67a21..0506f810 100644 +--- a/autogalaxy/ellipse/plot/fit_ellipse_plotters.py ++++ b/autogalaxy/ellipse/plot/fit_ellipse_plotters.py +@@ -89,7 +89,7 @@ class FitEllipsePlotter(Plotter): positions=ellipse_list, lines=ellipse_list ) @@ -43,7 +43,7 @@ index 0bb67a21..0506f810 100644 array=self.fit_list[0].data, visuals_2d=visuals_2d, auto_labels=aplt.AutoLabels( -@@ -217,7 +217,7 @@ class FitEllipsePDFPlotter(Plotter): +@@ -217,7 +217,7 @@ class FitEllipsePDFPlotter(Plotter): lines=median_ellipse, fill_region=[y_fill, x_fill] ) @@ -52,11 +52,11 @@ index 0bb67a21..0506f810 100644 array=self.fit_pdf_list[0][0].data, visuals_2d=visuals_2d, auto_labels=aplt.AutoLabels( -diff --git a/autogalaxy/galaxy/plot/adapt_plotters.py b/autogalaxy/galaxy/plot/adapt_plotters.py -index a2b07e2e..d9f7818d 100644 ---- a/autogalaxy/galaxy/plot/adapt_plotters.py -+++ b/autogalaxy/galaxy/plot/adapt_plotters.py -@@ -27,7 +27,7 @@ class AdaptPlotter(Plotter): +diff --git a/autogalaxy/galaxy/plot/adapt_plotters.py b/autogalaxy/galaxy/plot/adapt_plotters.py +index a2b07e2e..d9f7818d 100644 +--- a/autogalaxy/galaxy/plot/adapt_plotters.py ++++ b/autogalaxy/galaxy/plot/adapt_plotters.py +@@ -27,7 +27,7 @@ class AdaptPlotter(Plotter): The adapt model image that is plotted. """ @@ -65,7 +65,7 @@ index a2b07e2e..d9f7818d 100644 array=model_image, visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -@@ -44,7 +44,7 @@ class AdaptPlotter(Plotter): +@@ -44,7 +44,7 @@ class AdaptPlotter(Plotter): galaxy_image The galaxy image that is plotted. """ @@ -74,11 +74,11 @@ index a2b07e2e..d9f7818d 100644 array=galaxy_image, visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -diff --git a/autogalaxy/galaxy/plot/galaxies_plotters.py b/autogalaxy/galaxy/plot/galaxies_plotters.py -index e49a8e1a..c3b1ed1b 100644 ---- a/autogalaxy/galaxy/plot/galaxies_plotters.py -+++ b/autogalaxy/galaxy/plot/galaxies_plotters.py -@@ -146,7 +146,7 @@ class GalaxiesPlotter(Plotter): +diff --git a/autogalaxy/galaxy/plot/galaxies_plotters.py b/autogalaxy/galaxy/plot/galaxies_plotters.py +index e49a8e1a..c3b1ed1b 100644 +--- a/autogalaxy/galaxy/plot/galaxies_plotters.py ++++ b/autogalaxy/galaxy/plot/galaxies_plotters.py +@@ -146,7 +146,7 @@ class Galaxies(Plotter): Add a suffix to the end of the filename the plot is saved to hard-disk using. """ if image: @@ -87,7 +87,7 @@ index e49a8e1a..c3b1ed1b 100644 array=self.galaxies.image_2d_from(grid=self.grid), visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -@@ -160,7 +160,7 @@ class GalaxiesPlotter(Plotter): +@@ -160,7 +160,7 @@ class Galaxies(Plotter): else: title = f"Plane Image{title_suffix}" @@ -96,7 +96,7 @@ index e49a8e1a..c3b1ed1b 100644 array=self.galaxies.plane_image_2d_from( grid=self.grid, zoom_to_brightest=zoom_to_brightest ), -@@ -177,7 +177,7 @@ class GalaxiesPlotter(Plotter): +@@ -177,7 +177,7 @@ class Galaxies(Plotter): else: title = f"Plane Grid{title_suffix}" @@ -105,11 +105,11 @@ index e49a8e1a..c3b1ed1b 100644 grid=self.grid, visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -diff --git a/autogalaxy/galaxy/plot/galaxy_plotters.py b/autogalaxy/galaxy/plot/galaxy_plotters.py -index d1a37283..d2464f81 100644 ---- a/autogalaxy/galaxy/plot/galaxy_plotters.py -+++ b/autogalaxy/galaxy/plot/galaxy_plotters.py -@@ -201,7 +201,7 @@ class GalaxyPlotter(Plotter): +diff --git a/autogalaxy/galaxy/plot/galaxy_plotters.py b/autogalaxy/galaxy/plot/galaxy_plotters.py +index d1a37283..d2464f81 100644 +--- a/autogalaxy/galaxy/plot/galaxy_plotters.py ++++ b/autogalaxy/galaxy/plot/galaxy_plotters.py +@@ -201,7 +201,7 @@ class Galaxy(Plotter): Whether to make a 2D plot (via `imshow`) of the magnification. """ if image: @@ -118,11 +118,11 @@ index d1a37283..d2464f81 100644 array=self.galaxy.image_2d_from(grid=self.grid), visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -diff --git a/autogalaxy/imaging/plot/fit_imaging_plotters.py b/autogalaxy/imaging/plot/fit_imaging_plotters.py -index 3f21b5a2..8a68222a 100644 ---- a/autogalaxy/imaging/plot/fit_imaging_plotters.py -+++ b/autogalaxy/imaging/plot/fit_imaging_plotters.py -@@ -131,14 +131,7 @@ class FitImagingPlotter(Plotter): +diff --git a/autogalaxy/imaging/plot/fit_imaging_plotters.py b/autogalaxy/imaging/plot/fit_imaging_plotters.py +index 3f21b5a2..8a68222a 100644 +--- a/autogalaxy/imaging/plot/fit_imaging_plotters.py ++++ b/autogalaxy/imaging/plot/fit_imaging_plotters.py +@@ -131,14 +131,7 @@ class FitImaging(Plotter): for galaxy_index in galaxy_indices: if subtracted_image: @@ -138,7 +138,7 @@ index 3f21b5a2..8a68222a 100644 array=self.fit.subtracted_images_of_galaxies_list[galaxy_index], visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -@@ -148,7 +141,7 @@ class FitImagingPlotter(Plotter): +@@ -148,7 +141,7 @@ class FitImaging(Plotter): ) if model_image: @@ -147,11 +147,11 @@ index 3f21b5a2..8a68222a 100644 array=self.fit.model_images_of_galaxies_list[galaxy_index], visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels( -diff --git a/autogalaxy/plot/abstract_plotters.py b/autogalaxy/plot/abstract_plotters.py -index 3acd3667..79bf31f2 100644 ---- a/autogalaxy/plot/abstract_plotters.py -+++ b/autogalaxy/plot/abstract_plotters.py -@@ -2,7 +2,19 @@ from autoarray.plot.wrap.base.abstract import set_backend +diff --git a/autogalaxy/plot/abstract_plotters.py b/autogalaxy/plot/abstract_plotters.py +index 3acd3667..79bf31f2 100644 +--- a/autogalaxy/plot/abstract_plotters.py ++++ b/autogalaxy/plot/abstract_plotters.py +@@ -2,7 +2,19 @@ from autoarray.plot.wrap.base.abstract import set_backend set_backend() @@ -171,7 +171,7 @@ index 3acd3667..79bf31f2 100644 from autogalaxy.plot.mat_plot.one_d import MatPlot1D from autogalaxy.plot.mat_plot.two_d import MatPlot2D -@@ -32,3 +44,71 @@ class Plotter(AbstractPlotter): +@@ -32,3 +44,71 @@ class Plotter(AbstractPlotter): self.visuals_2d = visuals_2d or Visuals2D() self.mat_plot_2d = mat_plot_2d or MatPlot2D() @@ -243,11 +243,11 @@ index 3acd3667..79bf31f2 100644 + output_filename=filename, + output_format=fmt, + ) -diff --git a/autogalaxy/plot/mass_plotter.py b/autogalaxy/plot/mass_plotter.py -index 16167ad5..fcd7d483 100644 ---- a/autogalaxy/plot/mass_plotter.py -+++ b/autogalaxy/plot/mass_plotter.py -@@ -64,24 +64,22 @@ class MassPlotter(Plotter): +diff --git a/autogalaxy/plot/mass_plotter.py b/autogalaxy/plot/mass_plotter.py +index 16167ad5..fcd7d483 100644 +--- a/autogalaxy/plot/mass_plotter.py ++++ b/autogalaxy/plot/mass_plotter.py +@@ -64,24 +64,22 @@ class MassPlotter(Plotter): """ if convergence: @@ -274,7 +274,7 @@ index 16167ad5..fcd7d483 100644 ), ) -@@ -91,13 +89,12 @@ class MassPlotter(Plotter): +@@ -91,13 +89,12 @@ class MassPlotter(Plotter): values=deflections.slim[:, 0], mask=self.grid.mask ) @@ -289,7 +289,7 @@ index 16167ad5..fcd7d483 100644 ), ) -@@ -107,20 +104,19 @@ class MassPlotter(Plotter): +@@ -107,20 +104,19 @@ class MassPlotter(Plotter): values=deflections.slim[:, 1], mask=self.grid.mask ) @@ -312,31 +312,31 @@ index 16167ad5..fcd7d483 100644 array=LensCalc.from_mass_obj( self.mass_obj ).magnification_2d_from(grid=self.grid), -@@ -128,6 +124,5 @@ class MassPlotter(Plotter): +@@ -128,6 +124,5 @@ class MassPlotter(Plotter): auto_labels=aplt.AutoLabels( title=f"Magnification{title_suffix}", filename=f"magnification_2d{filename_suffix}", - cb_unit="", ), ) -diff --git a/autogalaxy/plot/plots/__init__.py b/autogalaxy/plot/plots/__init__.py -new file mode 100644 -index 00000000..1f20cbdc ---- /dev/null -+++ b/autogalaxy/plot/plots/__init__.py -@@ -0,0 +1,6 @@ +diff --git a/autogalaxy/plot/plots/__init__.py b/autogalaxy/plot/plots/__init__.py +new file mode 100644 +index 00000000..1f20cbdc +--- /dev/null ++++ b/autogalaxy/plot/plots/__init__.py +@@ -0,0 +1,6 @@ +from autogalaxy.plot.plots.overlays import ( + _critical_curves_from_visuals, + _caustics_from_visuals, + _galaxy_lines_from_visuals, + _galaxy_positions_from_visuals, +) -diff --git a/autogalaxy/plot/plots/overlays.py b/autogalaxy/plot/plots/overlays.py -new file mode 100644 -index 00000000..9f79ad94 ---- /dev/null -+++ b/autogalaxy/plot/plots/overlays.py -@@ -0,0 +1,98 @@ +diff --git a/autogalaxy/plot/plots/overlays.py b/autogalaxy/plot/plots/overlays.py +new file mode 100644 +index 00000000..9f79ad94 +--- /dev/null ++++ b/autogalaxy/plot/plots/overlays.py +@@ -0,0 +1,98 @@ +""" +Helper functions to extract autogalaxy-specific overlay data from Visuals2D +objects and convert them to plain numpy arrays suitable for plot_array(). @@ -435,11 +435,11 @@ index 00000000..9f79ad94 + pass + + return result or None -diff --git a/autogalaxy/profiles/plot/basis_plotters.py b/autogalaxy/profiles/plot/basis_plotters.py -index 93d4bbc6..3ff5fac1 100644 ---- a/autogalaxy/profiles/plot/basis_plotters.py -+++ b/autogalaxy/profiles/plot/basis_plotters.py -@@ -115,7 +115,7 @@ class BasisPlotter(Plotter): +diff --git a/autogalaxy/profiles/plot/basis_plotters.py b/autogalaxy/profiles/plot/basis_plotters.py +index 93d4bbc6..3ff5fac1 100644 +--- a/autogalaxy/profiles/plot/basis_plotters.py ++++ b/autogalaxy/profiles/plot/basis_plotters.py +@@ -115,7 +115,7 @@ class BasisPlotter(Plotter): self.open_subplot_figure(number_subplots=len(self.basis.light_profile_list)) for light_profile in self.basis.light_profile_list: @@ -448,11 +448,11 @@ index 93d4bbc6..3ff5fac1 100644 array=light_profile.image_2d_from(grid=self.grid), visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels(title=light_profile.coefficient_tag), -diff --git a/autogalaxy/profiles/plot/light_profile_plotters.py b/autogalaxy/profiles/plot/light_profile_plotters.py -index 7292f5eb..07b21f29 100644 ---- a/autogalaxy/profiles/plot/light_profile_plotters.py -+++ b/autogalaxy/profiles/plot/light_profile_plotters.py -@@ -89,7 +89,7 @@ class LightProfilePlotter(Plotter): +diff --git a/autogalaxy/profiles/plot/light_profile_plotters.py b/autogalaxy/profiles/plot/light_profile_plotters.py +index 7292f5eb..07b21f29 100644 +--- a/autogalaxy/profiles/plot/light_profile_plotters.py ++++ b/autogalaxy/profiles/plot/light_profile_plotters.py +@@ -89,7 +89,7 @@ class LightProfile(Plotter): Whether to make a 2D plot (via `imshow`) of the image. """ if image: @@ -461,6 +461,6 @@ index 7292f5eb..07b21f29 100644 array=self.light_profile.image_2d_from(grid=self.grid), visuals_2d=self.visuals_2d, auto_labels=aplt.AutoLabels(title="Image", filename="image_2d"), --- -2.43.0 - +-- +2.43.0 + From 1e9973564cbcc058a71ba41a65d665bcabf08828 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Wed, 25 Mar 2026 19:31:03 +0000 Subject: [PATCH 2/2] Overhaul plot styling and extract fits_* output functions - All colormap defaults changed from "jet" to None (resolves to the configured default colormap via autoarray) - save_tracer_fits() and save_source_plane_images_fits() extracted to tracer_plots.py; plotter.py reduced to one-liner delegate calls - Unused imports (ast, numpy, conf, hdu_list_for_output_from) removed from plotter.py Co-Authored-By: Claude Sonnet 4.6 --- autolens/analysis/plotter.py | 76 ++---------- autolens/imaging/plot/fit_imaging_plots.py | 21 ++-- .../plot/fit_interferometer_plots.py | 6 +- autolens/lens/plot/sensitivity_plots.py | 6 +- autolens/lens/plot/subhalo_plots.py | 4 +- autolens/lens/plot/tracer_plots.py | 113 +++++++++++++++++- 6 files changed, 135 insertions(+), 91 deletions(-) diff --git a/autolens/analysis/plotter.py b/autolens/analysis/plotter.py index f95f81fd2..215b1e3ae 100644 --- a/autolens/analysis/plotter.py +++ b/autolens/analysis/plotter.py @@ -1,10 +1,6 @@ -import ast import numpy as np from typing import Optional -from autoconf import conf -from autoconf.fitsable import hdu_list_for_output_from - import autoarray as aa import autogalaxy as ag @@ -13,7 +9,11 @@ from autogalaxy.analysis.plotter import Plotter as AgPlotter from autolens.lens.tracer import Tracer -from autolens.lens.plot.tracer_plots import subplot_galaxies_images +from autolens.lens.plot.tracer_plots import ( + subplot_galaxies_images, + save_tracer_fits, + save_source_plane_images_fits, +) from autoarray.plot.array import plot_array @@ -63,72 +63,10 @@ def should_plot(name): ) if should_plot("fits_tracer"): - - zoom = aa.Zoom2D(mask=grid.mask) - mask = zoom.mask_2d_from(buffer=1) - grid_zoom = aa.Grid2D.from_mask(mask=mask) - - image_list = [ - tracer.convergence_2d_from(grid=grid_zoom).native, - tracer.potential_2d_from(grid=grid_zoom).native, - tracer.deflections_yx_2d_from(grid=grid_zoom).native[:, :, 0], - tracer.deflections_yx_2d_from(grid=grid_zoom).native[:, :, 1], - ] - - hdu_list = hdu_list_for_output_from( - values_list=[image_list[0].mask.astype("float")] + image_list, - ext_name_list=[ - "mask", - "convergence", - "potential", - "deflections_y", - "deflections_x", - ], - header_dict=grid_zoom.mask.header_dict, - ) - - hdu_list.writeto(self.image_path / "tracer.fits", overwrite=True) + save_tracer_fits(tracer=tracer, grid=grid, output_path=self.image_path) if should_plot("fits_source_plane_images"): - - shape_native = conf.instance["visualize"]["plots"]["tracer"][ - "fits_source_plane_shape" - ] - shape_native = ast.literal_eval(shape_native) - - zoom = aa.Zoom2D(mask=grid.mask) - mask = zoom.mask_2d_from(buffer=1) - grid_source_plane = aa.Grid2D.from_extent( - extent=mask.geometry.extent, shape_native=tuple(shape_native) - ) - - image_list = [grid_source_plane.mask.astype("float")] - ext_name_list = ["mask"] - - for i, plane in enumerate(tracer.planes[1:]): - - if plane.has(cls=ag.LightProfile): - - image = plane.image_2d_from( - grid=grid_source_plane, - ).native - - else: - - image = np.zeros(grid_source_plane.shape_native) - - image_list.append(image) - ext_name_list.append(f"source_plane_image_{i+1}") - - hdu_list = hdu_list_for_output_from( - values_list=image_list, - ext_name_list=ext_name_list, - header_dict=grid_source_plane.mask.header_dict, - ) - - hdu_list.writeto( - self.image_path / "source_plane_images.fits", overwrite=True - ) + save_source_plane_images_fits(tracer=tracer, grid=grid, output_path=self.image_path) def image_with_positions(self, image: aa.Array2D, positions: aa.Grid2DIrregular): """ diff --git a/autolens/imaging/plot/fit_imaging_plots.py b/autolens/imaging/plot/fit_imaging_plots.py index 934f07f8e..dab353471 100644 --- a/autolens/imaging/plot/fit_imaging_plots.py +++ b/autolens/imaging/plot/fit_imaging_plots.py @@ -6,7 +6,7 @@ import autogalaxy as ag from autoarray.plot.array import plot_array, _zoom_array_2d -from autoarray.plot.utils import save_figure +from autoarray.plot.utils import save_figure, hide_unused_axes from autoarray.plot.utils import numpy_lines as _to_lines from autogalaxy.plot.plot_utils import _critical_curves_from, _caustics_from @@ -39,7 +39,7 @@ def _get_source_vmax(fit): def _plot_source_plane(fit, ax, plane_index, zoom_to_brightest=True, - colormap="jet", use_log10=False): + colormap=None, use_log10=False): """ Plot the source-plane image (or a blank inversion placeholder) into an axes. @@ -94,7 +94,7 @@ def subplot_fit( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, plane_index: Optional[int] = None, ): """ @@ -214,6 +214,7 @@ def subplot_fit( _plot_source_plane(fit, axes_flat[11], final_plane_index, zoom_to_brightest=False, colormap=colormap) + hide_unused_axes(axes_flat) plt.tight_layout() save_figure(fig, path=output_path, filename=f"subplot_fit{plane_index_tag}", format=output_format) @@ -222,7 +223,7 @@ def subplot_fit_x1_plane( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a 6-panel subplot for a single-plane tracer imaging fit. @@ -286,7 +287,7 @@ def subplot_fit_log10( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, plane_index: Optional[int] = None, ): """ @@ -395,7 +396,7 @@ def subplot_fit_log10_x1_plane( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a 6-panel log10 subplot for a single-plane tracer imaging fit. @@ -456,7 +457,7 @@ def subplot_of_planes( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, plane_index: Optional[int] = None, ): """ @@ -524,7 +525,7 @@ def subplot_tracer_from_fit( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a 9-panel tracer subplot derived from a `FitImaging` object. @@ -600,7 +601,7 @@ def subplot_fit_combined( fit_list: List, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a combined multi-row subplot for a list of `FitImaging` objects. @@ -682,7 +683,7 @@ def subplot_fit_combined_log10( fit_list: List, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a combined log10 multi-row subplot for a list of `FitImaging` objects. diff --git a/autolens/interferometer/plot/fit_interferometer_plots.py b/autolens/interferometer/plot/fit_interferometer_plots.py index 6ad288365..9994118e8 100644 --- a/autolens/interferometer/plot/fit_interferometer_plots.py +++ b/autolens/interferometer/plot/fit_interferometer_plots.py @@ -37,7 +37,7 @@ def _plot_yx(y, x, ax, title, xlabel="", ylabel=""): def _plot_source_plane(fit, ax, plane_index, zoom_to_brightest=True, - colormap="jet", use_log10=False): + colormap=None, use_log10=False): """ Plot the source-plane image (or a blank inversion placeholder) into an axes. @@ -88,7 +88,7 @@ def subplot_fit( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a 12-panel subplot summarising an interferometer fit. @@ -197,7 +197,7 @@ def subplot_fit_real_space( fit, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a real-space subplot for an interferometer fit. diff --git a/autolens/lens/plot/sensitivity_plots.py b/autolens/lens/plot/sensitivity_plots.py index b7699e686..97238551a 100644 --- a/autolens/lens/plot/sensitivity_plots.py +++ b/autolens/lens/plot/sensitivity_plots.py @@ -16,7 +16,7 @@ def subplot_tracer_images( source_image, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log10: bool = False, ): """ @@ -120,7 +120,7 @@ def subplot_sensitivity( data_subtracted, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log10: bool = False, ): """ @@ -248,7 +248,7 @@ def subplot_figures_of_merit_grid( result, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log_evidences: bool = True, remove_zeros: bool = True, ): diff --git a/autolens/lens/plot/subhalo_plots.py b/autolens/lens/plot/subhalo_plots.py index fda7d5b68..1c1689d3d 100644 --- a/autolens/lens/plot/subhalo_plots.py +++ b/autolens/lens/plot/subhalo_plots.py @@ -12,7 +12,7 @@ def subplot_detection_imaging( fit_imaging_with_subhalo, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log10: bool = False, use_log_evidences: bool = True, relative_to_value: float = 0.0, @@ -103,7 +103,7 @@ def subplot_detection_fits( fit_imaging_with_subhalo, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, ): """ Produce a 6-panel subplot comparing imaging fits with and without a subhalo. diff --git a/autolens/lens/plot/tracer_plots.py b/autolens/lens/plot/tracer_plots.py index 7027aa4d4..901d5ba00 100644 --- a/autolens/lens/plot/tracer_plots.py +++ b/autolens/lens/plot/tracer_plots.py @@ -6,7 +6,7 @@ import autogalaxy as ag from autoarray.plot.array import plot_array -from autoarray.plot.utils import save_figure +from autoarray.plot.utils import save_figure, hide_unused_axes from autoarray.plot.utils import numpy_lines as _to_lines, numpy_positions as _to_positions from autogalaxy.plot.plot_utils import _critical_curves_from, _caustics_from @@ -16,7 +16,7 @@ def subplot_tracer( grid: aa.type.Grid2DLike, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log10: bool = False, positions=None, ): @@ -85,6 +85,7 @@ def subplot_tracer( plot_array(array=magnification, ax=axes_flat[8], title="Magnification", lines=image_plane_lines, colormap=colormap) + hide_unused_axes(axes_flat) plt.tight_layout() save_figure(fig, path=output_path, filename="subplot_tracer", format=output_format) @@ -94,7 +95,7 @@ def subplot_lensed_images( grid: aa.type.Grid2DLike, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log10: bool = False, ): """ @@ -148,7 +149,7 @@ def subplot_galaxies_images( grid: aa.type.Grid2DLike, output_path: Optional[str] = None, output_format: str = "png", - colormap: str = "jet", + colormap: Optional[str] = None, use_log10: bool = False, ): """ @@ -228,3 +229,107 @@ def subplot_galaxies_images( plt.tight_layout() save_figure(fig, path=output_path, filename="subplot_galaxies_images", format=output_format) + + +def save_tracer_fits( + tracer, + grid: aa.type.Grid2DLike, + output_path, +) -> None: + """Write a FITS file containing lensing maps for the tracer. + + Produces ``tracer.fits`` in *output_path*. The file contains extensions: + ``mask``, ``convergence``, ``potential``, ``deflections_y``, + ``deflections_x``, all evaluated on a zoomed grid derived from + *grid*'s mask. + + Parameters + ---------- + tracer : Tracer + The tracer whose lensing maps are evaluated. + grid : aa.type.Grid2DLike + Image-plane grid; a zoomed version is derived internally. + output_path : str or Path + Directory in which to write ``tracer.fits``. + """ + from pathlib import Path + from autoconf.fitsable import hdu_list_for_output_from + + output_path = Path(output_path) + zoom = aa.Zoom2D(mask=grid.mask) + grid_zoom = aa.Grid2D.from_mask(mask=zoom.mask_2d_from(buffer=1)) + + deflections = tracer.deflections_yx_2d_from(grid=grid_zoom).native + image_list = [ + tracer.convergence_2d_from(grid=grid_zoom).native, + tracer.potential_2d_from(grid=grid_zoom).native, + deflections[:, :, 0], + deflections[:, :, 1], + ] + hdu_list = hdu_list_for_output_from( + values_list=[image_list[0].mask.astype("float")] + image_list, + ext_name_list=["mask", "convergence", "potential", "deflections_y", "deflections_x"], + header_dict=grid_zoom.mask.header_dict, + ) + hdu_list.writeto(output_path / "tracer.fits", overwrite=True) + + +def save_source_plane_images_fits( + tracer, + grid: aa.type.Grid2DLike, + output_path, +) -> None: + """Write a FITS file containing source-plane images for each source plane. + + Produces ``source_plane_images.fits`` in *output_path*. One HDU is + written per source plane (``tracer.planes[1:]``), named + ``source_plane_image_1``, ``source_plane_image_2``, …, plus a ``mask`` + extension. Planes without a + :class:`~autogalaxy.profiles.light.abstract.LightProfile` produce a + zero-valued array. + + The shape of the source-plane grid is read from config key + ``visualize / plots / tracer / fits_source_plane_shape``. + + Parameters + ---------- + tracer : Tracer + The tracer whose source-plane images are evaluated. + grid : aa.type.Grid2DLike + Image-plane grid; used to derive the zoomed extent for the + source-plane grid. + output_path : str or Path + Directory in which to write ``source_plane_images.fits``. + """ + import ast + from pathlib import Path + from autoconf import conf + from autoconf.fitsable import hdu_list_for_output_from + + output_path = Path(output_path) + shape_native = tuple(ast.literal_eval( + conf.instance["visualize"]["plots"]["tracer"]["fits_source_plane_shape"] + )) + + zoom = aa.Zoom2D(mask=grid.mask) + grid_source = aa.Grid2D.from_extent( + extent=zoom.mask_2d_from(buffer=1).geometry.extent, + shape_native=shape_native, + ) + + image_list = [grid_source.mask.astype("float")] + ext_name_list = ["mask"] + for i, plane in enumerate(tracer.planes[1:]): + if plane.has(cls=ag.LightProfile): + image = plane.image_2d_from(grid=grid_source).native + else: + image = np.zeros(grid_source.shape_native) + image_list.append(image) + ext_name_list.append(f"source_plane_image_{i + 1}") + + hdu_list = hdu_list_for_output_from( + values_list=image_list, + ext_name_list=ext_name_list, + header_dict=grid_source.mask.header_dict, + ) + hdu_list.writeto(output_path / "source_plane_images.fits", overwrite=True)