diff --git a/autoarray/__init__.py b/autoarray/__init__.py index 710f74094..e5740115b 100644 --- a/autoarray/__init__.py +++ b/autoarray/__init__.py @@ -34,7 +34,6 @@ from .inversion.inversion.abstract import AbstractInversion from .inversion.regularization.abstract import AbstractRegularization from .inversion.inversion.factory import inversion_from as Inversion -from .inversion.inversion.mapper_valued import MapperValued from .inversion.inversion.dataset_interface import DatasetInterface from .inversion.pixelization.border_relocator import BorderRelocator from .inversion.pixelization.pixelization import Pixelization diff --git a/autoarray/inversion/inversion/abstract.py b/autoarray/inversion/inversion/abstract.py index 1c63bc94d..9bc487868 100644 --- a/autoarray/inversion/inversion/abstract.py +++ b/autoarray/inversion/inversion/abstract.py @@ -14,6 +14,7 @@ from autoarray.inversion.inversion.settings import SettingsInversion from autoarray.preloads import Preloads from autoarray.structures.arrays.uniform_2d import Array2D +from autoarray.structures.grids.irregular_2d import Grid2DIrregular from autoarray.structures.visibilities import Visibilities from autoarray.util import misc_util @@ -754,3 +755,92 @@ def data_linear_func_matrix_dict(self): @property def mapper_operated_mapping_matrix_dict(self) -> Dict: raise NotImplementedError + + def max_pixel_list_from( + self, + total_pixels: int = 1, + filter_neighbors: bool = False, + mapper_index: int = 0, + ) -> List[List[int]]: + """ + Returns a list of lists of the maximum cell or pixel values in the mapper. + + Neighbors can be filtered such that each maximum value in a pixel is higher than all surrounding pixels, + thus forming a `peak` in the mapper values. + + For example, if a `reconstruction` is the mapper values and neighbor filtering is on, this would return the + brightest pixels in the mapper reconstruction which are brighter than all pixels around them. + + In gravitational lensing, these peaks are the brightest regions of the source reconstruction and correspond + to features like the centre of the source galaxy and knots of star formation in a galaxy. + + Parameters + ---------- + total_pixels + The total number of pixels to return in the list of peak pixels. + filter_neighbors + If True, the peak pixels are filtered such that they are the brightest pixel in the mapper and all + of its neighbors. + mapper_index + The index of the mapper in the inversion to compute the max pixels for, where there may be multiple + mappers in the inversion. + + Returns + ------- + + """ + mapper = self.cls_list_from(cls=AbstractMapper)[mapper_index] + reconstruction = self.reconstruction_dict[mapper] + + max_pixel_list = [] + + pixel_list = [] + + pixels_ascending_list = list(reversed(np.argsort(reconstruction))) + + for pixel in range(total_pixels): + pixel_index = pixels_ascending_list[pixel] + + add_pixel = True + + if filter_neighbors: + pixel_neighbors = mapper.neighbors[pixel_index] + pixel_neighbors = pixel_neighbors[pixel_neighbors >= 0] + + max_value = reconstruction[pixel_index] + max_value_neighbors = reconstruction[pixel_neighbors] + + if max_value < np.max(max_value_neighbors): + add_pixel = False + + if add_pixel: + pixel_list.append(pixel_index) + + max_pixel_list.append(pixel_list) + + return max_pixel_list + + def max_pixel_centre(self, mapper_index: int = 0) -> Grid2DIrregular: + """ + Returns the centre of the brightest pixel in the mapper values. + + Parameters + ---------- + mapper_index + The index of the mapper in the inversion to compute the max pixels for, where there may be multiple + mappers in the inversion. + + Returns + ------- + The centre of the brightest pixel in the mapper values. + """ + mapper = self.cls_list_from(cls=AbstractMapper)[mapper_index] + reconstruction = self.reconstruction_dict[mapper] + + max_pixel = np.argmax(reconstruction) + + max_pixel_centre = Grid2DIrregular( + values=[mapper.source_plane_mesh_grid.array[max_pixel]] + ) + + return max_pixel_centre diff --git a/autoarray/inversion/inversion/mapper_valued.py b/autoarray/inversion/inversion/mapper_valued.py deleted file mode 100644 index 1afd0c985..000000000 --- a/autoarray/inversion/inversion/mapper_valued.py +++ /dev/null @@ -1,311 +0,0 @@ -import numpy as np -from typing import List, Optional, Tuple - -from autoarray.structures.arrays.uniform_2d import Array2D -from autoarray.structures.grids.irregular_2d import Grid2DIrregular -from autoarray.inversion.pixelization.mappers.delaunay import MapperDelaunay - -from autoarray import exc -from autoarray.inversion.inversion import inversion_util - - -class MapperValued: - def __init__(self, mapper, values, mesh_pixel_mask: Optional[np.ndarray] = None): - """ - Pairs a `Mapper` object with an array of values (e.g. the `reconstruction` values of each value of each - mapper pixel) in order to perform calculations which use both the `Mapper` and these values. - - For example, a common use case is to interpolate the reconstruction of values on a mapper from the - mesh of the mapper (e.g. a Delaunay mesh) to a uniform Cartesian grid of values, because the irregular mesh - is difficult to plot and analyze. - - This class also provides functionality to compute the magnification of the reconstruction, by comparing the - sum of the values on the mapper in both the image and source planes, which is a specific quantity - used in gravitational lensing. - - Parameters - ---------- - mapper - The `Mapper` object which pairs with the values, for example a `MapperDelaunay` object. - values - The values of each pixel of the mapper, which could be the `reconstruction` values of an `Inversion`, - but alternatively could be other quantities such as the noise-map of these values. - mesh_pixel_mask - The mask of pixels that are omitted from the reconstruction when computing the image, for example to - remove pixels with low signal-to-noise so they do not impact the magnification calculation. - - """ - self.mapper = mapper - self.values = values - self.mesh_pixel_mask = mesh_pixel_mask - - @property - def values_masked(self): - """ - Applies the `mesh_pixel_mask` to the values, setting all masked pixels to 0.0, so that mesh pixels - can be removed to prevent them from impacting calculations. - - For example, the magnification calculation uses the values of the reconstruction to compute the magnification, - but this can be impacted by pixels with low signal-to-noise. The `mesh_pixel_mask` can be used to remove - these pixels from the calculation. - - Returns - ------- - The values of the mapper with the `mesh_pixel_mask` applied. - """ - - values = self.values - - if self.mesh_pixel_mask is not None: - if self.mapper._xp.__name__.startswith("jax"): - values = values.at[self.mesh_pixel_mask].set(0.0) - else: - values = values.copy() - values[self.mesh_pixel_mask] = 0.0 - - return values - - def interpolated_array_from( - self, - shape_native: Tuple[int, int] = (401, 401), - extent: Optional[Tuple[float, float, float, float]] = None, - ) -> Array2D: - """ - The values of a mapper can be on an irregular pixelization (e.g. a Delaunay triangulation). - - Analysing the reconstruction can therefore be difficult and require specific functionality tailored to using - this irregular grid. - - This function therefore interpolates the irregular reconstruction on to a regular grid of square pixels. - The routine that performs the interpolation is specific to each pixelization and contained in its - corresponding `Mapper`` objects, which are called by this function. - - The output interpolated reconstruction cis by default returned on a grid of 401 x 401 square pixels. This - can be customized by changing the `shape_native` input, and a rectangular grid with rectangular pixels can - be returned by instead inputting the optional `shape_scaled` tuple. - - Parameters - ---------- - shape_native - The 2D shape in pixels of the interpolated reconstruction, which is always returned using square pixels. - extent - The (x0, x1, y0, y1) extent of the grid in scaled coordinates over which the grid is created if it - is input. - """ - - return self.mapper.interpolated_array_from( - values=self.values_masked, - shape_native=shape_native, - extent=extent, - ) - - def max_pixel_list_from( - self, total_pixels: int = 1, filter_neighbors: bool = False - ) -> List[List[int]]: - """ - Returns a list of lists of the maximum cell or pixel values in the mapper. - - Neighbors can be filtered such that each maximum value in a pixel is higher than all surrounding pixels, - thus forming a `peak` in the mapper values. - - For example, if a `reconstruction` is the mapper values and neighbor filtering is on, this would return the - brightest pixels in the mapper reconstruction which are brighter than all pixels around them. - - In gravitational lensing, these peaks are the brightest regions of the source reconstruction and correspond - to features like the centre of the source galaxy and knots of star formation in a galaxy. - - Parameters - ---------- - total_pixels - The total number of pixels to return in the list of peak pixels. - filter_neighbors - If True, the peak pixels are filtered such that they are the brightest pixel in the mapper and all - of its neighbors. - - Returns - ------- - - """ - max_pixel_list = [] - - pixel_list = [] - - pixels_ascending_list = list(reversed(np.argsort(self.values_masked))) - - for pixel in range(total_pixels): - pixel_index = pixels_ascending_list[pixel] - - add_pixel = True - - if filter_neighbors: - pixel_neighbors = self.mapper.neighbors[pixel_index] - pixel_neighbors = pixel_neighbors[pixel_neighbors >= 0] - - max_value = self.values_masked[pixel_index] - max_value_neighbors = self.values_masked[pixel_neighbors] - - if max_value < np.max(max_value_neighbors): - add_pixel = False - - if add_pixel: - pixel_list.append(pixel_index) - - max_pixel_list.append(pixel_list) - - return max_pixel_list - - @property - def max_pixel_centre(self) -> Grid2DIrregular: - """ - Returns the centre of the brightest pixel in the mapper values. - - Returns - ------- - The centre of the brightest pixel in the mapper values. - """ - max_pixel = np.argmax(self.values_masked) - - max_pixel_centre = Grid2DIrregular( - values=[self.mapper.source_plane_mesh_grid.array[max_pixel]] - ) - - return max_pixel_centre - - def mapped_reconstructed_image_from( - self, - ) -> Array2D: - """ - Returns the image of the reconstruction computed via the mapping matrix, where the image is the reconstruction - of the source-plane image in the image-plane without accounting for the PSF convolution. - - This image is computed by mapping the reconstruction to the image, using the mapping matrix of the inversion. - - The image is used to compute magnification, where the magnification is the ratio of the surface brightness of - image in the image-plane over the surface brightness of the source in the source-plane. - - Returns - ------- - The image of the reconstruction computed via the mapping matrix, with the PSF convolution not accounted for. - """ - - mapping_matrix = self.mapper.mapping_matrix - - if self.mesh_pixel_mask is not None: - if self.mapper._xp.__name__.startswith("jax"): - mapping_matrix = mapping_matrix.at[:, self.mesh_pixel_mask].set(0.0) - else: - mapping_matrix[:, self.mesh_pixel_mask] = 0.0 - - return Array2D( - values=inversion_util.mapped_reconstructed_data_via_mapping_matrix_from( - mapping_matrix=mapping_matrix, - reconstruction=self.values_masked, - xp=self.mapper._xp, - ), - mask=self.mapper.mapper_grids.mask, - ) - - def magnification_via_mesh_from( - self, - ) -> float: - """ - Returns the magnification of the reconstruction computed via the mesh, where the magnification is the ratio - of the surface brightness of image in the image-plane over the surface brightness of the source in - the source-plane. - - In the image-plane, this is computed by mapping the reconstruction to the image, summing all reconstructed - values and multiplying by the area of each image pixel. This image-plane image is not convolved with the - PSF, as the source plane reconstruction is a non-convolved image. - - In the source-plane, this is computed by summing the reconstruction values multiplied by the area of each - mesh pixel, for example if the source-plane is a `Delaunay` mesh this is the area of each corresponding - Delaunay pixel. - - This calculatiion is generally more robust that using an interpolated - image (see `magnification_via_interpolation_from`), because it uses the exact the source-plane reconstruction - values. However, certain meshes have irregular pixels, especially at the edge, which can produce large - areas that can artificially decrease the magnification. Including cuts on which source-plane pixels are used, - for example based on brightness, is recommended to ensure the magnification is robust. - - Parameters - ---------- - mesh_pixel_mask - The mask of pixels that are omitted from the reconstruction when computing the image, for example to - remove pixels with low signal-to-noise so they do not impact the magnification calculation. - - Returns - ------- - The magnification of the reconstruction computed via the mesh. - """ - - if isinstance(self.mapper, MapperDelaunay): - raise exc.MeshException( - """ - The method `magnification_via_mesh_from` does not currently support `Delaunay` mesh objects. - - To compute the magnification of a `Delaunay` mesh, use the method `magnification_via_interpolation_from`. - - This method only supports a `RectangularAdaptDensity`. - """ - ) - - mapped_reconstructed_image = self.mapped_reconstructed_image_from() - - mesh_areas = self.mapper.source_plane_mesh_grid.areas_for_magnification - - if np.all(mesh_areas == 0.0): - raise exc.MeshException( - """ - The magnification cannot be computed because the areas of the source-plane mesh pixels are all zero. - - This probably means you have specified an invalid source-plane mesh. - """ - ) - - return np.sum( - mapped_reconstructed_image * mapped_reconstructed_image.pixel_area - ) / np.sum(self.values_masked * mesh_areas) - - def magnification_via_interpolation_from( - self, - shape_native: Tuple[int, int] = (201, 201), - extent: Optional[Tuple[float, float, float, float]] = None, - ) -> float: - """ - Returns the magnification of the reconstruction computed via interpolation, where the magnification is the ratio - of the surface brightness of image in the image-plane over the surface brightness of the source in - the source-plane. - - In the image-plane, this is computed by mapping the reconstruction to the image, summing all reconstructed - values and multiplying by the area of each image pixel. This image-plane image is not convolved with the - PSF, as the source plane reconstruction is a non-convolved image. This image therefore does not use - interpolation. - - In the source-plane, this is computed by interpolating the reconstruction to a regular grid of pixels, for - example a 2D grid of 401 x 401 pixels, and summing the reconstruction values multiplied by the area of each - pixel. This calculation uses interpolation to compute the source-plane image. - - This calculation is generally less robust than using the mesh to compute the magnification, - (see `magnification_via_mesh_from`), as the interpolation may not perfectly represent the source-plane - reconstruction. However, it is computationally faster and can be used when the source-plane mesh has - irregular pixels that are not suitable for computing the magnification. - - Parameters - ---------- - mesh_pixel_mask - The mask of pixels that are omitted from the reconstruction when computing the image, for example to - remove pixels with low signal-to-noise so they do not impact the magnification calculation. - - Returns - ------- - The magnification of the reconstruction computed via interpolation. - """ - mapped_reconstructed_image = self.mapped_reconstructed_image_from() - - interpolated_reconstruction = self.interpolated_array_from( - shape_native=shape_native, extent=extent - ) - - return np.sum( - mapped_reconstructed_image * mapped_reconstructed_image.pixel_area - ) / np.sum(interpolated_reconstruction * interpolated_reconstruction.pixel_area) diff --git a/autoarray/inversion/mock/mock_mapper.py b/autoarray/inversion/mock/mock_mapper.py index ab9a1f0ca..529155db8 100644 --- a/autoarray/inversion/mock/mock_mapper.py +++ b/autoarray/inversion/mock/mock_mapper.py @@ -20,7 +20,6 @@ def __init__( mapping_matrix=None, pixel_signals=None, parameters=None, - interpolated_array=None, ): mapper_grids = MapperGrids( mask=mask, @@ -41,7 +40,6 @@ def __init__( self._mapping_matrix = mapping_matrix self._parameters = parameters self._pixel_signals = pixel_signals - self._interpolated_array = interpolated_array def pixel_signals_from(self, signal_scale, xp=np): if self._pixel_signals is None: @@ -71,11 +69,3 @@ def pix_sub_weights_split_points(self): @property def mapping_matrix(self): return self._mapping_matrix - - def interpolated_array_from( - self, - values: np.ndarray, - shape_native: Tuple[int, int] = (401, 401), - extent: Optional[Tuple[float, float, float, float]] = None, - ): - return self._interpolated_array diff --git a/autoarray/inversion/pixelization/mappers/abstract.py b/autoarray/inversion/pixelization/mappers/abstract.py index c06b5b51d..e13ec3470 100644 --- a/autoarray/inversion/pixelization/mappers/abstract.py +++ b/autoarray/inversion/pixelization/mappers/abstract.py @@ -410,42 +410,6 @@ def extent_from( extent=self.source_plane_mesh_grid.geometry.extent ) - def interpolated_array_from( - self, - values: np.ndarray, - shape_native: Tuple[int, int] = (401, 401), - extent: Optional[Tuple[float, float, float, float]] = None, - ) -> Array2D: - """ - The reconstructed values of a mapper (e.g. the `reconstruction` of an `Inversion` may be on an irregular - pixelization (e.g. a Delaunay triangulation). - - Analysing the reconstruction can therefore be difficult and require specific functionality tailored to using - this irregular grid. - - This function offers a simple alternative is therefore to interpolate the irregular reconstruction on to a - regular grid of square pixels. The routine that performs the interpolation is specific to each pixelization - and contained `Grid2DMesh` object, which are called by this function. - - The output interpolated reconstruction is by default returned on a grid of 401 x 401 square pixels. This - can be customized by changing the `shape_native` input, and a rectangular grid with rectangular pixels can - be returned by instead inputting the optional `shape_scaled` tuple. - - Parameters - ---------- - values - The value corresponding to the reconstructed value of every pixelization pixel (e.g. Delaunay triangle - vertexes). - shape_native - The 2D shape in pixels of the interpolated reconstruction, which is always returned using square pixels. - extent - The (x0, x1, y0, y1) extent of the grid in scaled coordinates over which the grid is created if it - is input. - """ - return self.source_plane_mesh_grid.interpolated_array_from( - values=values, shape_native=shape_native, extent=extent - ) - class PixSubWeights: def __init__(self, mappings: np.ndarray, sizes: np.ndarray, weights: np.ndarray): diff --git a/autoarray/inversion/pixelization/mappers/mapper_numba_util.py b/autoarray/inversion/pixelization/mappers/mapper_numba_util.py index 896eb0c10..de787f4a5 100644 --- a/autoarray/inversion/pixelization/mappers/mapper_numba_util.py +++ b/autoarray/inversion/pixelization/mappers/mapper_numba_util.py @@ -1,12 +1,7 @@ import numpy as np from typing import Tuple -from autoconf import conf - from autoarray import numba_util -from autoarray.inversion.pixelization.mesh import mesh_numba_util - -from autoarray import exc @numba_util.jit() diff --git a/autoarray/inversion/pixelization/mappers/rectangular.py b/autoarray/inversion/pixelization/mappers/rectangular.py index ace9c82c0..cf9e5290a 100644 --- a/autoarray/inversion/pixelization/mappers/rectangular.py +++ b/autoarray/inversion/pixelization/mappers/rectangular.py @@ -128,6 +128,18 @@ def areas_transformed(self): xp=self._xp, ) + @property + def areas_for_magnification(self): + """ + The area of every pixel in the rectangular pixelization. + + Returns + ------- + ndarray + The area of every pixel in the rectangular pixelization. + """ + return self.areas_transformed + @property def edges_transformed(self): """ diff --git a/autoarray/inversion/pixelization/mesh/mesh_numba_util.py b/autoarray/inversion/pixelization/mesh/mesh_numba_util.py deleted file mode 100644 index fca9cbc46..000000000 --- a/autoarray/inversion/pixelization/mesh/mesh_numba_util.py +++ /dev/null @@ -1,124 +0,0 @@ -import numpy as np - -from typing import List, Tuple, Union - -from autoarray import numba_util - - -@numba_util.jit() -def delaunay_triangle_area_from( - corner_0: Tuple[float, float], - corner_1: Tuple[float, float], - corner_2: Tuple[float, float], -) -> float: - """ - Returns the area within a Delaunay triangle where the three corners are located at the (x,y) coordinates given by - the inputs `corner_a` `corner_b` and `corner_c`. - - This function actually returns the area of any triangle, but the term `delaunay` is included in the title to - separate it from the `rectangular` and `voronoi` methods in `mesh_util.py`. - - Parameters - ---------- - corner_0 - The (x,y) coordinates of the triangle's first corner. - corner_1 - The (x,y) coordinates of the triangle's second corner. - corner_2 - The (x,y) coordinates of the triangle's third corner. - - Returns - ------- - The area of the triangle given the input (x,y) corners. - """ - - x1 = corner_0[0] - y1 = corner_0[1] - x2 = corner_1[0] - y2 = corner_1[1] - x3 = corner_2[0] - y3 = corner_2[1] - - return 0.5 * np.abs(x1 * y2 + x2 * y3 + x3 * y1 - x2 * y1 - x3 * y2 - x1 * y3) - - -def delaunay_interpolated_array_from( - shape_native: Tuple[int, int], - interpolation_grid_slim: np.ndarray, - pixel_values: np.ndarray, - delaunay: "scipy.spatial.Delaunay", -) -> np.ndarray: - """ - Given a Delaunay triangulation and 1D values at the node of each Delaunay pixel (e.g. the connecting points where - triangles meet), interpolate these values to a uniform 2D (y,x) grid. - - By mapping the delaunay's value to a regular grid this enables a source reconstruction of an inversion to be - output to a .fits file. - - The `grid_interpolate_slim`, which gives the (y,x) coordinates the values are evaluated at for interpolation, - need not be regular and can have undergone coordinate transforms (e.g. it can be the `source_plane_mesh_grid`) - of a `Mapper`. - - The shape of `grid_interpolate_slim` therefore must be equal to `shape_native[0] * shape_native[1]`, but the (y,x) - coordinates themselves do not need to be uniform. - - Parameters - ---------- - shape_native - The 2D (y,x) shape of the uniform grid the values are interpolated on too. - interpolation_grid_slim - A 1D grid of (y,x) coordinates where each interpolation is evaluated. The shape of this grid must be equal to - shape_native[0] * shape_native[1], but it does not need to be uniform itself. - pixel_values - The values of the Delaunay nodes (e.g. the connecting points where triangles meet) which are interpolated - to compute the value in each pixel on the `interpolated_grid`. - delaunay - A `scipy.spatial.Delaunay` object which contains all functionality describing the Delaunay triangulation. - - Returns - ------- - The input values interpolated to the `grid_interpolate_slim` (y,x) coordintes given the Delaunay triangulation. - - """ - simplex_index_for_interpolate_index = delaunay.find_simplex(interpolation_grid_slim) - - simplices = delaunay.simplices - pixel_points = delaunay.points - - interpolated_array = np.zeros(len(interpolation_grid_slim)) - - for slim_index in range(len(interpolation_grid_slim)): - simplex_index = simplex_index_for_interpolate_index[slim_index] - interpolating_point = tuple(interpolation_grid_slim[slim_index]) - - if simplex_index == -1: - cloest_pixel_index = np.argmin( - np.sum((pixel_points - interpolating_point) ** 2.0, axis=1) - ) - interpolated_array[slim_index] = pixel_values[cloest_pixel_index] - else: - triangle_points = pixel_points[simplices[simplex_index]] - triangle_values = pixel_values[simplices[simplex_index]] - - area_0 = delaunay_triangle_area_from( - corner_0=triangle_points[1], - corner_1=triangle_points[2], - corner_2=interpolating_point, - ) - area_1 = delaunay_triangle_area_from( - corner_0=triangle_points[0], - corner_1=triangle_points[2], - corner_2=interpolating_point, - ) - area_2 = delaunay_triangle_area_from( - corner_0=triangle_points[0], - corner_1=triangle_points[1], - corner_2=interpolating_point, - ) - norm = area_0 + area_1 + area_2 - - weight_abc = np.array([area_0, area_1, area_2]) / norm - - interpolated_array[slim_index] = np.sum(weight_abc * triangle_values) - - return interpolated_array.reshape(shape_native) diff --git a/autoarray/inversion/plot/inversion_plotters.py b/autoarray/inversion/plot/inversion_plotters.py index 1710c23cb..5b747f2f0 100644 --- a/autoarray/inversion/plot/inversion_plotters.py +++ b/autoarray/inversion/plot/inversion_plotters.py @@ -9,7 +9,6 @@ from autoarray.plot.auto_labels import AutoLabels from autoarray.structures.arrays.uniform_2d import Array2D from autoarray.inversion.inversion.abstract import AbstractInversion -from autoarray.inversion.inversion.mapper_valued import MapperValued from autoarray.inversion.plot.mapper_plotters import MapperPlotter @@ -102,7 +101,6 @@ def figures_2d_of_pixelization( image_pixels_per_mesh_pixel: bool = False, magnification_per_mesh_pixel: bool = False, zoom_to_brightest: bool = True, - interpolate_to_uniform: bool = False, ): """ Plots the individual attributes of a specific `Mapper` of the plotter's `Inversion` object in 2D. @@ -137,9 +135,6 @@ def figures_2d_of_pixelization( zoom_to_brightest For images not in the image-plane (e.g. the `plane_image`), whether to automatically zoom the plot to the brightest regions of the galaxies being plotted as opposed to the full extent of the grid. - interpolate_to_uniform - If `True`, the mapper's reconstruction is interpolated to a uniform grid before plotting, for example - meaning that an irregular Delaunay grid can be plotted as a uniform grid. """ if not self.inversion.has(cls=AbstractMapper): @@ -199,7 +194,6 @@ def figures_2d_of_pixelization( mapper_plotter.plot_source_from( pixel_values=pixel_values, zoom_to_brightest=zoom_to_brightest, - interpolate_to_uniform=interpolate_to_uniform, auto_labels=AutoLabels( title="Source Reconstruction", filename="reconstruction" ), @@ -419,12 +413,10 @@ def subplot_mappings( mapper = self.inversion.cls_list_from(cls=AbstractMapper)[pixelization_index] - mapper_valued = MapperValued( - values=self.inversion.reconstruction_dict[mapper], mapper=mapper - ) - - pix_indexes = mapper_valued.max_pixel_list_from( - total_pixels=total_pixels, filter_neighbors=True + pix_indexes = self.inversion.max_pixel_list_from( + total_pixels=total_pixels, + filter_neighbors=True, + mapper_index=pixelization_index, ) indexes = mapper.slim_indexes_for_pix_indexes(pix_indexes=pix_indexes) diff --git a/autoarray/inversion/plot/mapper_plotters.py b/autoarray/inversion/plot/mapper_plotters.py index 9f35bf037..83cfb79a3 100644 --- a/autoarray/inversion/plot/mapper_plotters.py +++ b/autoarray/inversion/plot/mapper_plotters.py @@ -46,25 +46,18 @@ def __init__( self.mapper = mapper - def figure_2d( - self, interpolate_to_uniform: bool = False, solution_vector: bool = None - ): + def figure_2d(self, solution_vector: bool = None): """ Plots the plotter's `Mapper` object in 2D. Parameters ---------- - interpolate_to_uniform - By default, the mesh's reconstruction is interpolated to a uniform 2D array for plotting. If the - reconstruction can be plotted in an alternative format (e.g. using a Delaunay mesh) - settings `interpolate_to_uniform=False` plots the reconstruction using this. solution_vector A vector of values which can culor the pixels of the mapper's source pixels. """ self.mat_plot_2d.plot_mapper( mapper=self.mapper, visuals_2d=self.visuals_2d, - interpolate_to_uniform=interpolate_to_uniform, pixel_values=solution_vector, auto_labels=AutoLabels( title="Pixelization Mesh (Source-Plane)", filename="mapper" @@ -83,7 +76,8 @@ def figure_2d_image(self, image): ) def subplot_image_and_mapper( - self, image: Array2D, interpolate_to_uniform: bool = False + self, + image: Array2D, ): """ Make a subplot of an input image and the `Mapper`'s source-plane reconstruction. @@ -94,17 +88,13 @@ def subplot_image_and_mapper( Parameters ---------- - interpolate_to_uniform - By default, the mesh's reconstruction is interpolated to a uniform 2D array for plotting. If the - reconstruction can be plotted in an alternative format (e.g. a Delaunay mesh) - settings `interpolate_to_uniform=False` plots the reconstruction using this. image The image which is plotted on the subplot. """ self.open_subplot_figure(number_subplots=2) self.figure_2d_image(image=image) - self.figure_2d(interpolate_to_uniform=interpolate_to_uniform) + self.figure_2d() self.mat_plot_2d.output.subplot_to_figure( auto_filename="subplot_image_and_mapper" @@ -115,7 +105,6 @@ def plot_source_from( self, pixel_values: np.ndarray, zoom_to_brightest: bool = True, - interpolate_to_uniform: bool = False, auto_labels: AutoLabels = AutoLabels(), ): """ @@ -128,9 +117,6 @@ def plot_source_from( zoom_to_brightest For images not in the image-plane (e.g. the `plane_image`), whether to automatically zoom the plot to the brightest regions of the galaxies being plotted as opposed to the full extent of the grid. - interpolate_to_uniform - If `True`, the mapper's reconstruction is interpolated to a uniform grid before plotting, for example - meaning that an irregular Delaunay grid can be plotted as a uniform grid. auto_labels The labels given to the figure. """ @@ -141,7 +127,6 @@ def plot_source_from( auto_labels=auto_labels, pixel_values=pixel_values, zoom_to_brightest=zoom_to_brightest, - interpolate_to_uniform=interpolate_to_uniform, ) except ValueError: logger.info( diff --git a/autoarray/plot/__init__.py b/autoarray/plot/__init__.py index 39693d1eb..1ec4ff8ad 100644 --- a/autoarray/plot/__init__.py +++ b/autoarray/plot/__init__.py @@ -28,9 +28,6 @@ from autoarray.plot.wrap.two_d.grid_errorbar import GridErrorbar from autoarray.plot.wrap.two_d.vector_yx_quiver import VectorYXQuiver from autoarray.plot.wrap.two_d.patch_overlay import PatchOverlay -from autoarray.plot.wrap.two_d.interpolated_reconstruction import ( - InterpolatedReconstruction, -) from autoarray.plot.wrap.two_d.delaunay_drawer import DelaunayDrawer from autoarray.plot.wrap.two_d.origin_scatter import OriginScatter from autoarray.plot.wrap.two_d.mask_scatter import MaskScatter diff --git a/autoarray/plot/mat_plot/two_d.py b/autoarray/plot/mat_plot/two_d.py index 4c5246f95..2bf1cc8a7 100644 --- a/autoarray/plot/mat_plot/two_d.py +++ b/autoarray/plot/mat_plot/two_d.py @@ -49,7 +49,6 @@ def __init__( grid_errorbar: Optional[w2d.GridErrorbar] = None, vector_yx_quiver: Optional[w2d.VectorYXQuiver] = None, patch_overlay: Optional[w2d.PatchOverlay] = None, - interpolated_reconstruction: Optional[w2d.InterpolatedReconstruction] = None, delaunay_drawer: Optional[w2d.DelaunayDrawer] = None, origin_scatter: Optional[w2d.OriginScatter] = None, mask_scatter: Optional[w2d.MaskScatter] = None, @@ -135,8 +134,6 @@ def __init__( Overlays matplotlib `patches.Patch` objects over the figure, such as an `Ellipse`. delaunay_drawer Draws a colored Delaunay mesh of pixels using `plt.tripcolor`. - interpolated_reconstruction - Draws a colored Delaunay mesh of pixels using `plt.fill`. origin_scatter Scatters the (y,x) origin of the data structure on the figure. mask_scatter @@ -190,10 +187,6 @@ def __init__( self.vector_yx_quiver = vector_yx_quiver or w2d.VectorYXQuiver(is_default=True) self.patch_overlay = patch_overlay or w2d.PatchOverlay(is_default=True) - self.interpolated_reconstruction = ( - interpolated_reconstruction - or w2d.InterpolatedReconstruction(is_default=True) - ) self.delaunay_drawer = delaunay_drawer or w2d.DelaunayDrawer(is_default=True) self.origin_scatter = origin_scatter or w2d.OriginScatter(is_default=True) @@ -493,7 +486,6 @@ def plot_mapper( mapper: MapperRectangular, visuals_2d: Visuals2D, auto_labels: AutoLabels, - interpolate_to_uniform: bool = False, pixel_values: np.ndarray = Optional[None], zoom_to_brightest: bool = True, ): @@ -511,7 +503,6 @@ def plot_mapper( mapper=mapper, visuals_2d=visuals_2d, auto_labels=auto_labels, - interpolate_to_uniform=interpolate_to_uniform, pixel_values=pixel_values, zoom_to_brightest=zoom_to_brightest, ) @@ -657,7 +648,6 @@ def _plot_delaunay_mapper( mapper: MapperDelaunay, visuals_2d: Visuals2D, auto_labels: AutoLabels, - interpolate_to_uniform: bool = False, pixel_values: np.ndarray = Optional[None], zoom_to_brightest: bool = True, ): @@ -694,36 +684,19 @@ def _plot_delaunay_mapper( interpolation_array = None - if interpolate_to_uniform: - interpolation_array = ( - self.interpolated_reconstruction.imshow_reconstruction( - mapper=mapper, - pixel_values=pixel_values, - units=self.units, - cmap=self.cmap, - colorbar=self.colorbar, - colorbar_tickparams=self.colorbar_tickparams, - aspect=aspect_inv, - ax=ax, - use_log10=self.use_log10, - ) - ) - - else: - - if hasattr(pixel_values, "array"): - pixel_values = pixel_values.array + if hasattr(pixel_values, "array"): + pixel_values = pixel_values.array - self.delaunay_drawer.draw_delaunay_pixels( - mapper=mapper, - pixel_values=pixel_values, - units=self.units, - cmap=self.cmap, - colorbar=self.colorbar, - colorbar_tickparams=self.colorbar_tickparams, - ax=ax, - use_log10=self.use_log10, - ) + self.delaunay_drawer.draw_delaunay_pixels( + mapper=mapper, + pixel_values=pixel_values, + units=self.units, + cmap=self.cmap, + colorbar=self.colorbar, + colorbar_tickparams=self.colorbar_tickparams, + ax=ax, + use_log10=self.use_log10, + ) self.title.set(auto_title=auto_labels.title) self.ylabel.set() diff --git a/autoarray/plot/wrap/__init__.py b/autoarray/plot/wrap/__init__.py index 6166ddebc..3da942a38 100644 --- a/autoarray/plot/wrap/__init__.py +++ b/autoarray/plot/wrap/__init__.py @@ -25,9 +25,6 @@ from autoarray.plot.wrap.two_d.grid_errorbar import GridErrorbar from autoarray.plot.wrap.two_d.vector_yx_quiver import VectorYXQuiver from autoarray.plot.wrap.two_d.patch_overlay import PatchOverlay -from autoarray.plot.wrap.two_d.interpolated_reconstruction import ( - InterpolatedReconstruction, -) from autoarray.plot.wrap.two_d.origin_scatter import OriginScatter from autoarray.plot.wrap.two_d.mask_scatter import MaskScatter from autoarray.plot.wrap.two_d.border_scatter import BorderScatter diff --git a/autoarray/plot/wrap/two_d/__init__.py b/autoarray/plot/wrap/two_d/__init__.py index f4bb5e1ab..8490a9af0 100644 --- a/autoarray/plot/wrap/two_d/__init__.py +++ b/autoarray/plot/wrap/two_d/__init__.py @@ -6,9 +6,6 @@ from .grid_errorbar import GridErrorbar from .vector_yx_quiver import VectorYXQuiver from .patch_overlay import PatchOverlay -from .interpolated_reconstruction import ( - InterpolatedReconstruction, -) from .delaunay_drawer import DelaunayDrawer from .origin_scatter import OriginScatter from .mask_scatter import MaskScatter diff --git a/autoarray/plot/wrap/two_d/interpolated_reconstruction.py b/autoarray/plot/wrap/two_d/interpolated_reconstruction.py deleted file mode 100644 index 23d750683..000000000 --- a/autoarray/plot/wrap/two_d/interpolated_reconstruction.py +++ /dev/null @@ -1,110 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -from typing import Union - -from autoarray.plot.wrap.two_d.abstract import AbstractMatWrap2D -from autoarray.plot.wrap.base.units import Units -from autoarray.inversion.pixelization.mappers.delaunay import MapperDelaunay - -from autoarray.plot.wrap import base as wb - - -class InterpolatedReconstruction(AbstractMatWrap2D): - """ - Given a `Mapper` and a corresponding array of `pixel_values` (e.g. the reconstruction values of a Delaunay - triangulation) plot the values using `plt.imshow()`. - - The `pixel_values` are an ndarray of values which correspond to the irregular pixels of the mesh (e.g. for - a Delaunay triangulation they are the connecting corners of each triangle). This cannot be plotted - with `imshow()`, therefore this class first converts the `pixel_values` from this irregular grid to a uniform 2D - array of square pixels via interpolation. - - The interpolation routine depends on the `Mapper`, with most mappers having their own built-in interpolation - routine specific to that pixelization's mesh. - - This object wraps methods described in below: - - - plt.imshow: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.imshow.html - """ - - def imshow_reconstruction( - self, - mapper: Union[MapperDelaunay], - pixel_values: np.ndarray, - units: Units, - cmap: wb.Cmap, - colorbar: wb.Colorbar, - colorbar_tickparams: wb.ColorbarTickParams = None, - aspect=None, - ax=None, - use_log10: bool = False, - ): - """ - Given a `Mapper` and a corresponding array of `pixel_values` (e.g. the reconstruction values of a Delaunay - triangulation) plot the values using `plt.imshow()`. - - The `pixel_values` are an ndarray of values which correspond to the irregular pixels of the mesh (e.g. for - a Delaunay triangulation they are the connecting corners of each triangle). This cannot be plotted - with `imshow()`, therefore this class first converts the `pixel_values` from this irregular grid to a uniform 2D - array of square pixels via interpolation. - - The interpolation routine depends on the `Mapper`, with most mappers having their own built-in interpolation - routine specific to that pixelization's mesh. - - This object wraps methods described in below: - - - plt.imshow: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.imshow.html - - Parameters - ---------- - mapper - An object which contains a 2D mesh (e.g. Delaunay mesh cells) and defines how to - interpolate values from the pixelization's mesh. - pixel_values - The pixel values of the pixelization's mesh (e.g. a Delaunay mesh) which are interpolated to a uniform square - array for plotting with `imshow()`. - cmap - The colormap used by `imshow()` to plot the pixelization's mesh values. - colorbar - The `Colorbar` object in `mat_base` used to set the colorbar of the figure the interpolated pixelization's mesh - values (e.g. values interpolated from the Delaunay mesh) are plotted on. - colorbar_tickparams - Controls the tick parameters of the colorbar. - """ - - if pixel_values is None: - return - - interpolation_array = mapper.interpolated_array_from(values=pixel_values) - - norm = cmap.norm_from(array=interpolation_array, use_log10=use_log10) - - vmin = cmap.vmin_from(array=pixel_values, use_log10=use_log10) - vmax = cmap.vmax_from(array=pixel_values, use_log10=use_log10) - - color_values = np.where(pixel_values > vmax, vmax, pixel_values) - color_values = np.where(pixel_values < vmin, vmin, color_values) - - cmap = plt.get_cmap(cmap.cmap) - - if colorbar is not None: - colorbar = colorbar.set_with_color_values( - units=units, - cmap=cmap, - norm=norm, - color_values=color_values, - ax=ax, - use_log10=use_log10, - ) - if colorbar is not None and colorbar_tickparams is not None: - colorbar_tickparams.set(cb=colorbar) - - plt.imshow( - X=interpolation_array.native, - cmap=cmap, - norm=norm, - extent=mapper.source_plane_mesh_grid.geometry.extent_square, - aspect=aspect, - ) - - return interpolation_array diff --git a/autoarray/structures/mesh/delaunay_2d.py b/autoarray/structures/mesh/delaunay_2d.py index 782cdd139..3bd8cf466 100644 --- a/autoarray/structures/mesh/delaunay_2d.py +++ b/autoarray/structures/mesh/delaunay_2d.py @@ -11,7 +11,6 @@ from autoarray.inversion.linear_obj.neighbors import Neighbors from autoarray import exc -from autoarray.inversion.pixelization.mesh import mesh_numba_util def scipy_delaunay(points_np, query_points_np, use_voronoi_areas, areas_factor): @@ -550,55 +549,6 @@ def neighbors(self) -> Neighbors: return Neighbors(arr=neighbors.astype("int"), sizes=sizes.astype("int")) - def interpolated_array_from( - self, - values: np.ndarray, - shape_native: Tuple[int, int] = (401, 401), - extent: Optional[Tuple[float, float, float, float]] = None, - ) -> Array2D: - """ - The reconstruction of data on a `Delaunay` triangulation (e.g. the `reconstruction` output from an `Inversion`) - is on irregular pixelization. - - Analysing the reconstruction can therefore be difficult and require specific functionality tailored to the - `Delaunay` triangulation. - - This function therefore interpolates the irregular reconstruction on to a regular grid of square pixels. - The routine uses the Delaunay triangulation interpolation weights based on the area of each triangle to - perform this interpolation. - - The output interpolated reconstruction cis by default returned on a grid of 401 x 401 square pixels. This - can be customized by changing the `shape_native` input, and a rectangular grid with rectangular pixels can - be returned by instead inputting the optional `shape_scaled` tuple. - - Parameters - ---------- - values - The value corresponding to the reconstructed value of Delaunay triangle vertex. - shape_native - The 2D shape in pixels of the interpolated reconstruction, which is always returned using square pixels. - extent - The (x0, x1, y0, y1) extent of the grid in scaled coordinates over which the grid is created if it - is input. - """ - # Uses find simplex so recomputes delaunay internally - delaunay = Delaunay(self.mesh_grid_xy) - - interpolation_grid = self.interpolation_grid_from( - shape_native=shape_native, extent=extent - ) - - interpolated_array = mesh_numba_util.delaunay_interpolated_array_from( - shape_native=shape_native, - interpolation_grid_slim=np.array(interpolation_grid.slim.array), - delaunay=delaunay, - pixel_values=values, - ) - - return Array2D.no_mask( - values=interpolated_array, pixel_scales=interpolation_grid.pixel_scales - ) - @cached_property def voronoi(self) -> "scipy.spatial.Voronoi": """ diff --git a/autoarray/structures/mesh/rectangular_2d.py b/autoarray/structures/mesh/rectangular_2d.py index 0bda2cace..d1ec1c0f3 100644 --- a/autoarray/structures/mesh/rectangular_2d.py +++ b/autoarray/structures/mesh/rectangular_2d.py @@ -135,50 +135,3 @@ def pixels(self) -> int: The total number of pixels in the rectangular pixelization. """ return self.shape_native[0] * self.shape_native[1] - - def interpolated_array_from( - self, - values: np.ndarray, - shape_native: Tuple[int, int] = (401, 401), - extent: Optional[Tuple[float, float, float, float]] = None, - ) -> Array2D: - """ - The reconstruction of data certain pixelizations, for example a `Delaunay` triangulation, requires that - reconstructed data (e.g. the `reconstruction` output from an `Inversion`) is on an irregular pixelization. - - Analysing the reconstruction can therefore be difficult and require specific functionality tailored to the - `Delaunay` triangulation. - - This function therefore interpolates the reconstruction on to a regular grid of square pixels. - For a rectangular pixelization which is uniform, this is not stricly necessary as the native grid is - easy to analyse. This interpolation function is included partly to mirror the API of other pixelizations. - - The output interpolated reconstruction cis by default returned on a grid of 401 x 401 square pixels. This - can be customized by changing the `shape_native` input, and a rectangular grid with rectangular pixels can - be returned by instead inputting the optional `shape_scaled` tuple. - - Parameters - ---------- - values - The value corresponding to the reconstructed value of every rectangular pixel on the rectangular grid. - shape_native - The 2D shape in pixels of the interpolated reconstruction, which is always returned using square pixels. - extent - The (x0, x1, y0, y1) extent of the grid in scaled coordinates over which the grid is created if it - is input. - """ - from scipy.interpolate import griddata - - interpolation_grid = self.interpolation_grid_from( - shape_native=shape_native, extent=extent - ) - - interpolated_array = griddata( - points=self.array, values=values, xi=interpolation_grid - ) - - interpolated_array = interpolated_array.reshape(shape_native) - - return Array2D.no_mask( - values=interpolated_array, pixel_scales=interpolation_grid.pixel_scales - ) diff --git a/autoarray/util/__init__.py b/autoarray/util/__init__.py index 363c400f6..5342717be 100644 --- a/autoarray/util/__init__.py +++ b/autoarray/util/__init__.py @@ -11,7 +11,6 @@ from autoarray.layout import layout_util as layout from autoarray.fit import fit_util as fit from autoarray.inversion.pixelization.mesh import mesh_util as mesh -from autoarray.inversion.pixelization.mesh import mesh_numba_util as mesh_numba from autoarray.inversion.pixelization.mappers import mapper_util as mapper from autoarray.inversion.pixelization.mappers import mapper_numba_util as mapper_numba from autoarray.inversion.regularization import regularization_util as regularization diff --git a/test_autoarray/inversion/inversion/test_abstract.py b/test_autoarray/inversion/inversion/test_abstract.py index 249a75f77..47c462de9 100644 --- a/test_autoarray/inversion/inversion/test_abstract.py +++ b/test_autoarray/inversion/inversion/test_abstract.py @@ -4,8 +4,6 @@ import autoarray as aa -from autoarray import exc - directory = path.dirname(path.realpath(__file__)) @@ -514,3 +512,53 @@ def test__reconstruction_noise_map(): assert inversion.reconstruction_noise_map == pytest.approx( np.sqrt(np.array([2.5, 1.0, 0.5])), 1.0e-3 ) + + +def test__max_pixel_list_from_and_centre(): + mapper = aa.m.MockMapper( + source_plane_mesh_grid=aa.Mesh2DDelaunay( + [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [5.0, 0.0]] + ) + ) + + inversion = aa.m.MockInversion( + reconstruction=np.array([2.0, 3.0, 5.0, 0.0]), linear_obj_list=[mapper] + ) + + assert inversion.max_pixel_list_from(total_pixels=2)[0] == [ + 2, + 1, + ] + + assert inversion.max_pixel_centre().in_list == [(5.0, 6.0)] + + +def test__max_pixel_list_from__filter_neighbors(): + + mapper = aa.m.MockMapper( + source_plane_mesh_grid=aa.Mesh2DDelaunay( + [ + [1.0, 1.0], + [1.0, 2.0], + [1.0, 3.0], + [2.0, 1.0], + [2.0, 2.0], + [2.0, 3.0], + [3.0, 1.0], + [3.0, 2.0], + [3.0, 3.0], + ] + ) + ) + + inversion = aa.m.MockInversion( + reconstruction=np.array([5.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]), + linear_obj_list=[mapper], + ) + + pixel_list = inversion.max_pixel_list_from(total_pixels=9, filter_neighbors=True) + + assert pixel_list[0] == [ + 0, + 8, + ] diff --git a/test_autoarray/inversion/inversion/test_mapper_valued.py b/test_autoarray/inversion/inversion/test_mapper_valued.py deleted file mode 100644 index f74662628..000000000 --- a/test_autoarray/inversion/inversion/test_mapper_valued.py +++ /dev/null @@ -1,215 +0,0 @@ -import numpy as np -import pytest - -import autoarray as aa - - -def test__max_pixel_list_from_and_centre(): - mapper = aa.m.MockMapper( - source_plane_mesh_grid=aa.Mesh2DDelaunay( - [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [5.0, 0.0]] - ) - ) - - mapper_valued = aa.MapperValued( - values=np.array([2.0, 3.0, 5.0, 0.0]), mapper=mapper - ) - - assert mapper_valued.max_pixel_list_from(total_pixels=2)[0] == [ - 2, - 1, - ] - - assert mapper_valued.max_pixel_centre.in_list == [(5.0, 6.0)] - - -def test__max_pixel_list_from__filter_neighbors(): - mapper = aa.m.MockMapper( - source_plane_mesh_grid=aa.Mesh2DDelaunay( - [ - [1.0, 1.0], - [1.0, 2.0], - [1.0, 3.0], - [2.0, 1.0], - [2.0, 2.0], - [2.0, 3.0], - [3.0, 1.0], - [3.0, 2.0], - [3.0, 3.0], - ] - ) - ) - - mapper_valued = aa.MapperValued( - values=np.array([5.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]), mapper=mapper - ) - - pixel_list = mapper_valued.max_pixel_list_from( - total_pixels=9, filter_neighbors=True - ) - - assert pixel_list[0] == [ - 0, - 8, - ] - - -def test__interpolated_array_from(): - values = np.array([0.0, 1.0, 1.0, 1.0]) - - mapper = aa.m.MockMapper(parameters=4, interpolated_array=values) - - mapper_valued = aa.MapperValued(values=values, mapper=mapper) - - values = mapper_valued.interpolated_array_from( - shape_native=(3, 3), extent=(-0.2, 0.2, -0.3, 0.3) - ) - - assert (values == np.array([0.0, 1.0, 1.0, 1.0])).all() - - -def test__interpolated_array_from__with_pixel_mask(): - values = np.array([0.0, 1.0, 1.0, 1.0]) - - mapper = aa.m.MockMapper(parameters=4, interpolated_array=values) - - mesh_pixel_mask = np.array([True, False, False, True]) - - mapper_valued = aa.MapperValued( - values=values, mapper=mapper, mesh_pixel_mask=mesh_pixel_mask - ) - - values = mapper_valued.interpolated_array_from( - shape_native=(3, 3), extent=(-0.2, 0.2, -0.3, 0.3) - ) - - assert values == pytest.approx(np.array([0.0, 1.0, 1.0, 1.0]), 1.0e-4) - - -def test__magnification_via_mesh_from(): - mask = aa.Mask2D( - mask=np.array( - [ - [False, False, False], - [False, False, False], - [False, False, False], - [False, False, False], - ] - ), - pixel_scales=(0.5, 0.5), - ) - - magnification = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - - source_plane_mesh_grid = aa.Mesh2DDelaunay( - values=np.array( - [ - [0.0, 0.0], - [1.0, 0.5], - [0.0, 1.0], - [1.0, 2.0], - [2.0, 1.0], - [2.0, 2.0], - [2.0, 0.0], - [0.0, 2.0], - [1.0, 1.0], - [1.0, 1.0], - ] - ), - ) - - mapper = aa.m.MockMapper( - parameters=3, - source_plane_mesh_grid=source_plane_mesh_grid, - mask=mask, - mapping_matrix=np.ones((12, 10)), - ) - - mapper_valued = aa.MapperValued(values=magnification, mapper=mapper) - - magnification = mapper_valued.magnification_via_mesh_from() - - assert magnification == pytest.approx(11.7073170731, 1.0e-4) - - -def test__magnification_via_mesh_from__with_pixel_mask(): - mask = aa.Mask2D( - mask=np.array( - [ - [False, False, False], - [False, False, False], - [False, False, False], - [False, False, False], - ] - ), - pixel_scales=(0.5, 0.5), - ) - - magnification = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) - - source_plane_mesh_grid = aa.Mesh2DDelaunay( - values=np.array( - [ - [0.0, 0.0], - [1.0, 0.5], - [0.0, 1.0], - [1.0, 2.0], - [2.0, 1.0], - [2.0, 2.0], - [2.0, 0.0], - [0.0, 2.0], - [1.0, 1.0], - [1.0, 1.0], - ] - ), - ) - - mapper = aa.m.MockMapper( - parameters=3, - source_plane_mesh_grid=source_plane_mesh_grid, - mask=mask, - mapping_matrix=np.ones((12, 10)), - ) - - mesh_pixel_mask = np.array( - [True, True, True, True, True, True, True, True, False, False] - ) - - mapper_valued = aa.MapperValued( - values=magnification, mapper=mapper, mesh_pixel_mask=mesh_pixel_mask - ) - - magnification = mapper_valued.magnification_via_mesh_from() - - assert magnification == pytest.approx(4.0, 1.0e-4) - - -def test__magnification_via_interpolation_from(): - mask = aa.Mask2D( - mask=np.array([[False, False], [False, False]]), - pixel_scales=(0.5, 0.5), - ) - - magnification = aa.Array2D( - values=[0.0, 1.0, 1.0, 1.0], - mask=mask, - ) - - mapper = aa.m.MockMapper( - parameters=4, - mask=mask, - interpolated_array=magnification, - mapping_matrix=np.ones((4, 4)), - ) - - mapper_valued = aa.MapperValued(values=np.array(magnification), mapper=mapper) - - magnification = mapper_valued.magnification_via_interpolation_from() - - assert magnification == pytest.approx(4.0, 1.0e-4) - - magnification = mapper_valued.magnification_via_interpolation_from( - shape_native=(3, 3), extent=(-1.0, 1.0, -1.0, 1.0) - ) - - assert magnification == pytest.approx(4.0, 1.0e-4) diff --git a/test_autoarray/inversion/pixelization/mappers/test_abstract.py b/test_autoarray/inversion/pixelization/mappers/test_abstract.py index efd7400b3..7e01cd70c 100644 --- a/test_autoarray/inversion/pixelization/mappers/test_abstract.py +++ b/test_autoarray/inversion/pixelization/mappers/test_abstract.py @@ -133,38 +133,6 @@ def test__adaptive_pixel_signals_from___matches_util(grid_2d_7x7, image_7x7): assert (pixel_signals == pixel_signals_util).all() -def test__interpolated_array_from(grid_2d_7x7): - mesh_grid_ndarray = aa.Grid2D.no_mask( - values=[[0.1, 0.1], [1.1, 0.6], [2.1, 0.1], [0.4, 1.1], [1.1, 7.1], [2.1, 1.1]], - shape_native=(3, 2), - pixel_scales=1.0, - ) - - mesh_grid = aa.Mesh2DDelaunay(values=mesh_grid_ndarray) - - mapper_grids = aa.MapperGrids( - mask=grid_2d_7x7.mask, - source_plane_data_grid=grid_2d_7x7, - source_plane_mesh_grid=mesh_grid, - ) - - mapper = aa.Mapper(mapper_grids=mapper_grids, regularization=None) - - interpolated_array_via_mapper = mapper.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), - shape_native=(3, 3), - extent=(-0.2, 0.2, -0.2, 0.2), - ) - - interpolated_array_via_grid = mesh_grid.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), - shape_native=(3, 3), - extent=(-0.2, 0.2, -0.2, 0.2), - ) - - assert (interpolated_array_via_mapper == interpolated_array_via_grid).all() - - def test__mapped_to_source_from(grid_2d_7x7): mesh_grid = aa.Grid2D.no_mask( values=[[0.1, 0.1], [1.1, 0.6], [2.1, 0.1], [0.4, 1.1], [1.1, 7.1], [2.1, 1.1]], diff --git a/test_autoarray/inversion/pixelization/mesh/test_mesh_util.py b/test_autoarray/inversion/pixelization/mesh/test_mesh_util.py index 33cf76df9..2a1c8ad78 100644 --- a/test_autoarray/inversion/pixelization/mesh/test_mesh_util.py +++ b/test_autoarray/inversion/pixelization/mesh/test_mesh_util.py @@ -104,30 +104,3 @@ def test__rectangular_neighbors_from(): assert ( neighbors_sizes == np.array([2, 3, 3, 2, 3, 4, 4, 3, 3, 4, 4, 3, 2, 3, 3, 2]) ).all() - - -def test__delaunay_interpolated_grid_from(): - shape_native = (3, 3) - - grid_interpolate_slim = aa.Grid2D.uniform( - shape_native=shape_native, pixel_scales=1.0 - ).slim - - delaunay_grid = np.array( - [[1.0, -1.0], [1.0, 1.0], [0.0, 0.0], [-1.0, -1.0], [-1.0, 1.0]] - ) - - delaunay = scipy.spatial.Delaunay(delaunay_grid) - - values = np.array([1.0, 2.0, 3.0, 4.0, 5.0]) - - interpolated_grid = aa.util.mesh_numba.delaunay_interpolated_array_from( - shape_native=shape_native, - interpolation_grid_slim=grid_interpolate_slim, - pixel_values=values, - delaunay=delaunay, - ) - - assert interpolated_grid == pytest.approx( - np.array([[1.0, 1.5, 2.0], [2.5, 3.0, 3.5], [4.0, 4.5, 5.0]]), 1.0e-4 - ) diff --git a/test_autoarray/inversion/plot/test_mapper_plotters.py b/test_autoarray/inversion/plot/test_mapper_plotters.py index 2de4add0b..2f0f7cb04 100644 --- a/test_autoarray/inversion/plot/test_mapper_plotters.py +++ b/test_autoarray/inversion/plot/test_mapper_plotters.py @@ -38,18 +38,6 @@ def test__figure_2d( assert path.join(plot_path, "mapper1.png") in plot_patch.paths - plot_patch.paths = [] - - mapper_plotter = aplt.MapperPlotter( - mapper=delaunay_mapper_9_3x3, - visuals_2d=visuals_2d, - mat_plot_2d=mat_plot_2d, - ) - - mapper_plotter.figure_2d(interpolate_to_uniform=True) - - assert path.join(plot_path, "mapper1.png") in plot_patch.paths - def test__subplot_image_and_mapper( imaging_7x7, @@ -67,19 +55,6 @@ def test__subplot_image_and_mapper( ) mapper_plotter.subplot_image_and_mapper( - image=imaging_7x7.data, interpolate_to_uniform=True - ) - assert path.join(plot_path, "subplot_image_and_mapper.png") in plot_patch.paths - - plot_patch.paths = [] - - mapper_plotter = aplt.MapperPlotter( - mapper=delaunay_mapper_9_3x3, - visuals_2d=visuals_2d, - mat_plot_2d=aplt.MatPlot2D(output=aplt.Output(path=plot_path, format="png")), - ) - - mapper_plotter.subplot_image_and_mapper( - image=imaging_7x7.data, interpolate_to_uniform=True + image=imaging_7x7.data, ) assert path.join(plot_path, "subplot_image_and_mapper.png") in plot_patch.paths diff --git a/test_autoarray/structures/mesh/test_delaunay.py b/test_autoarray/structures/mesh/test_delaunay.py index bc12b00e7..072fa5f91 100644 --- a/test_autoarray/structures/mesh/test_delaunay.py +++ b/test_autoarray/structures/mesh/test_delaunay.py @@ -4,42 +4,6 @@ import autoarray as aa -def test__interpolated_array_from(): - grid = aa.Grid2D.no_mask( - values=[[0.0, 0.0], [1.1, 0.6], [2.1, 0.1], [0.4, 1.1], [1.1, 7.1], [2.1, 1.1]], - shape_native=(3, 2), - pixel_scales=1.0, - ) - - mesh = aa.Mesh2DDelaunay(values=grid) - - interpolated_array = mesh.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), shape_native=(3, 2) - ) - - assert interpolated_array.native == pytest.approx( - np.array([[3.0, 5.0], [2.0, 5.0], [1.0, 5.0]]), 1.0e-4 - ) - - interpolated_array = mesh.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), shape_native=(2, 3) - ) - - assert interpolated_array.native == pytest.approx( - np.array([[3.0, 6.0, 5.0], [1.0, 4.0, 5.0]]), 1.0e-4 - ) - - interpolated_array = mesh.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), - shape_native=(3, 2), - extent=(-0.4, 0.4, -0.4, 0.4), - ) - - assert interpolated_array.native == pytest.approx( - np.array([[1.0, 1.907216], [1.0, 1.0], [1.0, 1.0]]), 1.0e-4 - ) - - def test__neighbors(grid_2d_sub_1_7x7): mesh_grid = aa.Grid2D.no_mask( diff --git a/test_autoarray/structures/mesh/test_rectangular.py b/test_autoarray/structures/mesh/test_rectangular.py index a693fd292..af5f6ae26 100644 --- a/test_autoarray/structures/mesh/test_rectangular.py +++ b/test_autoarray/structures/mesh/test_rectangular.py @@ -148,41 +148,3 @@ def test__pixel_centres__3x3_grid__pixel_centres(): ] ) ) - - -def test__interpolated_array_from(): - grid = aa.Grid2D.no_mask( - values=[[1.0, -1.0], [1.0, 1.0], [-1.0, -1.0], [-1.0, 1.0]], - shape_native=(2, 2), - pixel_scales=1.0, - ) - - grid_rectangular = aa.Mesh2DRectangularUniform( - values=grid, shape_native=grid.shape_native, pixel_scales=grid.pixel_scales - ) - - interpolated_array = grid_rectangular.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0]), shape_native=(3, 2) - ) - - assert interpolated_array.native == pytest.approx( - np.array([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0]]), 1.0e-4 - ) - - interpolated_array = grid_rectangular.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0]), shape_native=(2, 3) - ) - - assert interpolated_array.native == pytest.approx( - np.array([[1.0, 1.5, 2.0], [3.0, 3.5, 4.0]]), 1.0e-4 - ) - - interpolated_array = grid_rectangular.interpolated_array_from( - values=np.array([1.0, 2.0, 3.0, 4.0]), - shape_native=(3, 2), - extent=(-0.4, 0.4, -0.4, 0.4), - ) - - assert interpolated_array.native == pytest.approx( - np.array([[1.9, 2.3], [2.3, 2.7], [2.7, 3.1]]), 1.0e-4 - )