diff --git a/autolens/imaging/model/visualizer.py b/autolens/imaging/model/visualizer.py index fb5c37438..e98f44505 100644 --- a/autolens/imaging/model/visualizer.py +++ b/autolens/imaging/model/visualizer.py @@ -231,13 +231,28 @@ def visualize_combined( if analyses is None: return + # A mixed-dataset factor graph (e.g. imaging + weak lensing) routes every + # factor's analysis here; this combined subplot can only draw its own + # dataset type, so other analyses are skipped (each still visualizes its + # own fit individually). + from autolens.imaging.model.analysis import AnalysisImaging + + pairs = [ + (analysis, single_instance) + for analysis, single_instance in zip(analyses, instance) + if isinstance(analysis, AnalysisImaging) + ] + + if len(pairs) == 0: + return + plotter = PlotterImaging( - image_path=paths.image_path, title_prefix=analyses[0].title_prefix + image_path=paths.image_path, title_prefix=pairs[0][0].title_prefix ) fit_list = [ analysis.fit_for_visualization(instance=single_instance) - for analysis, single_instance in zip(analyses, instance) + for analysis, single_instance in pairs ] plotter.fit_imaging_combined( diff --git a/autolens/interferometer/model/visualizer.py b/autolens/interferometer/model/visualizer.py index 3202c60e7..d70883d3c 100644 --- a/autolens/interferometer/model/visualizer.py +++ b/autolens/interferometer/model/visualizer.py @@ -201,13 +201,28 @@ def visualize_combined( if analyses is None: return + # A mixed-dataset factor graph (e.g. imaging + weak lensing) routes every + # factor's analysis here; this combined subplot can only draw its own + # dataset type, so other analyses are skipped (each still visualizes its + # own fit individually). + from autolens.interferometer.model.analysis import AnalysisInterferometer + + pairs = [ + (analysis, single_instance) + for analysis, single_instance in zip(analyses, instance) + if isinstance(analysis, AnalysisInterferometer) + ] + + if len(pairs) == 0: + return + plotter = PlotterInterferometer( - image_path=paths.image_path, title_prefix=analyses[0].title_prefix + image_path=paths.image_path, title_prefix=pairs[0][0].title_prefix ) fit_list = [ analysis.fit_for_visualization(instance=single_instance) - for analysis, single_instance in zip(analyses, instance) + for analysis, single_instance in pairs ] plotter.fit_interferometer_combined( diff --git a/test_autolens/imaging/model/test_visualizer_mixed_graph.py b/test_autolens/imaging/model/test_visualizer_mixed_graph.py new file mode 100644 index 000000000..7b58c9f36 --- /dev/null +++ b/test_autolens/imaging/model/test_visualizer_mixed_graph.py @@ -0,0 +1,41 @@ +import autoarray as aa +import autolens as al + +from autolens.imaging.model.visualizer import VisualizerImaging + + +class _RaisingPaths: + """visualize_combined must return before touching paths when no imaging analysis is present.""" + + @property + def image_path(self): + raise AssertionError("plotting was attempted for a graph with no imaging analyses") + + +def test__visualize_combined__skips_non_imaging_analyses(): + """ + A mixed-dataset factor graph (e.g. imaging + weak) routes every factor's analysis into the + lead factor's Visualizer.visualize_combined; non-imaging analyses must be filtered out + rather than treated as FitImaging producers (which raised AttributeError before the fix). + """ + grid = aa.Grid2DIrregular(values=[(1.0, 1.0), (-1.0, 1.0)]) + tracer = al.Tracer( + galaxies=[ + al.Galaxy( + redshift=0.5, + mass=al.mp.IsothermalSph(einstein_radius=1.0), + ), + al.Galaxy(redshift=1.0), + ] + ) + dataset = al.SimulatorShearYX(noise_sigma=0.1, seed=1).via_tracer_from( + tracer=tracer, grid=grid + ) + analysis_weak = al.AnalysisWeak(dataset=dataset) + + VisualizerImaging.visualize_combined( + analyses=[analysis_weak], + paths=_RaisingPaths(), + instance=[None], + during_analysis=True, + )