Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 1 addition & 28 deletions autoarray/config/visualize/plots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,11 @@

dataset: # Settings for plots of all datasets (e.g. ImagingPlotter, InterferometerPlotter).
subplot_dataset: true # Plot subplot containing all dataset quantities (e.g. the data, noise-map, etc.)?
data: false # Plot the individual data of every dataset?
noise_map: false # Plot the individual noise-map of every dataset?
signal_to_noise_map: false # Plot the individual signal-to-noise-map of every dataset?
over_sample_size_lp: false # Plot the over-sampling size, used to evaluate light profiles, of every dataset?
over_sample_size_pixelization: false # Plot the over-sampling size, used to evaluate pixelizations, of every dataset?
imaging: # Settings for plots of imaging datasets (e.g. ImagingPlotter)
psf: false
fit: # Settings for plots of all fits (e.g. FitImagingPlotter, FitInterferometerPlotter).
subplot_fit: true # Plot subplot of all fit quantities for any dataset (e.g. the model data, residual-map, etc.)?
subplot_fit_log10: true # Plot subplot of all fit quantities for any dataset using log10 color maps (e.g. the model data, residual-map, etc.)?
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?
all_at_end_fits: true # Plot all individual plots listed below as .fits (even if False)?
all_at_end_pdf: false # Plot all individual plots listed below as publication-quality .pdf (even if False)?
data: false # Plot individual plots of the data?
noise_map: false # Plot individual plots of the noise-map?
signal_to_noise_map: false # Plot individual plots of the signal-to-noise-map?
Expand All @@ -30,9 +22,6 @@ fit_imaging: {} # Settings for plots of fits to imagi
inversion: # Settings for plots of inversions (e.g. InversionPlotter).
subplot_inversion: true # Plot subplot of all quantities in each inversion (e.g. reconstrucuted image, reconstruction)?
subplot_mappings: true # Plot subplot of the image-to-source pixels mappings of each pixelization?
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?
all_at_end_fits: true # Plot all individual plots listed below as .fits (even if False)?
all_at_end_pdf: false # Plot all individual plots listed below as publication-quality .pdf (even if False)?
data_subtracted: false # Plot individual plots of the data with the other inversion linear objects subtracted?
reconstruction_noise_map: false # Plot image of the noise of every mesh-pixel reconstructed value?
sub_pixels_per_image_pixels: false # Plot the number of sub pixels per masked data pixels?
Expand All @@ -41,22 +30,6 @@ inversion: # Settings for plots of inversions (e
reconstructed_image: false # Plot image of the reconstructed data (e.g. in the image-plane)?
reconstruction: false # Plot the reconstructed inversion (e.g. the pixelization's mesh in the source-plane)?
regularization_weights: false # Plot the effective regularization weight of every inversion mesh pixel?
interferometer: # Settings for plots of interferometer datasets (e.g. InterferometerPlotter).
amplitudes_vs_uv_distances: false
phases_vs_uv_distances: false
uv_wavelengths: false
dirty_image: false
dirty_noise_map: false
dirty_signal_to_noise_map: false
fit_interferometer: # Settings for plots of fits to interferometer datasets (e.g. FitInterferometerPlotter).
subplot_fit_dirty_images: false # Plot subplot of the dirty-images of all interferometer datasets?
subplot_fit_real_space: false # Plot subplot of the real-space images of all interferometer datasets?
amplitudes_vs_uv_distances: false
phases_vs_uv_distances: false
uv_wavelengths: false
dirty_image: false
dirty_noise_map: false
dirty_signal_to_noise_map: false
dirty_residual_map: false
dirty_normalized_residual_map: false
dirty_chi_squared_map: false
subplot_fit_real_space: false # Plot subplot of the real-space images of all interferometer datasets?
2 changes: 1 addition & 1 deletion autoarray/inversion/inversion/mapper_valued.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def magnification_via_mesh_from(

def magnification_via_interpolation_from(
self,
shape_native: Tuple[int, int] = (401, 401),
shape_native: Tuple[int, int] = (201, 201),
extent: Optional[Tuple[float, float, float, float]] = None,
) -> float:
"""
Expand Down
2 changes: 1 addition & 1 deletion autoarray/operators/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def pylops_exception():
"\n--------------------\n"
"You are attempting to perform interferometer analysis.\n\n"
"However, the optional library PyLops (https://github.com/PyLops/pylops) is not installed.\n\n"
"Install it via the command `pip install pylops==1.18.3`.\n\n"
"Install it via the command `pip install pylops==2.3.1`.\n\n"
"----------------------"
)

Expand Down
118 changes: 95 additions & 23 deletions autoarray/plot/multi_plotters.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os
from pathlib import Path
from typing import List, Optional, Tuple

from autoarray.plot.wrap.base.ticks import YTicks
Expand Down Expand Up @@ -104,29 +106,6 @@ def plot_via_func(self, plotter, figure_name: str, func_name: str, kwargs):
else:
func(**{**{figure_name: True}, **kwargs})

def output_subplot(self, filename_suffix: str = ""):
"""
Outplot the subplot to a file after all figures have been plotted on the subplot.

The multi-plotter requires its own output function to ensure that the subplot is output to a file, which
this provides.

Parameters
----------
filename_suffix
The suffix of the filename that the subplot is output to.
"""

if self.plotter_list[0].mat_plot_1d is not None:
self.plotter_list[0].mat_plot_1d.output.subplot_to_figure(
auto_filename=f"subplot_{filename_suffix}"
)
if self.plotter_list[0].mat_plot_2d is not None:
self.plotter_list[0].mat_plot_2d.output.subplot_to_figure(
auto_filename=f"subplot_{filename_suffix}"
)
self.plotter_list[0].close_subplot_figure()

def subplot_of_figure(
self, func_name: str, figure_name: str, filename_suffix: str = "", **kwargs
):
Expand Down Expand Up @@ -266,6 +245,99 @@ def subplot_of_multi_yx_1d(self, filename_suffix="", **kwargs):
)
self.plotter_list[0].plotter_list[0].close_subplot_figure()

def output_subplot(self, filename_suffix: str = ""):
"""
Outplot the subplot to a file after all figures have been plotted on the subplot.

The multi-plotter requires its own output function to ensure that the subplot is output to a file, which
this provides.

Parameters
----------
filename_suffix
The suffix of the filename that the subplot is output to.
"""

plotter = self.plotter_list[0]

if plotter.mat_plot_1d is not None:
plotter.mat_plot_1d.output.subplot_to_figure(
auto_filename=f"subplot_{filename_suffix}"
)
if plotter.mat_plot_2d is not None:
plotter.mat_plot_2d.output.subplot_to_figure(
auto_filename=f"subplot_{filename_suffix}"
)
plotter.close_subplot_figure()

def output_to_fits(
self,
func_name_list: List[str],
figure_name_list: List[str],
filename: str,
tag_list: Optional[List[str]] = None,
remove_fits_first: bool = False,
**kwargs,
):
"""
Outputs a list of figures of the plotter objects in the `plotter_list` to a single .fits file.

This function takes as input lists of function names and figure names and then calls them via
the `plotter_list` with an interface that outputs each to a .fits file.

For example, if you have multiple `ImagingPlotter` objects and want to output the `data` and `noise_map` of
each to a single .fits files, you would input:

- `func_name_list=['figures_2d', 'figures_2d']` and
- `figure_name_list=['data', 'noise_map']`.

The implementation of this code is hacky, with it using a specific interface in the `Output` object
which sets the format to `fits_multi` to call a function which outputs the .fits files. A major visualuzation
refactor is required to make this more elegant.

Parameters
----------
func_name_list
The list of function names that are called to plot the figures on the subplot.
figure_name_list
The list of figure names that are plotted on the subplot.
filenane
The filename that the .fits file is output to.
tag_list
The list of tags that are used to set the `EXTNAME` of each hdu of the .fits file.
remove_fits_first
If the .fits file already exists, it is removed before the new .fits file is output, else it is updated
with the figure going into the next hdu.
kwargs
Any additional keyword arguments that are passed to the function that plots the figure on the subplot.
"""

output_path = self.plotter_list[0].mat_plot_2d.output.output_path_from(
format="fits_multi"
)
output_fits_file = Path(output_path)/ f"{filename}.fits"

if remove_fits_first:
output_fits_file.unlink(missing_ok=True)

for i, plotter in enumerate(self.plotter_list):
plotter.mat_plot_2d.output._format = "fits_multi"

plotter.set_filename(filename=f"{filename}")

for j, (func_name, figure_name) in enumerate(
zip(func_name_list, figure_name_list)
):
if tag_list is not None:
plotter.mat_plot_2d.output._tag_fits_multi = tag_list[j]

self.plot_via_func(
plotter=plotter,
figure_name=figure_name,
func_name=func_name,
kwargs=kwargs,
)


class MultiYX1DPlotter:
def __init__(
Expand Down
13 changes: 13 additions & 0 deletions autoarray/plot/wrap/base/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def __init__(
self.format_folder = format_folder
self.bypass = bypass
self.bbox_inches = bbox_inches
self._tag_fits_multi = None

self.kwargs = kwargs

Expand Down Expand Up @@ -105,6 +106,7 @@ def savefig(self, filename: str, output_path: str, format: str):
plt.savefig(
path.join(output_path, f"{filename}.{format}"),
bbox_inches=self.bbox_inches,
pad_inches=0,
)
except ValueError as e:
logger.info(
Expand Down Expand Up @@ -151,6 +153,17 @@ def to_figure(
file_path=path.join(output_path, f"{filename}.fits"),
overwrite=True,
)
elif format == "fits_multi":
if structure is not None:
from autoarray.structures.arrays.array_2d_util import (
update_fits_file,
)

update_fits_file(
arr=structure.native,
file_path=path.join(output_path, f"{filename}.fits"),
tag=self._tag_fits_multi,
)

def subplot_to_figure(self, auto_filename: Optional[str] = None):
"""
Expand Down
2 changes: 1 addition & 1 deletion autoarray/plot/wrap/two_d/voronoi_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def draw_voronoi_pixels(

cmap = plt.get_cmap(cmap.cmap)

if colorbar is not None:
if colorbar is not None and colorbar is not False:
cb = colorbar.set_with_color_values(
units=units,
norm=norm,
Expand Down
58 changes: 58 additions & 0 deletions autoarray/structures/arrays/array_2d_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -862,3 +862,61 @@ def header_obj_from(file_path: Union[Path, str], hdu: int) -> Dict:
hdu_list = fits.open(file_path)

return hdu_list[hdu].header


def update_fits_file(
arr: np.ndarray,
file_path: str,
tag: Optional[str] = None,
header: Optional[fits.Header] = None,
):
"""
Update a .fits file with a new array.

This function is used by the `fits_multi` output interface so that a single .fits file with groups of data
in hdu's can be created.

It may receive a `tag` which is used to set the `EXTNAME` of the HDU in the .fits file and therefore is the name
of the hdu seen by the user when they open it with DS9 or other .fits software.

A header may also be provided, which by default has the pixel scales of the array added to it.

Parameters
----------
arr
The array that is written to the .fits file.
file_path
The full path of the file that is output, including the file name and ``.fits`` extension.
tag
The `EXTNAME` of the HDU in the .fits file.
header
The header of the .fits file that the array is written to, which if blank will still contain the pixel scales
of the array.
"""

if header is None:
header = fits.Header()

try:
y, x = map(str, arr.pixel_scales)
header["PIXSCAY"] = y
header["PIXSCAX"] = x
except AttributeError:
pass

if conf.instance["general"]["fits"]["flip_for_ds9"]:
arr = np.flipud(arr)

if os.path.exists(file_path):
with fits.open(file_path, mode="update") as hdul:
hdul.append(fits.ImageHDU(arr, header))
if tag is not None:
hdul[-1].header["EXTNAME"] = tag.upper()
hdul.flush()

else:
hdu = fits.PrimaryHDU(arr, header)
if tag is not None:
hdu.header["EXTNAME"] = tag.upper()
hdul = fits.HDUList([hdu])
hdul.writeto(file_path, overwrite=True)
Loading