@@ -328,6 +328,102 @@ def subplot_fit_dirty_images(
328328 save_figure (fig , path = output_path , filename = "fit_dirty_images" , format = output_format )
329329
330330
331+ def subplot_fit_interferometer_combined (
332+ fit_list ,
333+ output_path : Optional [str ] = None ,
334+ output_format : str = None ,
335+ colormap : Optional [str ] = None ,
336+ title_prefix : str = None ,
337+ ):
338+ """
339+ Produce a combined multi-row subplot for a list of `FitInterferometer` objects.
340+
341+ Each row corresponds to one channel of a datacube (or one dataset of a multi-band
342+ interferometer fit) and contains four panels:
343+
344+ * Dirty Image (data)
345+ * Dirty Model Image (with critical curves)
346+ * Source Plane (reconstruction)
347+ * Dirty Normalised Residual Map
348+
349+ The layout mirrors :func:`subplot_fit_combined` for imaging — same purpose,
350+ different panel choice because interferometer fits are most informatively
351+ visualised in dirty-image space.
352+
353+ Parameters
354+ ----------
355+ fit_list : list of FitInterferometer
356+ The interferometer fits to display. Each fit occupies one row of the figure.
357+ output_path : str, optional
358+ Directory in which to save the figure. If ``None`` the figure is not saved.
359+ output_format : str, optional
360+ Image format passed to :func:`~autoarray.plot.utils.save_figure`.
361+ colormap : str, optional
362+ Matplotlib colormap name applied to all image panels.
363+ title_prefix : str, optional
364+ Optional prefix prepended to every panel title.
365+ """
366+ n_fits = len (fit_list )
367+ n_cols = 4
368+ fig , axes = subplots (n_fits , n_cols , figsize = conf_subplot_figsize (n_fits , n_cols ))
369+ if n_fits == 1 :
370+ all_axes = [list (axes )]
371+ else :
372+ all_axes = [list (axes [i ]) for i in range (n_fits )]
373+
374+ final_plane_index = len (fit_list [0 ].tracer .planes ) - 1
375+
376+ _pf = (lambda t : f"{ title_prefix .rstrip ()} { t } " ) if title_prefix else (lambda t : t )
377+ for row , fit in enumerate (fit_list ):
378+ row_axes = all_axes [row ]
379+
380+ tracer = fit .tracer_linear_light_profiles_to_light_profiles
381+ cc_grid = fit .dataset .real_space_mask .derive_grid .all_false
382+ ip_lines , ip_colors , sp_lines , sp_colors = _compute_critical_curve_lines (
383+ tracer , cc_grid
384+ )
385+
386+ plot_array (
387+ array = fit .dirty_image ,
388+ ax = row_axes [0 ],
389+ title = _pf (f"Dirty Image (ch { row } )" ),
390+ colormap = colormap ,
391+ )
392+
393+ plot_array (
394+ array = fit .dirty_model_image ,
395+ ax = row_axes [1 ],
396+ title = _pf ("Dirty Model Image" ),
397+ colormap = colormap ,
398+ lines = ip_lines ,
399+ line_colors = ip_colors ,
400+ )
401+
402+ try :
403+ _plot_source_plane (
404+ fit ,
405+ row_axes [2 ],
406+ final_plane_index ,
407+ colormap = colormap ,
408+ title = _pf (f"Source Plane { final_plane_index } " ),
409+ lines = sp_lines ,
410+ line_colors = sp_colors ,
411+ )
412+ except Exception :
413+ row_axes [2 ].axis ("off" )
414+
415+ plot_array (
416+ array = fit .dirty_normalized_residual_map ,
417+ ax = row_axes [3 ],
418+ title = _pf ("Dirty Norm Residual" ),
419+ colormap = colormap ,
420+ cb_unit = r"$\sigma$" ,
421+ )
422+
423+ tight_layout ()
424+ save_figure (fig , path = output_path , filename = "fit_combined" , format = output_format )
425+
426+
331427def subplot_fit_real_space (
332428 fit ,
333429 output_path : Optional [str ] = None ,
0 commit comments