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
7 changes: 7 additions & 0 deletions autolens/config/visualize/plots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
psf: false
positions: # Settings for plots with resampling image-positions on (e.g. the image).
image_with_positions: true
point_dataset: # Settings for plots of point source datasets (e.g. PointDatasetPlotter).
subplot_dataset: true # Plot subplot containing all dataset quantities (e.g. the data, noise-map, etc.)?
positions: false # Plot the positions of th multiple images of the point source in the image plane?
fluxes: false # Plot the fluxes of the multiple images of the point source in the image plane?
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.)?
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?
Expand All @@ -25,6 +29,9 @@
subtracted_images_of_planes: false # Plot individual plots of each plane's subtracted image?
plane_images_of_planes: false # Plot individual plots of each plane's image (e.g. in the source plane)?
fit_imaging: {} # Settings for plots of fits to imaging datasets (e.g. FitImagingPlotter).
fit_point_dataset: # Settings for plots of fits to point source datasets (e.g. FitPointDatasetPlotter).
positions: false # Plot the positions of th multiple images of the point source in the image plane?
fluxes: false # Plot the fluxes of the multiple images of the point source in the image plane?
tracer: # Settings for plots of tracers (e.g. TracerPlotter).
subplot_tracer: true # Plot subplot of all quantities in each tracer (e.g. images, convergence)?
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?
Expand Down
9 changes: 9 additions & 0 deletions autolens/point/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,12 @@ def info(self) -> str:
info += f"fluxes : {self.fluxes}\n"
info += f"fluxes_noise_map : {self.fluxes_noise_map}\n"
return info

def extent_from(self, buffer : float = 0.1):

y_max = max(self.positions[:, 0]) + buffer
y_min = min(self.positions[:, 0]) - buffer
x_max = max(self.positions[:, 1]) + buffer
x_min = min(self.positions[:, 1]) - buffer

return [y_min, y_max, x_min, x_max]
9 changes: 3 additions & 6 deletions autolens/point/model/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from autogalaxy.analysis.analysis.analysis import Analysis as AgAnalysis

from autolens.analysis.analysis.lens import AnalysisLens
from autolens.analysis.plotter_interface import PlotterInterface
from autolens.point.fit.positions.image.pair_repeat import FitPositionsImagePairRepeat
from autolens.point.fit.dataset import FitPointDataset
from autolens.point.dataset import PointDataset
from autolens.point.model.result import ResultPoint
from autolens.point.model.visualizer import VisualizerPoint
from autolens.point.solver import PointSolver

from autolens import exc
Expand All @@ -24,6 +24,8 @@


class AnalysisPoint(AgAnalysis, AnalysisLens):

Visualizer = VisualizerPoint
Result = ResultPoint

