def convert_array_2d(array_2d, mask_2d): """ Manual array functions take as input a list or ndarray which is to be returned as an Array2D. This function performs the following and checks and conversions on the input: 1) If the input is a list, convert it to an ndarray. 2) Check that the number of sub-pixels in the array is identical to that of the mask. 3) Map the input ndarray to its `slim` representation. For an Array2D, `slim` refers to a 1D NumPy array of shape [total_values] and `native` a 2D NumPy array of shape [total_y_values, total_values]. Parameters ---------- array_2d : np.ndarray or list The input structure which is converted to an ndarray if it is a list. mask_2d : Mask2D The mask of the output Array2D. """ array_2d = abstract_array.convert_array(array=array_2d) if len(array_2d.shape) == 1: array_2d_slim = abstract_array.convert_array(array=array_2d) if array_2d_slim.shape[0] != mask_2d.sub_pixels_in_mask: raise exc.ArrayException( "The input 1D array does not have the same number of entries as sub-pixels in" "the mask." ) return array_2d_slim if array_2d.shape != mask_2d.sub_shape_native: raise exc.ArrayException( "The input array is 2D but not the same dimensions as the sub-mask " "(e.g. the mask 2D shape multipled by its sub size." ) sub_array_1d = array_2d_util.array_2d_slim_from( array_2d_native=array_2d, mask_2d=mask_2d, sub_size=mask_2d.sub_size ) return sub_array_1d
def manual_slim( cls, array, shape_native, pixel_scales, sub_size=1, origin=(0.0, 0.0), exposure_info=None, ): """ Create an Array2D (see `AbstractArray2D.__new__`) by inputting the array values in 1D, for example: array=np.array([1.0, 2.0, 3.0, 4.0]) array=[1.0, 2.0, 3.0, 4.0] From 1D input the method cannot determine the 2D shape of the array and its mask, thus the shape_native must be input into this method. The mask is setup as a unmasked `Mask2D` of shape_native. Parameters ---------- array : np.ndarray or list The values of the array input as an ndarray of shape [total_unmasked_pixels*(sub_size**2)] or a list of lists. shape_native : (int, int) The 2D shape of the mask the array is paired with. pixel_scales: (float, float) or float The (y,x) scaled units to pixel units conversion factors of every pixel. If this is input as a ``float``, it is converted to a (float, float) structure. sub_size : int The size (sub_size x sub_size) of each unmasked pixels sub-array. origin : (float, float) The (y,x) scaled units origin of the mask's coordinate system. """ pixel_scales = geometry_util.convert_pixel_scales_2d(pixel_scales=pixel_scales) if shape_native is not None and len(shape_native) != 2: raise exc.ArrayException( "The input shape_native parameter is not a tuple of type (float, float)" ) mask = msk.Mask2D.unmasked( shape_native=shape_native, pixel_scales=pixel_scales, sub_size=sub_size, origin=origin, ) return cls(array=array, mask=mask, exposure_info=exposure_info)
def manual_1d(cls, array, mask, store_in_1d=True): if type(array) is list: array = np.asarray(array) if array.shape[0] != mask.sub_pixels_in_mask: raise exc.ArrayException( "The input 1D array does not have the same number of entries as sub-pixels in" "the mask.") if store_in_1d: return mask.mapping.array_stored_1d_from_sub_array_1d( sub_array_1d=array) else: return mask.mapping.array_stored_2d_from_sub_array_1d( sub_array_1d=array)
def manual_2d(cls, array, mask, store_in_1d=True): if type(array) is list: array = np.asarray(array) if array.shape != mask.sub_shape_2d: raise exc.ArrayException( "The input array is 2D but not the same dimensions as the sub-mask " "(e.g. the mask 2D shape multipled by its sub size.") if store_in_1d: return mask.mapping.array_stored_1d_from_sub_array_2d( sub_array_2d=array) else: masked_sub_array_1d = mask.mapping.array_stored_1d_from_sub_array_2d( sub_array_2d=array) return mask.mapping.array_stored_2d_from_sub_array_1d( sub_array_1d=masked_sub_array_1d)
def calibrated_gain(self): if round(self.gain) == 1: calibrated_gain = [0.99989998, 0.97210002, 1.01070000, 1.01800000] elif round(self.gain) == 2: calibrated_gain = [0.99989998, 0.97210002, 1.01070000, 1.01800000] elif round(self.gain) == 4: calibrated_gain = [4.011, 3.902, 4.074, 3.996] else: raise exc.ArrayException( "Calibrated gain of ACS file does not round to 1, 2 or 4.") if self.quadrant_letter == "A": return calibrated_gain[0] elif self.quadrant_letter == "B": return calibrated_gain[1] elif self.quadrant_letter == "C": return calibrated_gain[2] elif self.quadrant_letter == "D": return calibrated_gain[3]
def check_array_2d(array_2d): if len(array_2d.shape) != 1: raise exc.ArrayException( "An array input into the array_2d.Array2D.__new__ method is not of shape 1." )
def from_fits( cls, file_path, quadrant_letter, bias_subtract_via_prescan=False, bias_path=None, use_calibrated_gain=True, ): """ Use the input .fits file and quadrant letter to extract the quadrant from the full CCD, perform the rotations required to give correct arctic clocking and convert the image from units of COUNTS / CPS to ELECTRONS. See the docstring of the `FrameACS` class for a complete description of the Euclid FPA, quadrants and rotations. """ hdu = fits_hdu_from_quadrant_letter(quadrant_letter=quadrant_letter) header_sci_obj = array_2d_util.header_obj_from_fits( file_path=file_path, hdu=0) header_hdu_obj = array_2d_util.header_obj_from_fits( file_path=file_path, hdu=hdu) header = HeaderACS( header_sci_obj=header_sci_obj, header_hdu_obj=header_hdu_obj, hdu=hdu, quadrant_letter=quadrant_letter, ) if header.header_sci_obj["TELESCOP"] != "HST": raise exc.ArrayException( f"The file {file_path} does not point to a valid HST ACS dataset." ) if header.header_sci_obj["INSTRUME"] != "ACS": raise exc.ArrayException( f"The file {file_path} does not point to a valid HST ACS dataset." ) array = array_2d_util.numpy_array_2d_from_fits( file_path=file_path, hdu=hdu, do_not_scale_image_data=True) array = header.array_from_original_to_electrons(array=array) if use_calibrated_gain: array = array * header.calibrated_gain else: array = array * header.gain if bias_path is not None: bias = array_2d_util.numpy_array_2d_from_fits( file_path=bias_path, hdu=hdu, do_not_scale_image_data=True) header_sci_obj = array_2d_util.header_obj_from_fits( file_path=bias_path, hdu=0) header_hdu_obj = array_2d_util.header_obj_from_fits( file_path=bias_path, hdu=hdu) bias_header = HeaderACS( header_sci_obj=header_sci_obj, header_hdu_obj=header_hdu_obj, hdu=hdu, quadrant_letter=quadrant_letter, ) if bias_header.original_units != "COUNTS": raise exc.ArrayException( "Cannot use bias frame not in counts.") bias = bias * bias_header.calibrated_gain else: bias = None return cls.from_ccd( array_electrons=array, quadrant_letter=quadrant_letter, header=header, bias_subtract_via_prescan=bias_subtract_via_prescan, bias=bias, )
def plot_array( self, array, mask=None, lines=None, positions=None, grid=None, include_origin=False, include_border=False, bypass_output=False, ): """Plot an array of data_type as a figure. Parameters ----------- settings : PlotterSettings Settings include : PlotterInclude Include labels : PlotterLabels labels outputs : PlotterOutputs outputs array : data_type.array.aa.Scaled The 2D array of data_type which is plotted. origin : (float, float). The origin of the coordinate system of the array, which is plotted as an 'x' on the image if input. mask : data_type.array.mask.Mask The mask applied to the array, the edge of which is plotted as a set of points over the plotted array. extract_array_from_mask : bool The plotter array is extracted using the mask, such that masked values are plotted as zeros. This ensures \ bright features outside the mask do not impact the color map of the plotters. zoom_around_mask : bool If True, the 2D region of the array corresponding to the rectangle encompassing all unmasked values is \ plotted, thereby zooming into the region of interest. border : bool If a mask is supplied, its borders pixels (e.g. the exterior edge) is plotted if this is *True*. positions : [[]] Lists of (y,x) coordinates on the image which are plotted as colored dots, to highlight specific pixels. grid : data_type.array.aa.Grid A grid of (y,x) coordinates which may be plotted over the plotted array. as_subplot : bool Whether the array is plotted as part of a subplot, in which case the grid figure is not opened / closed. unit_label : str The label for the unit_label of the y / x axis of the plots. unit_conversion_factor : float or None The conversion factor between arc-seconds and kiloparsecs, required to plotters the unit_label in kpc. figsize : (int, int) The size of the figure in (rows, columns). aspect : str The aspect ratio of the array, specifically whether it is forced to be square ('equal') or adapts its size to \ the figure size ('auto'). cmap : str The colormap the array is plotted using, which may be chosen from the standard matplotlib colormaps. norm : str The normalization of the colormap used to plotters the image, specifically whether it is linear ('linear'), log \ ('log') or a symmetric log normalization ('symmetric_log'). norm_min : float or None The minimum array value the colormap map spans (all values below this value are plotted the same color). norm_max : float or None The maximum array value the colormap map spans (all values above this value are plotted the same color). linthresh : float For the 'symmetric_log' colormap normalization ,this specifies the range of values within which the colormap \ is linear. linscale : float For the 'symmetric_log' colormap normalization, this allowws the linear range set by linthresh to be stretched \ relative to the logarithmic range. cb_ticksize : int The size of the tick labels on the colorbar. cb_fraction : float The fraction of the figure that the colorbar takes up, which resizes the colorbar relative to the figure. cb_pad : float Pads the color bar in the figure, which resizes the colorbar relative to the figure. xsize : int The fontsize of the x axes label. ysize : int The fontsize of the y axes label. xyticksize : int The font size of the x and y ticks on the figure axes. mask_scatterer : int The size of the points plotted to show the mask. xticks_manual : [] or None If input, the xticks do not use the array's default xticks but instead overwrite them as these values. yticks_manual : [] or None If input, the yticks do not use the array's default yticks but instead overwrite them as these values. output_path : str The path on the hard-disk where the figure is output. output_filename : str The filename of the figure that is output. output_format : str The format the figue is output: 'show' - display on computer screen. 'png' - output to hard-disk as a png. 'fits' - output to hard-disk as a fits file.' Returns -------- None Examples -------- plotters.plot_array( array=image, origin=(0.0, 0.0), mask=circular_mask, border=False, points=[[1.0, 1.0], [2.0, 2.0]], grid=None, as_subplot=False, unit_label='scaled', kpc_per_arcsec=None, figsize=(7,7), aspect='auto', cmap='jet', norm='linear, norm_min=None, norm_max=None, linthresh=None, linscale=None, cb_ticksize=10, cb_fraction=0.047, cb_pad=0.01, cb_tick_values=None, cb_tick_labels=None, title='Image', titlesize=16, xsize=16, ysize=16, xyticksize=16, mask_scatterer=10, border_pointsize=2, position_pointsize=10, grid_pointsize=10, xticks_manual=None, yticks_manual=None, output_path='/path/to/output', output_format='png', output_filename='image') """ if array is None or np.all(array == 0): return if array.pixel_scales is None and self.units.use_scaled: raise exc.ArrayException( "You cannot plot an array using its scaled unit_label if the input array does not have " "a pixel scales attribute.") array = array.in_1d_binned if array.mask.is_all_false: buffer = 0 else: buffer = 1 extent = array.extent_of_zoomed_array(buffer=buffer) array = array.zoomed_around_mask(buffer=buffer) self.figure.open() aspect = self.figure.aspect_from_shape_2d(shape_2d=array.shape_2d) norm_scale = self.cmap.norm_from_array(array=array) plt.imshow( X=array.in_2d, aspect=aspect, cmap=self.cmap.cmap, norm=norm_scale, extent=extent, ) plt.axis(extent) self.ticks.set_yticks(array=array, extent=extent, units=self.units) self.ticks.set_xticks(array=array, extent=extent, units=self.units) self.labels.set_title() self.labels.set_yunits(units=self.units, include_brackets=True) self.labels.set_xunits(units=self.units, include_brackets=True) self.cb.set() if include_origin: self.origin_scatterer.scatter_grids(grids=[array.origin]) if mask is not None: self.mask_scatterer.scatter_grids( grids=mask.geometry.edge_grid.in_1d_binned) if include_border and mask is not None: self.border_scatterer.scatter_grids( grids=mask.geometry.border_grid.in_1d_binned) if grid is not None: self.grid_scatterer.scatter_grids(grids=grid) if positions is not None: self.positions_scatterer.scatter_grids(grids=positions) if lines is not None: self.liner.draw_grids(grids=lines) if not bypass_output: self.output.to_figure(structure=array) if not isinstance(self, SubPlotter) and not bypass_output: self.figure.close()
def plot_array( self, array: array_2d.Array2D, visuals_2d: vis.Visuals2D, auto_labels: AutoLabels, bypass: bool = False, ): """ Plot an `Array2D` data structure as a figure using the matplotlib wrapper objects and tools. This `Array2D` is plotted using `plt.imshow`. Parameters ----------- array : array_2d.Array2D The 2D array of data_type which is plotted. visuals_2d : vis.Visuals2D Contains all the visuals that are plotted over the `Array2D` (e.g. the origin, mask, grids, etc.). bypass : bool If `True`, `plt.close` is omitted and the matplotlib figure remains open. This is used when making subplots. """ if array is None or np.all(array == 0): return if array.pixel_scales is None and self.units.use_scaled: raise exc.ArrayException( "You cannot plot an array using its scaled unit_label if the input array does not have " "a pixel scales attribute.") array = array.binned if array.mask.is_all_false: buffer = 0 else: buffer = 1 if array.zoom_for_plot: extent_imshow = array.extent_of_zoomed_array(buffer=buffer) array = array.zoomed_around_mask(buffer=buffer) else: extent_imshow = array.extent if not self.is_for_subplot: self.figure.open() else: if not bypass: self.setup_subplot() aspect = self.figure.aspect_from_shape_native( shape_native=array.shape_native) norm_scale = self.cmap.norm_from_array(array=array) plt.imshow( X=array.native, aspect=aspect, cmap=self.cmap.config_dict["cmap"], norm=norm_scale, extent=extent_imshow, ) if visuals_2d.array_overlay is not None: self.array_overlay.overlay_array(array=visuals_2d.array_overlay, figure=self.figure) extent_axis = self.axis.config_dict.get("extent") extent_axis = extent_axis if extent_axis is not None else extent_imshow self.axis.set(extent=extent_axis) self.tickparams.set() self.yticks.set( array=array, min_value=extent_axis[2], max_value=extent_axis[3], units=self.units, ) self.xticks.set( array=array, min_value=extent_axis[0], max_value=extent_axis[1], units=self.units, ) self.title.set(auto_title=auto_labels.title) self.ylabel.set(units=self.units, include_brackets=True) self.xlabel.set(units=self.units, include_brackets=True) if self.colorbar is not None: cb = self.colorbar.set() self.colorbar_tickparams.set(cb=cb) visuals_2d.plot_via_plotter(plotter=self, grid_indexes=array.mask.masked_grid) if not self.is_for_subplot and not bypass: self.output.to_figure(structure=array, auto_filename=auto_labels.filename) self.figure.close()