def __init__(
Expand Down Expand Up @@ -104,11 +106,6 @@ def fit_from(
run_time_dict=run_time_dict,
)

def visualize(self, paths, instance, during_analysis):
tracer = self.tracer_via_instance_from(instance=instance)

plotter_interface = PlotterInterface(image_path=paths.image_path)

def save_attributes(self, paths: af.DirectoryPaths):
ag.output_to_json(
obj=self.dataset,
Expand Down
119 changes: 119 additions & 0 deletions autolens/point/model/plotter_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
from os import path

from autolens.analysis.plotter_interface import PlotterInterface

from autolens.point.fit.dataset import FitPointDataset
from autolens.point.plot.fit_point_plotters import FitPointDatasetPlotter
from autolens.point.dataset import PointDataset
from autolens.point.plot.point_dataset_plotters import PointDatasetPlotter

from autolens.analysis.plotter_interface import plot_setting


class PlotterInterfacePoint(PlotterInterface):

def dataset_point(self, dataset: PointDataset):
"""
Output visualization of an `PointDataset` dataset, typically before a model-fit is performed.

Images are output to the `image` folder of the `image_path` in a subfolder called `dataset`. When used with
a non-linear search the `image_path` is the output folder of the non-linear search.
`.
Visualization includes individual images of the different points of the dataset (e.g. the positions and fluxes)

The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml` under
the `dataset` header.

Parameters
----------
dataset
The imaging dataset which is visualized.
"""

def should_plot(name):
return plot_setting(section=["point_dataset"], name=name)

mat_plot_2d = self.mat_plot_2d_from(subfolders="dataset")

dataset_plotter = PointDatasetPlotter(
dataset=dataset, mat_plot_2d=mat_plot_2d, include_2d=self.include_2d
)

dataset_plotter.figures_2d(
positions=should_plot("positions"),
fluxes=should_plot("fluxes"),
)

mat_plot_2d = self.mat_plot_2d_from(subfolders="")

dataset_plotter = PointDatasetPlotter(
dataset=dataset, mat_plot_2d=mat_plot_2d, include_2d=self.include_2d
)

if should_plot("subplot_dataset"):
dataset_plotter.subplot_dataset()

def fit_point(
self, fit: FitPointDataset, during_analysis: bool, subfolders: str = "fit_dataset"
):
"""
Visualizes a `FitPointDataset` object, which fits an imaging dataset.

Images are output to the `image` folder of the `image_path` in a subfolder called `fit`. When
used with a non-linear search the `image_path` points to the search's results folder and this function
visualizes the maximum log likelihood `FitImaging` inferred by the search so far.

Visualization includes individual images of attributes of the `FitPointDataset` (e.g. the model data and data)
and a subplot of all `FitPointDataset`'s images on the same figure.

The images output by the `PlotterInterface` are customized using the file `config/visualize/plots.yaml` under the
[fit] header.

Parameters
----------
fit
The maximum log likelihood `FitPointDataset` of the non-linear search which is used to plot the fit.
during_analysis
Whether visualization is performed during a non-linear search or once it is completed.
visuals_2d
An object containing attributes which may be plotted over the figure (e.g. the centres of mass and light
profiles).
"""

def should_plot(name):
return plot_setting(section=["fit", "fit_point_dataset"], name=name)

mat_plot_2d = self.mat_plot_2d_from(subfolders=subfolders)

fit_plotter = FitPointDatasetPlotter(
fit=fit, mat_plot_2d=mat_plot_2d, include_2d=self.include_2d
)

fit_plotter.figures_2d(
positions=should_plot("positions"),
fluxes=should_plot("fluxes"),
)

mat_plot_2d = self.mat_plot_2d_from(subfolders="")

fit_plotter = FitPointDatasetPlotter(
fit=fit, mat_plot_2d=mat_plot_2d, include_2d=self.include_2d
)

if should_plot("subplot_fit"):
fit_plotter.subplot_fit()

if not during_analysis and should_plot("all_at_end_png"):

mat_plot_2d = self.mat_plot_2d_from(
subfolders=path.join("fit_dataset", "end"),
)

fit_plotter = FitPointDatasetPlotter(
fit=fit, mat_plot_2d=mat_plot_2d, include_2d=self.include_2d
)

fit_plotter.figures_2d(
positions=True,
fluxes=True
)
88 changes: 88 additions & 0 deletions autolens/point/model/visualizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import autofit as af
import autogalaxy as ag

from autolens.point.model.plotter_interface import PlotterInterfacePoint


class VisualizerPoint(af.Visualizer):

@staticmethod
def visualize_before_fit(
analysis,
paths: af.AbstractPaths,
model: af.AbstractPriorModel,
):
"""
PyAutoFit calls this function immediately before the non-linear search begins.

It visualizes objects which do not change throughout the model fit like the dataset.

Parameters
----------
paths
The paths object which manages all paths, e.g. where the non-linear search outputs are stored,
visualization and the pickled objects used by the aggregator output by this function.
model
The model object, which includes model components representing the galaxies that are fitted to
the imaging data.
"""

plotter_interface = PlotterInterfacePoint(
image_path=paths.image_path, title_prefix=analysis.title_prefix
)

plotter_interface.dataset_point(dataset=analysis.dataset)

@staticmethod
def visualize(
analysis,
paths: af.DirectoryPaths,
instance: af.ModelInstance,
during_analysis: bool,
):
"""
Output images of the maximum log likelihood model inferred by the model-fit. This function is called throughout
the non-linear search at regular intervals, and therefore provides on-the-fly visualization of how well the
model-fit is going.

The visualization performed by this function includes:

- Images of the best-fit `Tracer`, including the images of each of its galaxies.

- Images of the best-fit `FitPointDataset`, including the model-image, residuals and chi-squared of its fit to
the imaging data.

The images output by this function are customized using the file `config/visualize/plots.yaml`.

Parameters
----------
paths
The paths object which manages all paths, e.g. where the non-linear search outputs are stored,
visualization, and the pickled objects used by the aggregator output by this function.
instance
An instance of the model that is being fitted to the data by this analysis (whose parameters have been set
via a non-linear search).
during_analysis
If True the visualization is being performed midway through the non-linear search before it is finished,
which may change which images are output.
"""
fit = analysis.fit_from(instance=instance)

plotter_interface = PlotterInterfacePoint(
image_path=paths.image_path, title_prefix=analysis.title_prefix
)

plotter_interface.fit_point(fit=fit, during_analysis=during_analysis)

tracer = fit.tracer

grid = ag.Grid2D.from_extent(extent=fit.dataset.extent_from(), shape_native=(100, 100))

plotter_interface.tracer(
tracer=tracer, grid=grid, during_analysis=during_analysis
)
plotter_interface.galaxies(
galaxies=tracer.galaxies,
grid=fit.grids.uniform,
during_analysis=during_analysis,
)
38 changes: 32 additions & 6 deletions autolens/point/plot/fit_point_plotters.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from autoarray.plot.abstract_plotters import AbstractPlotter

import autogalaxy.plot as aplt

from autolens.plot.abstract_plotters import Plotter
from autolens.point.fit.dataset import FitPointDataset


class FitPointDatasetPlotter(AbstractPlotter):
class FitPointDatasetPlotter(Plotter):
def __init__(
self,
fit: FitPointDataset,
Expand Down Expand Up @@ -37,7 +36,34 @@ def figures_2d(self, positions: bool = False, fluxes: bool = False):
if positions:
visuals_2d = self.get_visuals_2d()

visuals_2d += visuals_2d.__class__(positions=self.fit.positions.model_data)
visuals_2d += visuals_2d.__class__(
multiple_images=self.fit.positions.model_data
)

if self.mat_plot_2d.axis.kwargs.get("extent") is None:

buffer = 0.1

y_max = max(
max(self.fit.dataset.positions[:, 0]),
max(self.fit.positions.model_data[:, 0]),
) + buffer
y_min = min(
min(self.fit.dataset.positions[:, 0]),
min(self.fit.positions.model_data[:, 0]),
) - buffer
x_max = max(
max(self.fit.dataset.positions[:, 1]),
max(self.fit.positions.model_data[:, 1]),
) + buffer
x_min = min(
min(self.fit.dataset.positions[:, 1]),
min(self.fit.positions.model_data[:, 1]),
) - buffer

extent = [y_min, y_max, x_min, x_max]

self.mat_plot_2d.axis.kwargs["extent"] = extent

self.mat_plot_2d.plot_grid(
grid=self.fit.dataset.positions,
Expand All @@ -46,7 +72,7 @@ def figures_2d(self, positions: bool = False, fluxes: bool = False):
visuals_2d=visuals_2d,
auto_labels=aplt.AutoLabels(
title=f"{self.fit.dataset.name} Fit Positions",
filename="fit_point_dataset_positions",
filename="fit_point_positions",
),
buffer=0.1,
)
Expand Down Expand Up @@ -76,7 +102,7 @@ def figures_2d(self, positions: bool = False, fluxes: bool = False):
visuals_1d=visuals_1d,
auto_labels=aplt.AutoLabels(
title=f" {self.fit.dataset.name} Fit Fluxes",
filename="fit_point_dataset_fluxes",
filename="fit_point_fluxes",
xlabel="Point Number",
),
plot_axis_type_override="errorbar",
Expand Down
3 changes: 3 additions & 0 deletions test_autolens/config/visualize.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ plots:
dirty_signal_to_noise_map: false
phases_vs_uv_distances: false
uv_wavelengths: false
fit_point_dataset: # Settings for plots of fits to point source datasets (e.g. FitPointDatasetPlotter).
positions: true # Plot the positions of th multiple images of the point source in the image plane?
fluxes: true # Plot the fluxes of the multiple images of the point source in the image plane?
fit_quantity:
all_at_end_fits: true
all_at_end_png: true
Expand Down
32 changes: 32 additions & 0 deletions test_autolens/point/model/test_plotter_interface_point.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os
import shutil
from os import path

import pytest
from autolens.point.model.plotter_interface import PlotterInterfacePoint

directory = path.dirname(path.realpath(__file__))


@pytest.fixture(name="plot_path")
def make_plotter_interface_plotter_setup():
return path.join("{}".format(directory), "files")


def test__fit_point(
fit_point_dataset_x2_plane, include_2d_all, plot_path, plot_patch
):
if os.path.exists(plot_path):
shutil.rmtree(plot_path)

plotter_interface = PlotterInterfacePoint(image_path=plot_path)

plotter_interface.fit_point(
fit=fit_point_dataset_x2_plane, during_analysis=False
)

assert path.join(plot_path, "subplot_fit.png") in plot_patch.paths

plot_path = path.join(plot_path, "fit_dataset")

assert path.join(plot_path, "fit_point_positions.png") in plot_patch.paths
Loading