From 5c4470305775f2eca4b1b8892dc27971b5d1c1fd Mon Sep 17 00:00:00 2001 From: Darren Chaddock Date: Sun, 23 Jun 2024 14:36:08 -0600 Subject: [PATCH] updated docs --- docs/code/pyaurorax_api_reference/index.js | 30 +- .../pyaurorax/index.html | 2 +- .../bounding_box/extract_metric/index.html | 234 +++++++++--- .../pyaurorax/tools/calibration/index.html | 56 +-- .../pyaurorax/tools/classes/montage.html | 36 +- .../pyaurorax/tools/classes/mosaic.html | 156 ++++++-- .../pyaurorax/tools/index.html | 242 +++++++----- .../pyaurorax/tools/keogram/index.html | 35 +- .../pyaurorax/tools/montage/index.html | 14 +- .../pyaurorax/tools/mosaic/index.html | 351 ++++++++++-------- pyaurorax | 2 +- 11 files changed, 773 insertions(+), 385 deletions(-) diff --git a/docs/code/pyaurorax_api_reference/index.js b/docs/code/pyaurorax_api_reference/index.js index 62cac7f..d4a8fa2 100644 --- a/docs/code/pyaurorax_api_reference/index.js +++ b/docs/code/pyaurorax_api_reference/index.js @@ -1616,7 +1616,7 @@ INDEX=[ { "ref":"pyaurorax.tools.scale_intensity", "url":33, -"doc":"Scale all values of an array that lie in the range min<=x<=max in to the range 0<=x<=high. Args: data (numpy.ndarray): data array, can be 2, 3, or 4-dimensional. Assumed to be an image, or array of images. Also assumed that the first 2 dimensions are the image's x and y coordinates, and the following dimensions are some combination of the number of images, and/or the colour channel. min (float): minimum value of array to be considered max (float): maximum value of array to be considered top (float): maximum value of the scaled result. If not supplied, the max value of the data array's dtype is used. Returns: A new numpy.ndarray that is the same dimensions as the inputted data array, with the scaling applied. Raises: ValueError: Issues with the supplied min, max, or top", +"doc":"Scale all values of an array that lie in the range min<=x<=max in to the range 0<=x<=high. Args: data (numpy.ndarray): Data array, can be 2, 3, or 4-dimensional. Assumed to be an image, or array of images. Also assumed that the first 2 dimensions are the image's x and y coordinates, and the following dimensions are some combination of the number of images, and/or the colour channel. min (float): Minimum value of array to be considered max (float): Maximum value of array to be considered top (float): Maximum value of the scaled result. If not supplied, the max value of the data array's dtype is used. memory_saver (bool): Utilize less RAM when scaling a set of images. Defaults to True . If set to False then the scaling routine will be faster, but will utilize significantly more RAM. Returns: A new numpy.ndarray that is the same dimensions as the inputted data array, with the scaling applied. Raises: ValueError: Issues with the supplied min, max, or top", "func":1 }, { @@ -1682,19 +1682,19 @@ INDEX=[ { "ref":"pyaurorax.tools.Mosaic.plot", "url":33, -"doc":"Generate a plot of the mosaic data. Either display it (default behaviour), save it to disk (using the savefig parameter), or return the matplotlib plot object for further usage (using the returnfig parameter). Args: map_extent (List[int]): Latitude/longitude range to be visible on the rendered map. This is a list of 4 integers and/or floats, in the order of [min_lon, max_lon, min_lat, max_lat]. figsize (tuple): The matplotlib figure size to use when plotting. For example figsize=(14,4) . rayleighs (bool): Set to True if the data being plotted is in Rayleighs. Defaults to False . max_rayleighs (int): Max intensity scale for Rayleighs. Defaults to 20000 . ocean_color (str): Colour of the ocean. Default is cartopy's default shade of blue. Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 55AADD ). land_color (str): Colour of the land. Default is grey . Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 41BB87 ). land_edgecolor (str): Color of the land edges. Default is 8A8A8A . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_color (str): Color of the country borders. Default is AEAEAE . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_disable (bool): Disbale rendering of the borders. Default is False . cbar_colorcmap (str): The matplotlib colormap to use for the plotted color bar. Default is grey . Commonly used colormaps are: - REGO: gist_heat - THEMIS ASI: gray - TREx Blue: Blues_r - TREx NIR: gray - TREx RGB: None A list of all available colormaps can be found on the [matplotlib documentation](https: matplotlib.org/stable/gallery/color/colormap_reference.html). returnfig (bool): Instead of displaying the image, return the matplotlib figure object. This allows for further plot manipulation, for example, adding labels or a title in a different location than the default. Remember - if this parameter is supplied, be sure that you close your plot after finishing work with it. This can be achieved by doing plt.close(fig) . Note that this method cannot be used in combination with savefig . savefig (bool): Save the displayed image to disk instead of displaying it. The parameter savefig_filename is required if this parameter is set to True. Defaults to False . savefig_filename (str): Filename to save the image to. Must be specified if the savefig parameter is set to True. savefig_quality (int): Quality level of the saved image. This can be specified if the savefig_filename is a JPG image. If it is a PNG, quality is ignored. Default quality level for JPGs is matplotlib/Pillow's default of 75%. Returns: The displayed montage, by default. If savefig is set to True, nothing will be returned. If returnfig is set to True, the plotting variables (fig, ax) will be returned. Raises:", +"doc":"Generate a plot of the mosaic data. Either display it (default behaviour), save it to disk (using the savefig parameter), or return the matplotlib plot object for further usage (using the returnfig parameter). Args: map_extent (List[int]): Latitude/longitude range to be visible on the rendered map. This is a list of 4 integers and/or floats, in the order of [min_lon, max_lon, min_lat, max_lat]. figsize (tuple): The matplotlib figure size to use when plotting. For example figsize=(14,4) . rayleighs (bool): Set to True if the data being plotted is in Rayleighs. Defaults to False . max_rayleighs (int): Max intensity scale for Rayleighs. Defaults to 20000 . ocean_color (str): Colour of the ocean. Default is cartopy's default shade of blue. Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 55AADD ). land_color (str): Colour of the land. Default is gray . Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 41BB87 ). land_edgecolor (str): Color of the land edges. Default is 8A8A8A . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_color (str): Color of the country borders. Default is AEAEAE . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_disable (bool): Disbale rendering of the borders. Default is False . cbar_colorcmap (str): The matplotlib colormap to use for the plotted color bar. Default is gray . Commonly used colormaps are: - REGO: gist_heat - THEMIS ASI: gray - TREx Blue: Blues_r - TREx NIR: gray - TREx RGB: None A list of all available colormaps can be found on the [matplotlib documentation](https: matplotlib.org/stable/gallery/color/colormap_reference.html). returnfig (bool): Instead of displaying the image, return the matplotlib figure object. This allows for further plot manipulation, for example, adding labels or a title in a different location than the default. Remember - if this parameter is supplied, be sure that you close your plot after finishing work with it. This can be achieved by doing plt.close(fig) . Note that this method cannot be used in combination with savefig . savefig (bool): Save the displayed image to disk instead of displaying it. The parameter savefig_filename is required if this parameter is set to True. Defaults to False . savefig_filename (str): Filename to save the image to. Must be specified if the savefig parameter is set to True. savefig_quality (int): Quality level of the saved image. This can be specified if the savefig_filename is a JPG image. If it is a PNG, quality is ignored. Default quality level for JPGs is matplotlib/Pillow's default of 75%. Returns: The displayed montage, by default. If savefig is set to True, nothing will be returned. If returnfig is set to True, the plotting variables (fig, ax) will be returned. Raises:", "func":1 }, { "ref":"pyaurorax.tools.Mosaic.add_geo_contours", "url":33, -"doc":"Add geographic contours to a mosaic. Args: lats (ndarray or list): Sequence of geographic latitudes defining a contour. lons (ndarray or list): Sequence of geographic longitudes defining a contour. constant_lats (float, int, or Sequence): Geographic Latitude(s) at which to add line(s) of constant latitude. constant_lons (float, int, or Sequence): Geographic Longitude(s) at which to add line(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", +"doc":"Add geographic contours to a mosaic. Args: lats (ndarray or list): Sequence of geographic latitudes defining a contour. lons (ndarray or list): Sequence of geographic longitudes defining a contour. constant_lats (float, int, or Sequence): Geographic Latitude(s) at which to add line(s) of constant latitude. constant_lons (float, int, or Sequence): Geographic Longitude(s) at which to add line(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). marker (str): The matplotlib marker used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", "func":1 }, { "ref":"pyaurorax.tools.Mosaic.add_mag_contours", "url":33, -"doc":"Add geomagnetic contours to a mosaic. Args: timestamp (datetime.datetime): The timestamp used in computing AACGM coordinates. lats (ndarray or list): Sequence of geomagnetic latitudes defining a contour. lons (ndarray or list): Sequence of geomagnetic longitudes defining a contour. constant_lats (float, int, Sequence): Geomagnetic latitude(s) at which to add contour(s) of constant latitude. constant_lons (float, int, Sequence): Geomagnetic longitude(s) at which to add contours(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", +"doc":"Add geomagnetic contours to a mosaic. Args: timestamp (datetime.datetime): The timestamp used in computing AACGM coordinates. lats (ndarray or list): Sequence of geomagnetic latitudes defining a contour. lons (ndarray or list): Sequence of geomagnetic longitudes defining a contour. constant_lats (float, int, Sequence): Geomagnetic latitude(s) at which to add contour(s) of constant latitude. constant_lons (float, int, Sequence): Geomagnetic longitude(s) at which to add contours(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). marker (str): The matplotlib marker used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", "func":1 }, { @@ -1771,31 +1771,31 @@ INDEX=[ { "ref":"pyaurorax.tools.bounding_box.extract_metric.geo", "url":36, -"doc":"Compute a metric of image data within a geographic lat/lon boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. altitude_km (int or float): The altitude of the image data in kilometers. lonlat_bounds (Sequence): A 4-element sequence specifying the lat/lon bounds from which to extract the metric. Anticipated order is [lon_0, lon_1, lat_0, lat_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", +"doc":"Compute a metric of image data within a geographic lat/lon boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. altitude_km (int or float): The altitude of the image data in kilometers. lonlat_bounds (Sequence): A 4-element sequence specifying the lat/lon bounds from which to extract the metric. Anticipated order is [lon_0, lon_1, lat_0, lat_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. show_preview (bool): Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", "func":1 }, { "ref":"pyaurorax.tools.bounding_box.extract_metric.ccd", "url":36, -"doc":"Compute a metric of image data within a CCD boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. ccd_bounds (List[int]): A 4-element sequence specifying the (inclusive) CCD bounds from which to extract the metric. Anticipated order is [y_0, y_1, x_0, x_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Defaults to median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. Returns: A numpy.ndarray containing the metrics computed within CCD bounds, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", +"doc":"Compute a metric of image data within a CCD boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. ccd_bounds (List[int]): A 4-element sequence specifying the (inclusive) CCD bounds from which to extract the metric. Anticipated order is [x_0, x_1, y_0, y_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Defaults to median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. show_preview (bool): Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within CCD bounds, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", "func":1 }, { "ref":"pyaurorax.tools.bounding_box.extract_metric.mag", "url":36, -"doc":"Compute a metric of image data within a magnetic lat/lon boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. altitude_km (int or float): The altitude of the image data in kilometers. lonlat_bounds (Sequence): A 4-element sequence specifying the magnetic lat/lon bounds from which to extract the metric. Anticipated order is [lon_0, lon_1, lat_0, lat_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", +"doc":"Compute a metric of image data within a magnetic lat/lon boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. altitude_km (int or float): The altitude of the image data in kilometers. lonlat_bounds (Sequence): A 4-element sequence specifying the magnetic lat/lon bounds from which to extract the metric. Anticipated order is [lon_0, lon_1, lat_0, lat_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. show_preview (bool): Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", "func":1 }, { "ref":"pyaurorax.tools.bounding_box.extract_metric.elevation", "url":36, -"doc":"Compute a metric of image data within an elevation boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. elevation_bounds (Sequence): A 2-element sequence specifying the elevation bounds from which to extract the metric. Anticipated order is [el_min, el_max]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", +"doc":"Compute a metric of image data within an elevation boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. elevation_bounds (Sequence): A 2-element sequence specifying the elevation bounds from which to extract the metric. Anticipated order is [el_min, el_max]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. show_preview (bool): Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", "func":1 }, { "ref":"pyaurorax.tools.bounding_box.extract_metric.azimuth", "url":36, -"doc":"Compute a metric of image data within an azimuthal boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. azimuth_bounds (Sequence[int | float]: A 2-element sequence specifying the azimuthal bounds from which to extract the metric. Anticipated order is [az_min, az_max]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. Returns: A numpy.ndarray containing the metrics computed within azimuth range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", +"doc":"Compute a metric of image data within an azimuthal boundary. Args: images (numpy.ndarray): A set of images. Normally this would come directly from a data read call, but can also be any arbitrary set of images. It is anticipated that the order of axes is [rows, cols, num_images] or [row, cols, channels, num_images]. skymap (pyaurorax.data.ucalgary.Skymap): The skymap corresponding to the image data. azimuth_bounds (Sequence[int | float]: A 2-element sequence specifying the azimuthal bounds from which to extract the metric. Anticipated order is [az_min, az_max]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are mean , median , sum . Default is median . n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. show_preview (bool): Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within azimuth range, for all image frames. Raises: ValueError: issue encountered with value supplied in parameter", "func":1 }, { @@ -1818,7 +1818,7 @@ INDEX=[ { "ref":"pyaurorax.tools.mosaic.create", "url":37, -"doc":"Create a mosaic object. Args: prepped_data (pyaurorax.tools.MosaicData): The prepared mosaic data. Generated from a prior prep_images() function call. prepped_skymap (pyaurorax.tools.MosaicSkymap): The prepared skymap data. Generated from a prior prep_skymaps() function call. frame_idx (int): The frame number to generate a mosaic for. cartopy_projection (cartopy.crs.Projection): The cartopy projection to use when creating the mosaic. min_elevation (int): The minimum elevation cutoff when projecting images on the map, in degrees. Default is 5 . cbar_colorcmap (str): The matplotlib colormap to use for the rendered image data. Default is grey . Commonly used colormaps are: - REGO: gist_heat - THEMIS ASI: gray - TREx Blue: Blues_r - TREx NIR: gray - TREx RGB: None A list of all available colormaps can be found on the [matplotlib documentation](https: matplotlib.org/stable/gallery/color/colormap_reference.html). image_intensity_scaled (List or Dict): Ranges for scaling images. Either a a list with 2 elements which will scale all sites with the same range, or as a dictionary which can be used for scaling each site differently. Example of uniform scaling across all sites: image_intensity_scales = [2000, 8000] Example of scaling each site differently: image_intensity_scales = {\"fsmi\": [1000, 10000], \"gill\": [2000, 8000]} Returns: The generated pyaurorax.tools.Mosaic object. Raises: ValueError: issues with supplied parameters.", +"doc":"Create a mosaic object. Args: prepped_data (pyaurorax.tools.MosaicData): The prepared mosaic data. Generated from a prior prep_images() function call. prepped_skymap (pyaurorax.tools.MosaicSkymap): The prepared skymap data. Generated from a prior prep_skymaps() function call. frame_idx (int): The frame number to generate a mosaic for. cartopy_projection (cartopy.crs.Projection): The cartopy projection to use when creating the mosaic. min_elevation (int): The minimum elevation cutoff when projecting images on the map, in degrees. Default is 5 . cbar_colorcmap (str): The matplotlib colormap to use for the rendered image data. Default is gray . Commonly used colormaps are: - REGO: gist_heat - THEMIS ASI: gray - TREx Blue: Blues_r - TREx NIR: gray - TREx RGB: None A list of all available colormaps can be found on the [matplotlib documentation](https: matplotlib.org/stable/gallery/color/colormap_reference.html). image_intensity_scaled (List or Dict): Ranges for scaling images. Either a a list with 2 elements which will scale all sites with the same range, or as a dictionary which can be used for scaling each site differently. Example of uniform scaling across all sites: image_intensity_scales = [2000, 8000] Example of scaling each site differently: image_intensity_scales = {\"fsmi\": [1000, 10000], \"gill\": [2000, 8000]} Returns: The generated pyaurorax.tools.Mosaic object. Raises: ValueError: issues with supplied parameters.", "func":1 }, { @@ -1846,13 +1846,13 @@ INDEX=[ { "ref":"pyaurorax.tools.calibration.rego", "url":39, -"doc":"Apply various calibration adjustments to a single or set of images raw images. Args: images (numpy.ndarray): Raw images to perform calibration procedures on. cal_flatfield (pyaurorax.data.ucalgary.Calibration): Calibration object containing the flatfield data to utilize. This field is required if the step_flatfield_corection is set to True. cal_rayleighs (pyaurorax.data.ucalgary.Calibration): Calibration object containing the Rayleighs data to utilize. This field is required if the step_rayleighs_conversion is set to True. step_dark_frame_correction (bool): Perform the dark frame correction step. Defaults to True . step_flatfield_correction (bool): Perform the flatfield correction step. Defaults to True . Note that the cal_flatfield parameter must be supplied if this is True. step_rayleighs_conversion (bool): Perform the Rayleighs conversion step. Defaults to True. Note that the cal_rayleighs parameter must be supplied if this is True. exposure_length_sec (float): Force the exposure length to be a certain value. Default is TREx NIR's nominal operating mode exposure length of 2.0 seconds . Adjusting this field should be done with caution. Returns: The calibrated images. The shape of the calibrated data will be same as the input images. The dtype of the calibrated data will depend on if the Rayleighs conversion was performed. If it was, a float32 array will be returned. If it wasn't, the dtype will be the same as input images' dtype. Raises: ValueError: issues encountered with supplied parameters.", +"doc":"Apply various calibration adjustments to a single or set of images raw images. Args: images (numpy.ndarray): Raw images to perform calibration procedures on. cal_flatfield (pyaurorax.data.ucalgary.Calibration): Calibration object containing the flatfield data to utilize. This field is required if the step_flatfield_corection is set to True. cal_rayleighs (pyaurorax.data.ucalgary.Calibration): Calibration object containing the Rayleighs data to utilize. This field is required if the step_rayleighs_calibration is set to True. step_dark_frame_correction (bool): Perform the dark frame correction step. Defaults to True . step_flatfield_calibration (bool): Perform the flatfield correction step. Defaults to True . Note that the cal_flatfield parameter must be supplied if this is True. step_rayleighs_calibration (bool): Perform the Rayleighs conversion step. Defaults to True. Note that the cal_rayleighs parameter must be supplied if this is True. exposure_length_sec (float): Force the exposure length to be a certain value. Default is TREx NIR's nominal operating mode exposure length of 2.0 seconds . Adjusting this field should be done with caution. Returns: The calibrated images. The shape of the calibrated data will be same as the input images. The dtype of the calibrated data will depend on if the Rayleighs conversion was performed. If it was, a float32 array will be returned. If it wasn't, the dtype will be the same as input images' dtype. Raises: ValueError: issues encountered with supplied parameters.", "func":1 }, { "ref":"pyaurorax.tools.calibration.trex_nir", "url":39, -"doc":"Apply various calibration adjustments to a single or set of images raw images. Args: images (numpy.ndarray): Raw images to perform calibration procedures on. cal_flatfield (pyaurorax.data.ucalgary.Calibration): Calibration object containing the flatfield data to utilize. This field is required if the step_flatfield_corection is set to True. cal_rayleighs (pyaurorax.data.ucalgary.Calibration): Calibration object containing the Rayleighs data to utilize. This field is required if the step_rayleighs_conversion is set to True. step_dark_frame_correction (bool): Perform the dark frame correction step. Defaults to True . step_flatfield_correction (bool): Perform the flatfield correction step. Defaults to True . Note that the cal_flatfield parameter must be supplied if this is True. step_rayleighs_conversion (bool): Perform the Rayleighs conversion step. Defaults to True. Note that the cal_rayleighs parameter must be supplied if this is True. exposure_length_sec (float): Force the exposure length to be a certain value. Default is TREx NIR's nominal operating mode exposure length of 5.0 seconds . Adjusting this field should be done with caution. Returns: The calibrated images. The shape of the calibrated data will be same as the input images. The dtype of the calibrated data will depend on if the Rayleighs conversion was performed. If it was, a float32 array will be returned. If it wasn't, the dtype will be the same as input images' dtype. Raises: ValueError: issues encountered with supplied parameters.", +"doc":"Apply various calibration adjustments to a single or set of images raw images. Args: images (numpy.ndarray): Raw images to perform calibration procedures on. cal_flatfield (pyaurorax.data.ucalgary.Calibration): Calibration object containing the flatfield data to utilize. This field is required if the step_flatfield_corection is set to True. cal_rayleighs (pyaurorax.data.ucalgary.Calibration): Calibration object containing the Rayleighs data to utilize. This field is required if the step_rayleighs_calibration is set to True. step_dark_frame_correction (bool): Perform the dark frame correction step. Defaults to True . step_flatfield_calibration (bool): Perform the flatfield correction step. Defaults to True . Note that the cal_flatfield parameter must be supplied if this is True. step_rayleighs_calibration (bool): Perform the Rayleighs conversion step. Defaults to True. Note that the cal_rayleighs parameter must be supplied if this is True. exposure_length_sec (float): Force the exposure length to be a certain value. Default is TREx NIR's nominal operating mode exposure length of 5.0 seconds . Adjusting this field should be done with caution. Returns: The calibrated images. The shape of the calibrated data will be same as the input images. The dtype of the calibrated data will depend on if the Rayleighs conversion was performed. If it was, a float32 array will be returned. If it wasn't, the dtype will be the same as input images' dtype. Raises: ValueError: issues encountered with supplied parameters.", "func":1 }, { @@ -1967,19 +1967,19 @@ INDEX=[ { "ref":"pyaurorax.tools.classes.mosaic.Mosaic.plot", "url":42, -"doc":"Generate a plot of the mosaic data. Either display it (default behaviour), save it to disk (using the savefig parameter), or return the matplotlib plot object for further usage (using the returnfig parameter). Args: map_extent (List[int]): Latitude/longitude range to be visible on the rendered map. This is a list of 4 integers and/or floats, in the order of [min_lon, max_lon, min_lat, max_lat]. figsize (tuple): The matplotlib figure size to use when plotting. For example figsize=(14,4) . rayleighs (bool): Set to True if the data being plotted is in Rayleighs. Defaults to False . max_rayleighs (int): Max intensity scale for Rayleighs. Defaults to 20000 . ocean_color (str): Colour of the ocean. Default is cartopy's default shade of blue. Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 55AADD ). land_color (str): Colour of the land. Default is grey . Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 41BB87 ). land_edgecolor (str): Color of the land edges. Default is 8A8A8A . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_color (str): Color of the country borders. Default is AEAEAE . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_disable (bool): Disbale rendering of the borders. Default is False . cbar_colorcmap (str): The matplotlib colormap to use for the plotted color bar. Default is grey . Commonly used colormaps are: - REGO: gist_heat - THEMIS ASI: gray - TREx Blue: Blues_r - TREx NIR: gray - TREx RGB: None A list of all available colormaps can be found on the [matplotlib documentation](https: matplotlib.org/stable/gallery/color/colormap_reference.html). returnfig (bool): Instead of displaying the image, return the matplotlib figure object. This allows for further plot manipulation, for example, adding labels or a title in a different location than the default. Remember - if this parameter is supplied, be sure that you close your plot after finishing work with it. This can be achieved by doing plt.close(fig) . Note that this method cannot be used in combination with savefig . savefig (bool): Save the displayed image to disk instead of displaying it. The parameter savefig_filename is required if this parameter is set to True. Defaults to False . savefig_filename (str): Filename to save the image to. Must be specified if the savefig parameter is set to True. savefig_quality (int): Quality level of the saved image. This can be specified if the savefig_filename is a JPG image. If it is a PNG, quality is ignored. Default quality level for JPGs is matplotlib/Pillow's default of 75%. Returns: The displayed montage, by default. If savefig is set to True, nothing will be returned. If returnfig is set to True, the plotting variables (fig, ax) will be returned. Raises:", +"doc":"Generate a plot of the mosaic data. Either display it (default behaviour), save it to disk (using the savefig parameter), or return the matplotlib plot object for further usage (using the returnfig parameter). Args: map_extent (List[int]): Latitude/longitude range to be visible on the rendered map. This is a list of 4 integers and/or floats, in the order of [min_lon, max_lon, min_lat, max_lat]. figsize (tuple): The matplotlib figure size to use when plotting. For example figsize=(14,4) . rayleighs (bool): Set to True if the data being plotted is in Rayleighs. Defaults to False . max_rayleighs (int): Max intensity scale for Rayleighs. Defaults to 20000 . ocean_color (str): Colour of the ocean. Default is cartopy's default shade of blue. Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 55AADD ). land_color (str): Colour of the land. Default is gray . Colours can be supplied as a word, or hexcode prefixed with a ' ' character (ie. 41BB87 ). land_edgecolor (str): Color of the land edges. Default is 8A8A8A . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_color (str): Color of the country borders. Default is AEAEAE . Colours can be supplied as a word, or hexcode prefixed with a ' ' character. borders_disable (bool): Disbale rendering of the borders. Default is False . cbar_colorcmap (str): The matplotlib colormap to use for the plotted color bar. Default is gray . Commonly used colormaps are: - REGO: gist_heat - THEMIS ASI: gray - TREx Blue: Blues_r - TREx NIR: gray - TREx RGB: None A list of all available colormaps can be found on the [matplotlib documentation](https: matplotlib.org/stable/gallery/color/colormap_reference.html). returnfig (bool): Instead of displaying the image, return the matplotlib figure object. This allows for further plot manipulation, for example, adding labels or a title in a different location than the default. Remember - if this parameter is supplied, be sure that you close your plot after finishing work with it. This can be achieved by doing plt.close(fig) . Note that this method cannot be used in combination with savefig . savefig (bool): Save the displayed image to disk instead of displaying it. The parameter savefig_filename is required if this parameter is set to True. Defaults to False . savefig_filename (str): Filename to save the image to. Must be specified if the savefig parameter is set to True. savefig_quality (int): Quality level of the saved image. This can be specified if the savefig_filename is a JPG image. If it is a PNG, quality is ignored. Default quality level for JPGs is matplotlib/Pillow's default of 75%. Returns: The displayed montage, by default. If savefig is set to True, nothing will be returned. If returnfig is set to True, the plotting variables (fig, ax) will be returned. Raises:", "func":1 }, { "ref":"pyaurorax.tools.classes.mosaic.Mosaic.add_geo_contours", "url":42, -"doc":"Add geographic contours to a mosaic. Args: lats (ndarray or list): Sequence of geographic latitudes defining a contour. lons (ndarray or list): Sequence of geographic longitudes defining a contour. constant_lats (float, int, or Sequence): Geographic Latitude(s) at which to add line(s) of constant latitude. constant_lons (float, int, or Sequence): Geographic Longitude(s) at which to add line(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", +"doc":"Add geographic contours to a mosaic. Args: lats (ndarray or list): Sequence of geographic latitudes defining a contour. lons (ndarray or list): Sequence of geographic longitudes defining a contour. constant_lats (float, int, or Sequence): Geographic Latitude(s) at which to add line(s) of constant latitude. constant_lons (float, int, or Sequence): Geographic Longitude(s) at which to add line(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). marker (str): The matplotlib marker used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", "func":1 }, { "ref":"pyaurorax.tools.classes.mosaic.Mosaic.add_mag_contours", "url":42, -"doc":"Add geomagnetic contours to a mosaic. Args: timestamp (datetime.datetime): The timestamp used in computing AACGM coordinates. lats (ndarray or list): Sequence of geomagnetic latitudes defining a contour. lons (ndarray or list): Sequence of geomagnetic longitudes defining a contour. constant_lats (float, int, Sequence): Geomagnetic latitude(s) at which to add contour(s) of constant latitude. constant_lons (float, int, Sequence): Geomagnetic longitude(s) at which to add contours(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", +"doc":"Add geomagnetic contours to a mosaic. Args: timestamp (datetime.datetime): The timestamp used in computing AACGM coordinates. lats (ndarray or list): Sequence of geomagnetic latitudes defining a contour. lons (ndarray or list): Sequence of geomagnetic longitudes defining a contour. constant_lats (float, int, Sequence): Geomagnetic latitude(s) at which to add contour(s) of constant latitude. constant_lons (float, int, Sequence): Geomagnetic longitude(s) at which to add contours(s) of constant longitude. color (str): The matplotlib color used for the contour(s). linewidth (float or int): The contour thickness. linestyle (str): The matplotlib linestyle used for the contour(s). marker (str): The matplotlib marker used for the contour(s). Returns: The object's contour_data parameter is populated appropriately. Raises: ValueError: issues encountered with supplied parameters.", "func":1 }, { diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/index.html index 805f08d..89a73af 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/index.html @@ -73,7 +73,7 @@

Package pyaurorax

""" # versioning info -__version__ = "1.0.0-rc1" +__version__ = "1.0.0" # documentation excludes __pdoc__ = {"cli": False, "pyaurorax": False} diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/bounding_box/extract_metric/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/bounding_box/extract_metric/index.html index b4f9485..4fb2949 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/bounding_box/extract_metric/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/bounding_box/extract_metric/index.html @@ -67,7 +67,7 @@

Module pyaurorax.tools.bounding_box.extract_metricFunctions

-def azimuth(images: numpy.ndarray, skymap: pyucalgarysrs.data.classes.Skymap, azimuth_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None) ‑> numpy.ndarray +def azimuth(images: numpy.ndarray, skymap: pyucalgarysrs.data.classes.Skymap, azimuth_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None, show_preview: bool = False) ‑> numpy.ndarray

Compute a metric of image data within an azimuthal boundary.

@@ -91,6 +91,8 @@

Args

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data.
+

show_preview (bool): +Plot a preview of the bounded area.

Returns

A numpy.ndarray containing the metrics computed within azimuth range, for all image frames.

Raises

@@ -106,7 +108,8 @@

Raises

skymap: Skymap, azimuth_bounds: Sequence[Union[int, float]], metric: Literal["mean", "median", "sum"] = "median", - n_channels: Optional[int] = None) -> np.ndarray: + n_channels: Optional[int] = None, + show_preview: bool = False) -> np.ndarray: """ Compute a metric of image data within an azimuthal boundary. @@ -131,6 +134,9 @@

Raises

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. + show_preview (bool): + Plot a preview of the bounded area. + Returns: A numpy.ndarray containing the metrics computed within azimuth range, for all image frames. @@ -138,7 +144,7 @@

Raises

ValueError: issue encountered with value supplied in parameter """ - # Select individual elevations from list + # Select individual azimuths from list az_0 = azimuth_bounds[0] az_1 = azimuth_bounds[1] @@ -157,9 +163,9 @@

Raises

# Ensure that coordinates are valid if az_0 > 360 or az_0 < 0: - raise ValueError("Invalid Elevation: " + str(az_0)) + raise ValueError("Invalid Azimuth: " + str(az_0)) elif az_1 > 360 or az_1 < 0: - raise ValueError("Invalid Elevation: " + str(az_1)) + raise ValueError("Invalid Azimuth: " + str(az_1)) # Ensure that azimuths are properly ordered if az_0 > az_1: @@ -167,9 +173,9 @@

Raises

# Ensure that this is a valid polygon if (az_0 == az_1): - raise ValueError("Elevation bounds defined with zero area.") + raise ValueError("Azimuth bounds defined with zero area.") - # Obtain elevation array from skymap + # Obtain azimuth array from skymap az = np.squeeze(skymap.full_azimuth) # Obtain indices into skymap within azimuth range @@ -177,13 +183,30 @@

Raises

# If boundaries contain no data, raise error if len(bound_idx[0]) == 0 or len(bound_idx[1]) == 0: - raise ValueError("No data within desired bounds.") + raise ValueError("No data within desired bounds. Try a larger area.") - # Slice out the bounded data + # Slice out the bounded data, and plot preview if requested if n_channels == 1: bound_data = images[bound_idx[0], bound_idx[1], :] + if show_preview: + preview_img = scale_intensity(images[:, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1]] = 255 + plt.figure() + plt.imshow(preview_img, cmap="grey", origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() elif n_channels == 3: bound_data = images[bound_idx[0], bound_idx[1], :, :] + if show_preview: + preview_img = scale_intensity(images[:, :, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1], 0] = 255 + preview_img[bound_idx[0], bound_idx[1], 1:] = 0 + plt.figure() + plt.imshow(preview_img, origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() else: raise ValueError("Unrecognized image format with shape: " + str(images.shape)) @@ -201,7 +224,7 @@

Raises

-def ccd(images: numpy.ndarray, ccd_bounds: Sequence[int], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None) ‑> numpy.ndarray +def ccd(images: numpy.ndarray, ccd_bounds: Sequence[int], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None, show_preview: bool = False) ‑> numpy.ndarray

Compute a metric of image data within a CCD boundary.

@@ -213,7 +236,7 @@

Args

or [row, cols, channels, num_images].
ccd_bounds : List[int]
A 4-element sequence specifying the (inclusive) CCD bounds from which to extract the metric. -Anticipated order is [y_0, y_1, x_0, x_1].
+Anticipated order is [x_0, x_1, y_0, y_1].
metric : str
The name of the metric that is to be computed for the bounded area. Valid metrics are mean, median, sum. Defaults to median.
@@ -221,6 +244,8 @@

Args

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data.
+

show_preview (bool): +Plot a preview of the bounded area.

Returns

A numpy.ndarray containing the metrics computed within CCD bounds, for all image frames.

Raises

@@ -235,7 +260,8 @@

Raises

def ccd(images: np.ndarray,
         ccd_bounds: Sequence[int],
         metric: Literal["mean", "median", "sum"] = "median",
-        n_channels: Optional[int] = None) -> np.ndarray:
+        n_channels: Optional[int] = None,
+        show_preview: bool = False) -> np.ndarray:
     """
     Compute a metric of image data within a CCD boundary.
 
@@ -247,7 +273,7 @@ 

Raises

ccd_bounds (List[int]): A 4-element sequence specifying the (inclusive) CCD bounds from which to extract the metric. - Anticipated order is [y_0, y_1, x_0, x_1]. + Anticipated order is [x_0, x_1, y_0, y_1]. metric (str): The name of the metric that is to be computed for the bounded area. Valid metrics are `mean`, @@ -256,6 +282,9 @@

Raises

n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. + + show_preview (bool): + Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within CCD bounds, for all image frames. @@ -309,8 +338,25 @@

Raises

# Slice out the bounded data if n_channels == 1: bound_data = images[y_0:y_1, x_0:x_1, :] + if show_preview: + preview_img = scale_intensity(images[:, :, 0], top=230) + preview_img[y_0:y_1, x_0:x_1] = 255 + plt.figure() + plt.imshow(preview_img, cmap="grey", origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() elif n_channels == 3: bound_data = images[y_0:y_1, x_0:x_1, :, :] + if show_preview: + preview_img = scale_intensity(images[:, :, :, 0], top=230) + preview_img[y_0:y_1, x_0:x_1, 0] = 255 + preview_img[y_0:y_1, x_0:x_1, 1:] = 0 + plt.figure() + plt.imshow(preview_img, origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() else: raise ValueError("Unrecognized image format with shape: " + str(images.shape)) @@ -328,7 +374,7 @@

Raises

-def elevation(images: numpy.ndarray, skymap: pyucalgarysrs.data.classes.Skymap, elevation_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None) ‑> numpy.ndarray +def elevation(images: numpy.ndarray, skymap: pyucalgarysrs.data.classes.Skymap, elevation_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None, show_preview: bool = False) ‑> numpy.ndarray

Compute a metric of image data within an elevation boundary.

@@ -350,6 +396,8 @@

Args

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data.
+

show_preview (bool): +Plot a preview of the bounded area.

Returns

A numpy.ndarray containing the metrics computed within elevation range, for all image frames.

Raises

@@ -365,7 +413,8 @@

Raises

skymap: Skymap, elevation_bounds: Sequence[Union[int, float]], metric: Literal["mean", "median", "sum"] = "median", - n_channels: Optional[int] = None) -> np.ndarray: + n_channels: Optional[int] = None, + show_preview: bool = False) -> np.ndarray: """ Compute a metric of image data within an elevation boundary. @@ -389,6 +438,10 @@

Raises

n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. + + show_preview (bool): + Plot a preview of the bounded area. + Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. @@ -432,17 +485,34 @@

Raises

elev = np.squeeze(skymap.full_elevation) # Obtain indices into skymap within elevation range - bound_idx = np.where(np.logical_and(elev > float(elev_0), elev < float(elev_1))) + bound_idx = np.where(np.logical_and(elev >= float(elev_0), elev <= float(elev_1))) # If boundaries contain no data, raise error if len(bound_idx[0]) == 0 or len(bound_idx[1]) == 0: - raise ValueError("No data within desired bounds.") + raise ValueError("No data within desired bounds. Try a larger area.") # Slice out the bounded data if n_channels == 1: bound_data = images[bound_idx[0], bound_idx[1], :] + if show_preview: + preview_img = scale_intensity(images[:, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1]] = 255 + plt.figure() + plt.imshow(preview_img, cmap="grey", origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() elif n_channels == 3: bound_data = images[bound_idx[0], bound_idx[1], :, :] + if show_preview: + preview_img = scale_intensity(images[:, :, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1], 0] = 255 + preview_img[bound_idx[0], bound_idx[1], 1:] = 0 + plt.figure() + plt.imshow(preview_img, origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() else: raise ValueError("Unrecognized image format with shape: " + str(images.shape)) @@ -460,7 +530,7 @@

Raises

-def geo(images: numpy.ndarray, skymap: pyucalgarysrs.data.classes.Skymap, altitude_km: Union[float, int], lonlat_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None) ‑> numpy.ndarray +def geo(images: numpy.ndarray, skymap: pyucalgarysrs.data.classes.Skymap, altitude_km: Union[float, int], lonlat_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None, show_preview: bool = False) ‑> numpy.ndarray

Compute a metric of image data within a geographic lat/lon boundary.

@@ -484,6 +554,8 @@

Args

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data.
+

show_preview (bool): +Plot a preview of the bounded area.

Returns

A numpy.ndarray containing the metrics computed within elevation range, for all image frames.

Raises

@@ -500,7 +572,8 @@

Raises

altitude_km: Union[int, float], lonlat_bounds: Sequence[Union[int, float]], metric: Literal["mean", "median", "sum"] = "median", - n_channels: Optional[int] = None) -> np.ndarray: + n_channels: Optional[int] = None, + show_preview: bool = False) -> np.ndarray: """ Compute a metric of image data within a geographic lat/lon boundary. @@ -527,6 +600,9 @@

Raises

n_channels (int): By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. + + show_preview (bool): + Plot a preview of the bounded area. Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. @@ -581,8 +657,9 @@

Raises

raise ValueError("Polygon defined with zero area.") # Obtain lat/lon arrays from skymap - if (altitude_km * 1000.0 in skymap.full_map_altitude): - altitude_idx = np.where(altitude_km * 1000.0 == skymap.full_map_altitude) + interp_alts = skymap.full_map_altitude / 1000.0 + if (altitude_km in interp_alts): + altitude_idx = np.where(altitude_km == interp_alts) lats = np.squeeze(skymap.full_map_latitude[altitude_idx, :, :]) lons = np.squeeze(skymap.full_map_longitude[altitude_idx, :, :]) @@ -590,28 +667,41 @@

Raises

else: # Make sure altitude is in range that can be interpolated - if (altitude_km * 1000.0 < skymap.full_map_altitude[0]) or (altitude_km * 1000.0 > skymap.full_map_altitude[2]): - raise ValueError("Altitude " + str(altitude_km) + " outside valid range of " + - str((skymap.full_map_altitude[0] / 1000.0, skymap.full_map_altitude[2] / 1000.0))) + if (altitude_km < interp_alts[0]) or (altitude_km > interp_alts[2]): + raise ValueError("Altitude " + str(altitude_km) + " outside valid range of " + str((interp_alts[0], interp_alts[2]))) # Initialze empty lat/lon arrays lats = np.full(np.squeeze(skymap.full_map_latitude[0, :, :]).shape, np.nan, dtype=skymap.full_map_latitude[0, :, :].dtype) - lons = lats.copy() + lons = np.full(np.squeeze(skymap.full_map_latitude[0, :, :]).shape, np.nan, dtype=skymap.full_map_latitude[0, :, :].dtype) # Interpolate lats and lons at desired altitude for i in range(skymap.full_map_latitude.shape[1]): for j in range(skymap.full_map_latitude.shape[2]): - lats[i, j] = np.interp(altitude_km * 1000.0, skymap.full_map_altitude, skymap.full_map_latitude[:, i, j]) - lons[i, j] = np.interp(altitude_km * 1000.0, skymap.full_map_altitude, skymap.full_map_longitude[:, i, j]) + pixel_lats = skymap.full_map_latitude[:, i, j] + pixel_lons = skymap.full_map_longitude[:, i, j] + if np.isnan(pixel_lats).any() or np.isnan(pixel_lons).any(): + continue + lats[i, j] = np.interp(altitude_km, interp_alts, pixel_lats) + lons[i, j] = np.interp(altitude_km, interp_alts, pixel_lons) lons[np.where(lons > 180)] -= 360.0 # Fix skymap to be in (-180,180) format + # Check that lat/lon range is reasonable + min_skymap_lat = np.nanmin(lats) + max_skymap_lat = np.nanmax(lats) + min_skymap_lon = np.nanmin(lons) + max_skymap_lon = np.nanmax(lons) + if (lat_0 <= min_skymap_lat) or (lat_1 >= max_skymap_lat): + raise ValueError(f"Latitude range supplied is outside the valid range for this skymap {(min_skymap_lat,max_skymap_lat)}.") + if (lon_0 <= min_skymap_lon) or (lon_1 >= max_skymap_lon): + raise ValueError(f"Longitude range supplied is outside the valid range for this skymap {(min_skymap_lon,max_skymap_lon)}.") + # Obtain indices into skymap within lat/lon range - bound_idx = np.where(np.logical_and.reduce((lats > float(lat_0), lats < float(lat_1), lons > float(lon_0), lons < float(lon_1)))) + bound_idx = np.where(np.logical_and.reduce((lats >= float(lat_0), lats <= float(lat_1), lons >= float(lon_0), lons <= float(lon_1)))) # If boundaries contain no data, raise error if len(bound_idx[0]) == 0 or len(bound_idx[1]) == 0: - raise ValueError("No data within desired bounds.") + raise ValueError("No data within desired bounds. Try a larger area.") # Convert from skymap coords to image coords bound_idx = tuple(i - 1 for i in bound_idx) @@ -620,8 +710,25 @@

Raises

# Slice out the bounded data if n_channels == 1: bound_data = images[bound_idx[0], bound_idx[1], :] + if show_preview: + preview_img = scale_intensity(images[:, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1]] = 255 + plt.figure() + plt.imshow(preview_img, cmap="grey", origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() elif n_channels == 3: bound_data = images[bound_idx[0], bound_idx[1], :, :] + if show_preview: + preview_img = scale_intensity(images[:, :, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1], 0] = 255 + preview_img[bound_idx[0], bound_idx[1], 1:] = 0 + plt.figure() + plt.imshow(preview_img, origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() else: raise ValueError("Unrecognized image format with shape: " + str(images.shape)) @@ -639,7 +746,7 @@

Raises

-def mag(images: numpy.ndarray, timestamp: datetime.datetime, skymap: pyucalgarysrs.data.classes.Skymap, altitude_km: Union[float, int], lonlat_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None) ‑> numpy.ndarray +def mag(images: numpy.ndarray, timestamp: datetime.datetime, skymap: pyucalgarysrs.data.classes.Skymap, altitude_km: Union[float, int], lonlat_bounds: Sequence[Union[float, int]], metric: Literal['mean', 'median', 'sum'] = 'median', n_channels: Optional[int] = None, show_preview: bool = False) ‑> numpy.ndarray

Compute a metric of image data within a magnetic lat/lon boundary.

@@ -663,6 +770,8 @@

Args

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data.
+

show_preview (bool): +Plot a preview of the bounded area.

Returns

A numpy.ndarray containing the metrics computed within elevation range, for all image frames.

Raises

@@ -680,7 +789,8 @@

Raises

altitude_km: Union[int, float], lonlat_bounds: Sequence[Union[int, float]], metric: Literal["mean", "median", "sum"] = "median", - n_channels: Optional[int] = None) -> np.ndarray: + n_channels: Optional[int] = None, + show_preview: bool = False) -> np.ndarray: """ Compute a metric of image data within a magnetic lat/lon boundary. @@ -708,6 +818,9 @@

Raises

By default, function will assume the type of data passed as input - this argument can be used to manually specify the number of channels contained in image data. + show_preview (bool): + Plot a preview of the bounded area. + Returns: A numpy.ndarray containing the metrics computed within elevation range, for all image frames. @@ -761,28 +874,32 @@

Raises

raise ValueError("Polygon defined with zero area.") # Obtain lat/lon arrays from skymap - if (altitude_km * 1000.0 in skymap.full_map_altitude): - altitude_idx = np.where(altitude_km * 1000.0 == skymap.full_map_altitude) + interp_alts = skymap.full_map_altitude / 1000.0 + if (altitude_km in interp_alts): + altitude_idx = np.where(altitude_km == interp_alts) lats = np.squeeze(skymap.full_map_latitude[altitude_idx, :, :]) lons = np.squeeze(skymap.full_map_longitude[altitude_idx, :, :]) - lons[np.where(lons > 180)] -= 360.0 + lons[np.where(lons > 180)] -= 360.0 # Fix skymap to be in (-180,180) format else: # Make sure altitude is in range that can be interpolated - if (altitude_km * 1000.0 < skymap.full_map_altitude[0]) or (altitude_km * 1000.0 > skymap.full_map_altitude[2]): - raise ValueError("Altitude " + str(altitude_km) + " outside valid range of " + - str((skymap.full_map_altitude[0] / 1000.0, skymap.full_map_altitude[2] / 1000.0))) + if (altitude_km < interp_alts[0]) or (altitude_km > interp_alts[2]): + raise ValueError("Altitude " + str(altitude_km) + " outside valid range of " + str((interp_alts[0], interp_alts[2]))) # Initialze empty lat/lon arrays lats = np.full(np.squeeze(skymap.full_map_latitude[0, :, :]).shape, np.nan, dtype=skymap.full_map_latitude[0, :, :].dtype) - lons = lats.copy() + lons = np.full(np.squeeze(skymap.full_map_latitude[0, :, :]).shape, np.nan, dtype=skymap.full_map_latitude[0, :, :].dtype) # Interpolate lats and lons at desired altitude for i in range(skymap.full_map_latitude.shape[1]): for j in range(skymap.full_map_latitude.shape[2]): - lats[i, j] = np.interp(altitude_km * 1000.0, skymap.full_map_altitude, skymap.full_map_latitude[:, i, j]) - lons[i, j] = np.interp(altitude_km * 1000.0, skymap.full_map_altitude, skymap.full_map_longitude[:, i, j]) + pixel_lats = skymap.full_map_latitude[:, i, j] + pixel_lons = skymap.full_map_longitude[:, i, j] + if np.isnan(pixel_lats).any() or np.isnan(pixel_lons).any(): + continue + lats[i, j] = np.interp(altitude_km, interp_alts, pixel_lats) + lons[i, j] = np.interp(altitude_km, interp_alts, pixel_lons) lons[np.where(lons > 180)] -= 360.0 # Fix skymap to be in (-180,180) format @@ -791,12 +908,28 @@

Raises

mag_lats = np.reshape(mag_lats, lats.shape) mag_lons = np.reshape(mag_lons, lons.shape) + # Check that lat/lon range is reasonable + min_skymap_lat = np.nanmin(mag_lats) + max_skymap_lat = np.nanmax(mag_lats) + min_skymap_lon = np.nanmin(mag_lons) + max_skymap_lon = np.nanmax(mag_lons) + if (lat_0 <= min_skymap_lat) or (lat_1 >= max_skymap_lat): + raise ValueError(f"Latitude range supplied is outside the valid range for this skymap {(min_skymap_lat,max_skymap_lat)}.") + if (lon_0 <= min_skymap_lon) or (lon_1 >= max_skymap_lon): + raise ValueError(f"Latitude range supplied is outside the valid range for this skymap {(min_skymap_lon,max_skymap_lon)}.") + # Obtain indices into skymap within lat/lon range - bound_idx = np.where(np.logical_and.reduce((mag_lats > float(lat_0), mag_lats < float(lat_1), mag_lons > float(lon_0), mag_lons < float(lon_1)))) + bound_idx = np.where( + np.logical_and.reduce(( + mag_lats >= float(lat_0), + mag_lats <= float(lat_1), + mag_lons >= float(lon_0), + mag_lons <= float(lon_1), + ))) # If boundaries contain no data, raise error if len(bound_idx[0]) == 0 or len(bound_idx[1]) == 0: - raise ValueError("No data within desired bounds.") + raise ValueError("No data within desired bounds. Try a larger area.") # Convert from skymap coords to image coords bound_idx = tuple(i - 1 for i in bound_idx) @@ -805,8 +938,25 @@

Raises

# Slice out the bounded data if n_channels == 1: bound_data = images[bound_idx[0], bound_idx[1], :] + if show_preview: + preview_img = scale_intensity(images[:, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1]] = 255 + plt.figure() + plt.imshow(preview_img, cmap="grey", origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() elif n_channels == 3: bound_data = images[bound_idx[0], bound_idx[1], :, :] + if show_preview: + preview_img = scale_intensity(images[:, :, :, 0], top=230) + preview_img[bound_idx[0], bound_idx[1], 0] = 255 + preview_img[bound_idx[0], bound_idx[1], 1:] = 0 + plt.figure() + plt.imshow(preview_img, origin="lower") + plt.title("Bounded Area Preview") + plt.axis("off") + plt.show() else: raise ValueError("Unrecognized image format with shape: " + str(images.shape)) diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/calibration/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/calibration/index.html index 98f201f..be252e2 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/calibration/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/calibration/index.html @@ -61,7 +61,7 @@

Module pyaurorax.tools.calibration

Functions

-def rego(images: numpy.ndarray, cal_flatfield: Optional[pyucalgarysrs.data.classes.Calibration] = None, cal_rayleighs: Optional[pyucalgarysrs.data.classes.Calibration] = None, step_dark_frame_correction: bool = True, step_flatfield_correction: bool = True, step_rayleighs_conversion: bool = True, exposure_length_sec: float = 2.0) ‑> numpy.ndarray +def rego(images: numpy.ndarray, cal_flatfield: Optional[pyucalgarysrs.data.classes.Calibration] = None, cal_rayleighs: Optional[pyucalgarysrs.data.classes.Calibration] = None, step_dark_frame_correction: bool = True, step_flatfield_calibration: bool = True, step_rayleighs_calibration: bool = True, exposure_length_sec: float = 2.0) ‑> numpy.ndarray

Apply various calibration adjustments to a single or set of images raw images.

@@ -74,13 +74,13 @@

Args

the step_flatfield_corection is set to True.
cal_rayleighs : Calibration
Calibration object containing the Rayleighs data to utilize. This field is required if -the step_rayleighs_conversion is set to True.
+the step_rayleighs_calibration is set to True.
step_dark_frame_correction : bool
Perform the dark frame correction step. Defaults to True.
-
step_flatfield_correction : bool
+
step_flatfield_calibration : bool
Perform the flatfield correction step. Defaults to True. Note that the cal_flatfield parameter must be supplied if this is True.
-
step_rayleighs_conversion : bool
+
step_rayleighs_calibration : bool
Perform the Rayleighs conversion step. Defaults to True. Note that the cal_rayleighs parameter must be supplied if this is True.
exposure_length_sec : float
@@ -106,8 +106,8 @@

Raises

cal_flatfield: Optional[Calibration] = None, cal_rayleighs: Optional[Calibration] = None, step_dark_frame_correction: bool = True, - step_flatfield_correction: bool = True, - step_rayleighs_conversion: bool = True, + step_flatfield_calibration: bool = True, + step_rayleighs_calibration: bool = True, exposure_length_sec: float = 2.0, ) -> np.ndarray: """ @@ -121,13 +121,13 @@

Raises

the `step_flatfield_corection` is set to True. cal_rayleighs (pyaurorax.data.ucalgary.Calibration): Calibration object containing the Rayleighs data to utilize. This field is required if - the `step_rayleighs_conversion` is set to True. + the `step_rayleighs_calibration` is set to True. step_dark_frame_correction (bool): Perform the dark frame correction step. Defaults to `True`. - step_flatfield_correction (bool): + step_flatfield_calibration (bool): Perform the flatfield correction step. Defaults to `True`. Note that the `cal_flatfield` parameter must be supplied if this is True. - step_rayleighs_conversion (bool): + step_rayleighs_calibration (bool): Perform the Rayleighs conversion step. Defaults to `True.` Note that the `cal_rayleighs` parameter must be supplied if this is True. exposure_length_sec (float): @@ -145,9 +145,9 @@

Raises

ValueError: issues encountered with supplied parameters. """ # verify that we have everything we need for each requested step - if (step_flatfield_correction is True and cal_flatfield is None): + if (step_flatfield_calibration is True and cal_flatfield is None): raise ValueError("The cal_flatfield parameter must be supplied to perform the flatfield correction step") - if (step_rayleighs_conversion is True and cal_rayleighs is None): + if (step_rayleighs_calibration is True and cal_rayleighs is None): raise ValueError("The cal_rayleighs parameter must be supplied to perform the rayleighs conversion step") # init @@ -160,11 +160,11 @@

Raises

calibrated_images = perform_dark_frame_correction(images, 5) # apply the flatfield correction - if (step_flatfield_correction is True and cal_flatfield is not None): - calibrated_images = perform_flatfield_correction(calibrated_images, cal_flatfield) + if (step_flatfield_calibration is True and cal_flatfield is not None): + calibrated_images = perform_flatfield_calibration(calibrated_images, cal_flatfield) # apply the rayleighs conversion - if (step_rayleighs_conversion is True and cal_rayleighs is not None): + if (step_rayleighs_calibration is True and cal_rayleighs is not None): calibrated_images = perform_rayleighs_correction(calibrated_images, cal_rayleighs, exposure_length_sec) # return @@ -172,7 +172,7 @@

Raises

-def trex_nir(images: numpy.ndarray, cal_flatfield: Optional[pyucalgarysrs.data.classes.Calibration] = None, cal_rayleighs: Optional[pyucalgarysrs.data.classes.Calibration] = None, step_dark_frame_correction: bool = True, step_flatfield_correction: bool = True, step_rayleighs_conversion: bool = True, exposure_length_sec: float = 5.0) ‑> numpy.ndarray +def trex_nir(images: numpy.ndarray, cal_flatfield: Optional[pyucalgarysrs.data.classes.Calibration] = None, cal_rayleighs: Optional[pyucalgarysrs.data.classes.Calibration] = None, step_dark_frame_correction: bool = True, step_flatfield_calibration: bool = True, step_rayleighs_calibration: bool = True, exposure_length_sec: float = 5.0) ‑> numpy.ndarray

Apply various calibration adjustments to a single or set of images raw images.

@@ -185,13 +185,13 @@

Args

the step_flatfield_corection is set to True.
cal_rayleighs : Calibration
Calibration object containing the Rayleighs data to utilize. This field is required if -the step_rayleighs_conversion is set to True.
+the step_rayleighs_calibration is set to True.
step_dark_frame_correction : bool
Perform the dark frame correction step. Defaults to True.
-
step_flatfield_correction : bool
+
step_flatfield_calibration : bool
Perform the flatfield correction step. Defaults to True. Note that the cal_flatfield parameter must be supplied if this is True.
-
step_rayleighs_conversion : bool
+
step_rayleighs_calibration : bool
Perform the Rayleighs conversion step. Defaults to True. Note that the cal_rayleighs parameter must be supplied if this is True.
exposure_length_sec : float
@@ -217,8 +217,8 @@

Raises

cal_flatfield: Optional[Calibration] = None, cal_rayleighs: Optional[Calibration] = None, step_dark_frame_correction: bool = True, - step_flatfield_correction: bool = True, - step_rayleighs_conversion: bool = True, + step_flatfield_calibration: bool = True, + step_rayleighs_calibration: bool = True, exposure_length_sec: float = 5.0, ) -> np.ndarray: """ @@ -232,13 +232,13 @@

Raises

the `step_flatfield_corection` is set to True. cal_rayleighs (pyaurorax.data.ucalgary.Calibration): Calibration object containing the Rayleighs data to utilize. This field is required if - the `step_rayleighs_conversion` is set to True. + the `step_rayleighs_calibration` is set to True. step_dark_frame_correction (bool): Perform the dark frame correction step. Defaults to `True`. - step_flatfield_correction (bool): + step_flatfield_calibration (bool): Perform the flatfield correction step. Defaults to `True`. Note that the `cal_flatfield` parameter must be supplied if this is True. - step_rayleighs_conversion (bool): + step_rayleighs_calibration (bool): Perform the Rayleighs conversion step. Defaults to `True.` Note that the `cal_rayleighs` parameter must be supplied if this is True. exposure_length_sec (float): @@ -256,9 +256,9 @@

Raises

ValueError: issues encountered with supplied parameters. """ # verify that we have everything we need for each requested step - if (step_flatfield_correction is True and cal_flatfield is None): + if (step_flatfield_calibration is True and cal_flatfield is None): raise ValueError("The cal_flatfield parameter must be supplied to perform the flatfield correction step") - if (step_rayleighs_conversion is True and cal_rayleighs is None): + if (step_rayleighs_calibration is True and cal_rayleighs is None): raise ValueError("The cal_rayleighs parameter must be supplied to perform the rayleighs conversion step") # init @@ -271,11 +271,11 @@

Raises

calibrated_images = perform_dark_frame_correction(images, 5) # apply the flatfield correction - if (step_flatfield_correction is True and cal_flatfield is not None): - calibrated_images = perform_flatfield_correction(calibrated_images, cal_flatfield) + if (step_flatfield_calibration is True and cal_flatfield is not None): + calibrated_images = perform_flatfield_calibration(calibrated_images, cal_flatfield) # apply the rayleighs conversion - if (step_rayleighs_conversion is True and cal_rayleighs is not None): + if (step_rayleighs_calibration is True and cal_rayleighs is not None): calibrated_images = perform_rayleighs_correction(calibrated_images, cal_rayleighs, exposure_length_sec) # return diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/montage.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/montage.html index 554f49e..1b036d3 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/montage.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/montage.html @@ -66,11 +66,14 @@

Module pyaurorax.tools.classes.montage

Timestamps corresponding to each montage image. """ - def __init__(self, data: np.ndarray, timestamp: List[datetime.datetime]): + def __init__(self, data: np.ndarray, timestamp: List[datetime.datetime], n_channels: int): # public vars self.data = data self.timestamp = timestamp + # private vars + self.__n_channels = n_channels + def __str__(self) -> str: return self.__repr__() @@ -160,12 +163,12 @@

Module pyaurorax.tools.classes.montage

# for each image for ax, i in zip(axs.flat, range(0, len(self.timestamp))): - if (len(self.data.shape) == 3): + if (self.__n_channels == 1): # single channel ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") - elif (len(self.data.shape) == 4): + elif (self.__n_channels == 3): # single channel - ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") + ax.imshow(self.data[:, :, :, i], cmap=cmap, origin="lower", interpolation="nearest") else: raise ValueError("Can only plot 3 or 4 dimensional data (series of single-channel or RGB mages), but found data of shape %s" % (self.data.shape)) @@ -176,7 +179,7 @@

Module pyaurorax.tools.classes.montage

if (timestamps_display is True): ax.text( int(np.floor(self.data.shape[1] / 2.)), - 0.5, + 5, self.timestamp[i].strftime(timestamps_format), ha="center", fontsize=timestamps_fontsize, @@ -232,7 +235,7 @@

Classes

class Montage -(data: numpy.ndarray, timestamp: List[datetime.datetime]) +(data: numpy.ndarray, timestamp: List[datetime.datetime], n_channels: int)

Class representation for a montage

@@ -260,11 +263,14 @@

Attributes

Timestamps corresponding to each montage image. """ - def __init__(self, data: np.ndarray, timestamp: List[datetime.datetime]): + def __init__(self, data: np.ndarray, timestamp: List[datetime.datetime], n_channels: int): # public vars self.data = data self.timestamp = timestamp + # private vars + self.__n_channels = n_channels + def __str__(self) -> str: return self.__repr__() @@ -354,12 +360,12 @@

Attributes

# for each image for ax, i in zip(axs.flat, range(0, len(self.timestamp))): - if (len(self.data.shape) == 3): + if (self.__n_channels == 1): # single channel ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") - elif (len(self.data.shape) == 4): + elif (self.__n_channels == 3): # single channel - ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") + ax.imshow(self.data[:, :, :, i], cmap=cmap, origin="lower", interpolation="nearest") else: raise ValueError("Can only plot 3 or 4 dimensional data (series of single-channel or RGB mages), but found data of shape %s" % (self.data.shape)) @@ -370,7 +376,7 @@

Attributes

if (timestamps_display is True): ax.text( int(np.floor(self.data.shape[1] / 2.)), - 0.5, + 5, self.timestamp[i].strftime(timestamps_format), ha="center", fontsize=timestamps_fontsize, @@ -550,12 +556,12 @@

Raises

# for each image for ax, i in zip(axs.flat, range(0, len(self.timestamp))): - if (len(self.data.shape) == 3): + if (self.__n_channels == 1): # single channel ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") - elif (len(self.data.shape) == 4): + elif (self.__n_channels == 3): # single channel - ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") + ax.imshow(self.data[:, :, :, i], cmap=cmap, origin="lower", interpolation="nearest") else: raise ValueError("Can only plot 3 or 4 dimensional data (series of single-channel or RGB mages), but found data of shape %s" % (self.data.shape)) @@ -566,7 +572,7 @@

Raises

if (timestamps_display is True): ax.text( int(np.floor(self.data.shape[1] / 2.)), - 0.5, + 5, self.timestamp[i].strftime(timestamps_format), ha="center", fontsize=timestamps_fontsize, diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/mosaic.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/mosaic.html index 1b229ef..db84593 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/mosaic.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/classes/mosaic.html @@ -156,7 +156,7 @@

Module pyaurorax.tools.classes.mosaic

contour_data (Dict[str, List[Any]]): Generated contour data. """ - polygon_data: PolyCollection + polygon_data: Union[PolyCollection, List[PolyCollection]] cartopy_projection: Projection contour_data: Optional[Dict[str, List[Any]]] = None @@ -164,13 +164,18 @@

Module pyaurorax.tools.classes.mosaic

return self.__repr__() def __repr__(self) -> str: + if isinstance(self.polygon_data, list): + polycollection_str = "[PolyCollection(...), ...]" + else: + polycollection_str = "PolyCollection(...)" + if self.contour_data is not None: return "Mosaic(polygon_data=PolyCollection(...), cartopy_projection=Projection(%s), %s Contours)" % ( self.cartopy_projection.to_string(), len(self.contour_data.get("x", [])), ) else: - return "Mosaic(polygon_data=PolyCollection(...), cartopy_projection=Projection(%s))" % (self.cartopy_projection.to_string()) + return "Mosaic(polygon_data="+polycollection_str+", cartopy_projection=Projection(%s))" % (self.cartopy_projection.to_string()) def plot(self, map_extent: Sequence[Union[float, int]], @@ -179,11 +184,11 @@

Module pyaurorax.tools.classes.mosaic

max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, - land_color: str = "grey", + land_color: str = "gray", land_edgecolor: str = "#8A8A8A", borders_color: str = "#AEAEAE", borders_disable: bool = False, - cbar_colormap: str = "grey", + cbar_colormap: str = "gray", returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, @@ -213,7 +218,7 @@

Module pyaurorax.tools.classes.mosaic

as a word, or hexcode prefixed with a '#' character (ie. `#55AADD`). land_color (str): - Colour of the land. Default is `grey`. Colours can be supplied as a word, or hexcode + Colour of the land. Default is `gray`. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. `#41BB87`). land_edgecolor (str): @@ -228,7 +233,7 @@

Module pyaurorax.tools.classes.mosaic

Disbale rendering of the borders. Default is `False`. cbar_colorcmap (str): - The matplotlib colormap to use for the plotted color bar. Default is `grey`. + The matplotlib colormap to use for the plotted color bar. Default is `gray`. Commonly used colormaps are: @@ -303,7 +308,11 @@

Module pyaurorax.tools.classes.mosaic

# # NOTE: it seems that when running this function a second time, the polygon # data is not too happy. So to handle this, we plot a copy of the polygon data - ax.add_collection(copy(self.polygon_data)) + if isinstance(self.polygon_data, list): + for polygon_data in self.polygon_data: + ax.add_collection(copy(polygon_data)) + else: + ax.add_collection(copy(self.polygon_data)) if self.contour_data is not None: for i in range(len(self.contour_data["x"])): @@ -312,6 +321,7 @@

Module pyaurorax.tools.classes.mosaic

color=self.contour_data["color"][i], linewidth=self.contour_data["linewidth"][i], linestyle=self.contour_data["linestyle"][i], + marker=self.contour_data["marker"][i], zorder=self.contour_data["zorder"][i]) # set title @@ -320,6 +330,9 @@

Module pyaurorax.tools.classes.mosaic

# add text if (rayleighs is True): + if isinstance(self.polygon_data, list): + raise ValueError("Rayleighs Keyword is currently not available for mosaics with multiple sets of data.") + # Create a colorbar, in Rayleighs, that accounts for the scaling limit we applied cbar_ticks = [float(j) / 5. for j in range(0, 6)] cbar_ticknames = [str(int(max_rayleighs / 5) * j) for j in range(0, 6)] @@ -384,6 +397,7 @@

Module pyaurorax.tools.classes.mosaic

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geographic contours to a mosaic. @@ -410,6 +424,9 @@

Module pyaurorax.tools.classes.mosaic

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -436,6 +453,10 @@

Module pyaurorax.tools.classes.mosaic

if linewidth <= 0: raise ValueError("Linewidth must be greater than zero.") + # Check that marker is valid + if marker not in ["", "o", ".", "p", "*", "x", "+", "X"]: + raise ValueError(f"Marker '{marker}' is not currently supported.") + # Convert numerics to lists if necessary if constant_lats is not None: if isinstance(constant_lats, (float, int)): @@ -446,7 +467,7 @@

Module pyaurorax.tools.classes.mosaic

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -472,6 +493,7 @@

Module pyaurorax.tools.classes.mosaic

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -493,6 +515,7 @@

Module pyaurorax.tools.classes.mosaic

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -515,6 +538,7 @@

Module pyaurorax.tools.classes.mosaic

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) def add_mag_contours(self, @@ -526,6 +550,7 @@

Module pyaurorax.tools.classes.mosaic

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geomagnetic contours to a mosaic. @@ -555,6 +580,9 @@

Module pyaurorax.tools.classes.mosaic

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -591,7 +619,7 @@

Module pyaurorax.tools.classes.mosaic

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -618,6 +646,7 @@

Module pyaurorax.tools.classes.mosaic

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -641,6 +670,7 @@

Module pyaurorax.tools.classes.mosaic

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -664,6 +694,7 @@

Module pyaurorax.tools.classes.mosaic

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))
@@ -678,7 +709,7 @@

Classes

class Mosaic -(polygon_data: matplotlib.collections.PolyCollection, cartopy_projection: cartopy.crs.Projection, contour_data: Optional[Dict[str, List[Any]]] = None) +(polygon_data: Union[matplotlib.collections.PolyCollection, List[matplotlib.collections.PolyCollection]], cartopy_projection: cartopy.crs.Projection, contour_data: Optional[Dict[str, List[Any]]] = None)

Class representation for a generated mosaic.

@@ -708,7 +739,7 @@

Attributes

contour_data (Dict[str, List[Any]]): Generated contour data. """ - polygon_data: PolyCollection + polygon_data: Union[PolyCollection, List[PolyCollection]] cartopy_projection: Projection contour_data: Optional[Dict[str, List[Any]]] = None @@ -716,13 +747,18 @@

Attributes

return self.__repr__() def __repr__(self) -> str: + if isinstance(self.polygon_data, list): + polycollection_str = "[PolyCollection(...), ...]" + else: + polycollection_str = "PolyCollection(...)" + if self.contour_data is not None: return "Mosaic(polygon_data=PolyCollection(...), cartopy_projection=Projection(%s), %s Contours)" % ( self.cartopy_projection.to_string(), len(self.contour_data.get("x", [])), ) else: - return "Mosaic(polygon_data=PolyCollection(...), cartopy_projection=Projection(%s))" % (self.cartopy_projection.to_string()) + return "Mosaic(polygon_data="+polycollection_str+", cartopy_projection=Projection(%s))" % (self.cartopy_projection.to_string()) def plot(self, map_extent: Sequence[Union[float, int]], @@ -731,11 +767,11 @@

Attributes

max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, - land_color: str = "grey", + land_color: str = "gray", land_edgecolor: str = "#8A8A8A", borders_color: str = "#AEAEAE", borders_disable: bool = False, - cbar_colormap: str = "grey", + cbar_colormap: str = "gray", returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, @@ -765,7 +801,7 @@

Attributes

as a word, or hexcode prefixed with a '#' character (ie. `#55AADD`). land_color (str): - Colour of the land. Default is `grey`. Colours can be supplied as a word, or hexcode + Colour of the land. Default is `gray`. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. `#41BB87`). land_edgecolor (str): @@ -780,7 +816,7 @@

Attributes

Disbale rendering of the borders. Default is `False`. cbar_colorcmap (str): - The matplotlib colormap to use for the plotted color bar. Default is `grey`. + The matplotlib colormap to use for the plotted color bar. Default is `gray`. Commonly used colormaps are: @@ -855,7 +891,11 @@

Attributes

# # NOTE: it seems that when running this function a second time, the polygon # data is not too happy. So to handle this, we plot a copy of the polygon data - ax.add_collection(copy(self.polygon_data)) + if isinstance(self.polygon_data, list): + for polygon_data in self.polygon_data: + ax.add_collection(copy(polygon_data)) + else: + ax.add_collection(copy(self.polygon_data)) if self.contour_data is not None: for i in range(len(self.contour_data["x"])): @@ -864,6 +904,7 @@

Attributes

color=self.contour_data["color"][i], linewidth=self.contour_data["linewidth"][i], linestyle=self.contour_data["linestyle"][i], + marker=self.contour_data["marker"][i], zorder=self.contour_data["zorder"][i]) # set title @@ -872,6 +913,9 @@

Attributes

# add text if (rayleighs is True): + if isinstance(self.polygon_data, list): + raise ValueError("Rayleighs Keyword is currently not available for mosaics with multiple sets of data.") + # Create a colorbar, in Rayleighs, that accounts for the scaling limit we applied cbar_ticks = [float(j) / 5. for j in range(0, 6)] cbar_ticknames = [str(int(max_rayleighs / 5) * j) for j in range(0, 6)] @@ -936,6 +980,7 @@

Attributes

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geographic contours to a mosaic. @@ -962,6 +1007,9 @@

Attributes

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -988,6 +1036,10 @@

Attributes

if linewidth <= 0: raise ValueError("Linewidth must be greater than zero.") + # Check that marker is valid + if marker not in ["", "o", ".", "p", "*", "x", "+", "X"]: + raise ValueError(f"Marker '{marker}' is not currently supported.") + # Convert numerics to lists if necessary if constant_lats is not None: if isinstance(constant_lats, (float, int)): @@ -998,7 +1050,7 @@

Attributes

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -1024,6 +1076,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -1045,6 +1098,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -1067,6 +1121,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) def add_mag_contours(self, @@ -1078,6 +1133,7 @@

Attributes

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geomagnetic contours to a mosaic. @@ -1107,6 +1163,9 @@

Attributes

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -1143,7 +1202,7 @@

Attributes

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -1170,6 +1229,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -1193,6 +1253,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -1216,6 +1277,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))

Class variables

@@ -1228,7 +1290,7 @@

Class variables

-
var polygon_data : matplotlib.collections.PolyCollection
+
var polygon_data : Union[matplotlib.collections.PolyCollection, List[matplotlib.collections.PolyCollection]]
@@ -1236,7 +1298,7 @@

Class variables

Methods

-def add_geo_contours(self, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', bring_to_front: bool = False) +def add_geo_contours(self, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', marker: str = '', bring_to_front: bool = False)

Add geographic contours to a mosaic.

@@ -1255,6 +1317,8 @@

Args

The contour thickness.

linestyle (str): The matplotlib linestyle used for the contour(s).

+

marker (str): +The matplotlib marker used for the contour(s).

Returns

The object's contour_data parameter is populated appropriately.

Raises

@@ -1274,6 +1338,7 @@

Raises

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geographic contours to a mosaic. @@ -1300,6 +1365,9 @@

Raises

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -1326,6 +1394,10 @@

Raises

if linewidth <= 0: raise ValueError("Linewidth must be greater than zero.") + # Check that marker is valid + if marker not in ["", "o", ".", "p", "*", "x", "+", "X"]: + raise ValueError(f"Marker '{marker}' is not currently supported.") + # Convert numerics to lists if necessary if constant_lats is not None: if isinstance(constant_lats, (float, int)): @@ -1336,7 +1408,7 @@

Raises

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -1362,6 +1434,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -1383,6 +1456,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -1405,11 +1479,12 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))
-def add_mag_contours(self, timestamp: datetime.datetime, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', bring_to_front: bool = False) +def add_mag_contours(self, timestamp: datetime.datetime, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', marker: str = '', bring_to_front: bool = False)

Add geomagnetic contours to a mosaic.

@@ -1430,6 +1505,8 @@

Args

The contour thickness.

linestyle (str): The matplotlib linestyle used for the contour(s).

+

marker (str): +The matplotlib marker used for the contour(s).

Returns

The object's contour_data parameter is populated appropriately.

Raises

@@ -1450,6 +1527,7 @@

Raises

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geomagnetic contours to a mosaic. @@ -1479,6 +1557,9 @@

Raises

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -1515,7 +1596,7 @@

Raises

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -1542,6 +1623,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -1565,6 +1647,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -1588,11 +1671,12 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))
-def plot(self, map_extent: Sequence[Union[float, int]], figsize: Optional[Tuple[int, int]] = None, rayleighs: bool = False, max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, land_color: str = 'grey', land_edgecolor: str = '#8A8A8A', borders_color: str = '#AEAEAE', borders_disable: bool = False, cbar_colormap: str = 'grey', returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, savefig_quality: Optional[int] = None) ‑> Any +def plot(self, map_extent: Sequence[Union[float, int]], figsize: Optional[Tuple[int, int]] = None, rayleighs: bool = False, max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, land_color: str = 'gray', land_edgecolor: str = '#8A8A8A', borders_color: str = '#AEAEAE', borders_disable: bool = False, cbar_colormap: str = 'gray', returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, savefig_quality: Optional[int] = None) ‑> Any

Generate a plot of the mosaic data.

@@ -1613,7 +1697,7 @@

Args

Colour of the ocean. Default is cartopy's default shade of blue. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. #55AADD).
land_color : str
-
Colour of the land. Default is grey. Colours can be supplied as a word, or hexcode +
Colour of the land. Default is gray. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. #41BB87).
land_edgecolor : str
Color of the land edges. Default is #8A8A8A. Colours can be supplied as a word, or @@ -1625,7 +1709,7 @@

Args

Disbale rendering of the borders. Default is False.
cbar_colorcmap : str
-

The matplotlib colormap to use for the plotted color bar. Default is grey.

+

The matplotlib colormap to use for the plotted color bar. Default is gray.

Commonly used colormaps are:

  • REGO: gist_heat
  • @@ -1669,11 +1753,11 @@

    Returns

    max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, - land_color: str = "grey", + land_color: str = "gray", land_edgecolor: str = "#8A8A8A", borders_color: str = "#AEAEAE", borders_disable: bool = False, - cbar_colormap: str = "grey", + cbar_colormap: str = "gray", returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, @@ -1703,7 +1787,7 @@

    Returns

    as a word, or hexcode prefixed with a '#' character (ie. `#55AADD`). land_color (str): - Colour of the land. Default is `grey`. Colours can be supplied as a word, or hexcode + Colour of the land. Default is `gray`. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. `#41BB87`). land_edgecolor (str): @@ -1718,7 +1802,7 @@

    Returns

    Disbale rendering of the borders. Default is `False`. cbar_colorcmap (str): - The matplotlib colormap to use for the plotted color bar. Default is `grey`. + The matplotlib colormap to use for the plotted color bar. Default is `gray`. Commonly used colormaps are: @@ -1793,7 +1877,11 @@

    Returns

    # # NOTE: it seems that when running this function a second time, the polygon # data is not too happy. So to handle this, we plot a copy of the polygon data - ax.add_collection(copy(self.polygon_data)) + if isinstance(self.polygon_data, list): + for polygon_data in self.polygon_data: + ax.add_collection(copy(polygon_data)) + else: + ax.add_collection(copy(self.polygon_data)) if self.contour_data is not None: for i in range(len(self.contour_data["x"])): @@ -1802,6 +1890,7 @@

    Returns

    color=self.contour_data["color"][i], linewidth=self.contour_data["linewidth"][i], linestyle=self.contour_data["linestyle"][i], + marker=self.contour_data["marker"][i], zorder=self.contour_data["zorder"][i]) # set title @@ -1810,6 +1899,9 @@

    Returns

    # add text if (rayleighs is True): + if isinstance(self.polygon_data, list): + raise ValueError("Rayleighs Keyword is currently not available for mosaics with multiple sets of data.") + # Create a colorbar, in Rayleighs, that accounts for the scaling limit we applied cbar_ticks = [float(j) / 5. for j in range(0, 6)] cbar_ticknames = [str(int(max_rayleighs / 5) * j) for j in range(0, 6)] diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/index.html index 16a4a15..0e7509b 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/index.html @@ -487,7 +487,7 @@

    Raises

-def scale_intensity(data: numpy.ndarray, min: Optional[float] = None, max: Optional[float] = None, top: Optional[float] = None) ‑> numpy.ndarray +def scale_intensity(data: numpy.ndarray, min: Optional[float] = None, max: Optional[float] = None, top: Optional[float] = None, memory_saver: bool = True) ‑> numpy.ndarray

Scale all values of an array that lie in the range min<=x<=max in to @@ -495,17 +495,20 @@

Raises

Args

data : numpy.ndarray
-
data array, can be 2, 3, or 4-dimensional. Assumed -to be an image, or array of images. Also assumed that the first 2 dimensions -are the image's x and y coordinates, and the following dimensions are some -combination of the number of images, and/or the colour channel.
+
Data array, can be 2, 3, or 4-dimensional. Assumed to be an image, or array of +images. Also assumed that the first 2 dimensions are the image's x and y +coordinates, and the following dimensions are some combination of the number of +images, and/or the colour channel.
min : float
-
minimum value of array to be considered
+
Minimum value of array to be considered
max : float
-
maximum value of array to be considered
+
Maximum value of array to be considered
top : float
-
maximum value of the scaled result. If not supplied, the max value +
Maximum value of the scaled result. If not supplied, the max value of the data array's dtype is used.
+
memory_saver : bool
+
Utilize less RAM when scaling a set of images. Defaults to True. If set to False then +the scaling routine will be faster, but will utilize significantly more RAM.

Returns

A new numpy.ndarray that is the same dimensions as the inputted data array, @@ -524,21 +527,33 @@

Raises

min: Optional[float] = None, max: Optional[float] = None, top: Optional[float] = None, + memory_saver: bool = True, ) -> np.ndarray: """ Scale all values of an array that lie in the range min<=x<=max in to the range 0<=x<=high. Args: - data (numpy.ndarray): data array, can be 2, 3, or 4-dimensional. Assumed - to be an image, or array of images. Also assumed that the first 2 dimensions - are the image's x and y coordinates, and the following dimensions are some - combination of the number of images, and/or the colour channel. - min (float): minimum value of array to be considered - max (float): maximum value of array to be considered - top (float): maximum value of the scaled result. If not supplied, the max value + data (numpy.ndarray): + Data array, can be 2, 3, or 4-dimensional. Assumed to be an image, or array of + images. Also assumed that the first 2 dimensions are the image's x and y + coordinates, and the following dimensions are some combination of the number of + images, and/or the colour channel. + + min (float): + Minimum value of array to be considered + + max (float): + Maximum value of array to be considered + + top (float): + Maximum value of the scaled result. If not supplied, the max value of the data array's dtype is used. + memory_saver (bool): + Utilize less RAM when scaling a set of images. Defaults to `True`. If set to `False` then + the scaling routine will be faster, but will utilize significantly more RAM. + Returns: A new `numpy.ndarray` that is the same dimensions as the inputted data array, with the scaling applied. @@ -546,51 +561,34 @@

Raises

Raises: ValueError: Issues with the supplied min, max, or top """ - # init - bottom = 0 - - # set top val - # - # NOTE: we only care about this if it's a uint array. If it's a double array, then we - # check to make sure that a top was specified. - if ("float" in str(data.dtype)): - # this is float type, check that the top was specified - if (top is None): - raise ValueError("The top parameter must be specified when a float array is supplied") - else: - dtype_maxval = np.iinfo(data.dtype).max - if (top is None): - # derive values using dtype of data array - top = dtype_maxval - - # check top - if (top > dtype_maxval): - raise ValueError("The top value must be less than or equal to %s" % (dtype_maxval)) - - # set min and max - if (min is None): - cmin = data.min() - else: - cmin = float(min) - if (max is None): - cmax = data.max() - else: - cmax = float(max) + if (memory_saver is True): + # determine if we are single or 3 channel + n_channels = 1 + if (len(data.shape) == 3): + # single channel + n_channels = 1 + elif (len(data.shape) == 4): + # three channel + n_channels = 3 + else: + ValueError("Unable to determine number of channels based on the supplied images. Make sure you are supplying a " + + "[rows,cols,images] or [rows,cols,channels,images] sized array.") - # set scaling factor - cscale = cmax - cmin - if cscale < 0: - raise ValueError("The max value must be larger than the min value") - elif cscale == 0: - cscale = 1 + # init destination array + images_scaled = np.empty((data.shape), dtype=data.dtype) - # do scaling - scale = float(top - bottom) / cscale - byte_data = (data - cmin) * scale + bottom - scaled_data = (byte_data.clip(bottom, top) + 0.5).astype(data.dtype) + # cycle through each image + for i in range(0, data.shape[-1]): + if (n_channels == 1): + images_scaled[:, :, i] = __scale_data(data[:, :, i], min, max, top) + else: + images_scaled[:, :, :, i] = __scale_data(data[:, :, :, i], min, max, top) - # return - return scaled_data + # return + return images_scaled + else: + # scale and return + return __scale_data(data, min, max, top)
@@ -1588,7 +1586,7 @@

Raises

class Montage -(data: numpy.ndarray, timestamp: List[datetime.datetime]) +(data: numpy.ndarray, timestamp: List[datetime.datetime], n_channels: int)

Class representation for a montage

@@ -1616,11 +1614,14 @@

Attributes

Timestamps corresponding to each montage image. """ - def __init__(self, data: np.ndarray, timestamp: List[datetime.datetime]): + def __init__(self, data: np.ndarray, timestamp: List[datetime.datetime], n_channels: int): # public vars self.data = data self.timestamp = timestamp + # private vars + self.__n_channels = n_channels + def __str__(self) -> str: return self.__repr__() @@ -1710,12 +1711,12 @@

Attributes

# for each image for ax, i in zip(axs.flat, range(0, len(self.timestamp))): - if (len(self.data.shape) == 3): + if (self.__n_channels == 1): # single channel ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") - elif (len(self.data.shape) == 4): + elif (self.__n_channels == 3): # single channel - ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") + ax.imshow(self.data[:, :, :, i], cmap=cmap, origin="lower", interpolation="nearest") else: raise ValueError("Can only plot 3 or 4 dimensional data (series of single-channel or RGB mages), but found data of shape %s" % (self.data.shape)) @@ -1726,7 +1727,7 @@

Attributes

if (timestamps_display is True): ax.text( int(np.floor(self.data.shape[1] / 2.)), - 0.5, + 5, self.timestamp[i].strftime(timestamps_format), ha="center", fontsize=timestamps_fontsize, @@ -1906,12 +1907,12 @@

Raises

# for each image for ax, i in zip(axs.flat, range(0, len(self.timestamp))): - if (len(self.data.shape) == 3): + if (self.__n_channels == 1): # single channel ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") - elif (len(self.data.shape) == 4): + elif (self.__n_channels == 3): # single channel - ax.imshow(self.data[:, :, i], cmap=cmap, origin="lower", interpolation="nearest") + ax.imshow(self.data[:, :, :, i], cmap=cmap, origin="lower", interpolation="nearest") else: raise ValueError("Can only plot 3 or 4 dimensional data (series of single-channel or RGB mages), but found data of shape %s" % (self.data.shape)) @@ -1922,7 +1923,7 @@

Raises

if (timestamps_display is True): ax.text( int(np.floor(self.data.shape[1] / 2.)), - 0.5, + 5, self.timestamp[i].strftime(timestamps_format), ha="center", fontsize=timestamps_fontsize, @@ -1971,7 +1972,7 @@

Raises

class Mosaic -(polygon_data: matplotlib.collections.PolyCollection, cartopy_projection: cartopy.crs.Projection, contour_data: Optional[Dict[str, List[Any]]] = None) +(polygon_data: Union[matplotlib.collections.PolyCollection, List[matplotlib.collections.PolyCollection]], cartopy_projection: cartopy.crs.Projection, contour_data: Optional[Dict[str, List[Any]]] = None)

Class representation for a generated mosaic.

@@ -2001,7 +2002,7 @@

Attributes

contour_data (Dict[str, List[Any]]): Generated contour data. """ - polygon_data: PolyCollection + polygon_data: Union[PolyCollection, List[PolyCollection]] cartopy_projection: Projection contour_data: Optional[Dict[str, List[Any]]] = None @@ -2009,13 +2010,18 @@

Attributes

return self.__repr__() def __repr__(self) -> str: + if isinstance(self.polygon_data, list): + polycollection_str = "[PolyCollection(...), ...]" + else: + polycollection_str = "PolyCollection(...)" + if self.contour_data is not None: return "Mosaic(polygon_data=PolyCollection(...), cartopy_projection=Projection(%s), %s Contours)" % ( self.cartopy_projection.to_string(), len(self.contour_data.get("x", [])), ) else: - return "Mosaic(polygon_data=PolyCollection(...), cartopy_projection=Projection(%s))" % (self.cartopy_projection.to_string()) + return "Mosaic(polygon_data="+polycollection_str+", cartopy_projection=Projection(%s))" % (self.cartopy_projection.to_string()) def plot(self, map_extent: Sequence[Union[float, int]], @@ -2024,11 +2030,11 @@

Attributes

max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, - land_color: str = "grey", + land_color: str = "gray", land_edgecolor: str = "#8A8A8A", borders_color: str = "#AEAEAE", borders_disable: bool = False, - cbar_colormap: str = "grey", + cbar_colormap: str = "gray", returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, @@ -2058,7 +2064,7 @@

Attributes

as a word, or hexcode prefixed with a '#' character (ie. `#55AADD`). land_color (str): - Colour of the land. Default is `grey`. Colours can be supplied as a word, or hexcode + Colour of the land. Default is `gray`. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. `#41BB87`). land_edgecolor (str): @@ -2073,7 +2079,7 @@

Attributes

Disbale rendering of the borders. Default is `False`. cbar_colorcmap (str): - The matplotlib colormap to use for the plotted color bar. Default is `grey`. + The matplotlib colormap to use for the plotted color bar. Default is `gray`. Commonly used colormaps are: @@ -2148,7 +2154,11 @@

Attributes

# # NOTE: it seems that when running this function a second time, the polygon # data is not too happy. So to handle this, we plot a copy of the polygon data - ax.add_collection(copy(self.polygon_data)) + if isinstance(self.polygon_data, list): + for polygon_data in self.polygon_data: + ax.add_collection(copy(polygon_data)) + else: + ax.add_collection(copy(self.polygon_data)) if self.contour_data is not None: for i in range(len(self.contour_data["x"])): @@ -2157,6 +2167,7 @@

Attributes

color=self.contour_data["color"][i], linewidth=self.contour_data["linewidth"][i], linestyle=self.contour_data["linestyle"][i], + marker=self.contour_data["marker"][i], zorder=self.contour_data["zorder"][i]) # set title @@ -2165,6 +2176,9 @@

Attributes

# add text if (rayleighs is True): + if isinstance(self.polygon_data, list): + raise ValueError("Rayleighs Keyword is currently not available for mosaics with multiple sets of data.") + # Create a colorbar, in Rayleighs, that accounts for the scaling limit we applied cbar_ticks = [float(j) / 5. for j in range(0, 6)] cbar_ticknames = [str(int(max_rayleighs / 5) * j) for j in range(0, 6)] @@ -2229,6 +2243,7 @@

Attributes

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geographic contours to a mosaic. @@ -2255,6 +2270,9 @@

Attributes

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -2281,6 +2299,10 @@

Attributes

if linewidth <= 0: raise ValueError("Linewidth must be greater than zero.") + # Check that marker is valid + if marker not in ["", "o", ".", "p", "*", "x", "+", "X"]: + raise ValueError(f"Marker '{marker}' is not currently supported.") + # Convert numerics to lists if necessary if constant_lats is not None: if isinstance(constant_lats, (float, int)): @@ -2291,7 +2313,7 @@

Attributes

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -2317,6 +2339,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -2338,6 +2361,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -2360,6 +2384,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) def add_mag_contours(self, @@ -2371,6 +2396,7 @@

Attributes

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geomagnetic contours to a mosaic. @@ -2400,6 +2426,9 @@

Attributes

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -2436,7 +2465,7 @@

Attributes

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -2463,6 +2492,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -2486,6 +2516,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -2509,6 +2540,7 @@

Attributes

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))

Class variables

@@ -2521,7 +2553,7 @@

Class variables

-
var polygon_data : matplotlib.collections.PolyCollection
+
var polygon_data : Union[matplotlib.collections.PolyCollection, List[matplotlib.collections.PolyCollection]]
@@ -2529,7 +2561,7 @@

Class variables

Methods

-def add_geo_contours(self, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', bring_to_front: bool = False) +def add_geo_contours(self, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', marker: str = '', bring_to_front: bool = False)

Add geographic contours to a mosaic.

@@ -2548,6 +2580,8 @@

Args

The contour thickness.

linestyle (str): The matplotlib linestyle used for the contour(s).

+

marker (str): +The matplotlib marker used for the contour(s).

Returns

The object's contour_data parameter is populated appropriately.

Raises

@@ -2567,6 +2601,7 @@

Raises

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geographic contours to a mosaic. @@ -2593,6 +2628,9 @@

Raises

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -2619,6 +2657,10 @@

Raises

if linewidth <= 0: raise ValueError("Linewidth must be greater than zero.") + # Check that marker is valid + if marker not in ["", "o", ".", "p", "*", "x", "+", "X"]: + raise ValueError(f"Marker '{marker}' is not currently supported.") + # Convert numerics to lists if necessary if constant_lats is not None: if isinstance(constant_lats, (float, int)): @@ -2629,7 +2671,7 @@

Raises

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -2655,6 +2697,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -2676,6 +2719,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -2698,11 +2742,12 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))
-def add_mag_contours(self, timestamp: datetime.datetime, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', bring_to_front: bool = False) +def add_mag_contours(self, timestamp: datetime.datetime, constant_lats: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, constant_lons: Union[float, int, Sequence[Union[float, int]], numpy.ndarray, ForwardRef(None)] = None, lats: Union[numpy.ndarray, list, ForwardRef(None)] = None, lons: Union[numpy.ndarray, list, ForwardRef(None)] = None, color: str = 'black', linewidth: Union[float, int] = 1, linestyle: str = 'solid', marker: str = '', bring_to_front: bool = False)

Add geomagnetic contours to a mosaic.

@@ -2723,6 +2768,8 @@

Args

The contour thickness.

linestyle (str): The matplotlib linestyle used for the contour(s).

+

marker (str): +The matplotlib marker used for the contour(s).

Returns

The object's contour_data parameter is populated appropriately.

Raises

@@ -2743,6 +2790,7 @@

Raises

color: str = "black", linewidth: Union[float, int] = 1, linestyle: str = "solid", + marker: str = "", bring_to_front: bool = False): """ Add geomagnetic contours to a mosaic. @@ -2772,6 +2820,9 @@

Raises

linestyle (str): The matplotlib linestyle used for the contour(s). + marker (str): + The matplotlib marker used for the contour(s). + Returns: The object's contour_data parameter is populated appropriately. @@ -2808,7 +2859,7 @@

Raises

# Initialize contour data dict if it doesn't exist yet if self.contour_data is None: - self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "zorder": []} + self.contour_data = {"x": [], "y": [], "color": [], "linewidth": [], "linestyle": [], "marker": [], "zorder": []} # Obtain the mosaic's projection source_proj = pyproj.CRS.from_user_input(cartopy.crs.Geodetic()) @@ -2835,6 +2886,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Next handling lines of constant latitude @@ -2858,6 +2910,7 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front)) # Now handling lines of constant longitude @@ -2881,11 +2934,12 @@

Raises

self.contour_data["color"].append(color) self.contour_data["linewidth"].append(linewidth) self.contour_data["linestyle"].append(linestyle) + self.contour_data["marker"].append(marker) self.contour_data["zorder"].append(int(bring_to_front))
-def plot(self, map_extent: Sequence[Union[float, int]], figsize: Optional[Tuple[int, int]] = None, rayleighs: bool = False, max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, land_color: str = 'grey', land_edgecolor: str = '#8A8A8A', borders_color: str = '#AEAEAE', borders_disable: bool = False, cbar_colormap: str = 'grey', returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, savefig_quality: Optional[int] = None) ‑> Any +def plot(self, map_extent: Sequence[Union[float, int]], figsize: Optional[Tuple[int, int]] = None, rayleighs: bool = False, max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, land_color: str = 'gray', land_edgecolor: str = '#8A8A8A', borders_color: str = '#AEAEAE', borders_disable: bool = False, cbar_colormap: str = 'gray', returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, savefig_quality: Optional[int] = None) ‑> Any

Generate a plot of the mosaic data.

@@ -2906,7 +2960,7 @@

Args

Colour of the ocean. Default is cartopy's default shade of blue. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. #55AADD).
land_color : str
-
Colour of the land. Default is grey. Colours can be supplied as a word, or hexcode +
Colour of the land. Default is gray. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. #41BB87).
land_edgecolor : str
Color of the land edges. Default is #8A8A8A. Colours can be supplied as a word, or @@ -2918,7 +2972,7 @@

Args

Disbale rendering of the borders. Default is False.
cbar_colorcmap : str
-

The matplotlib colormap to use for the plotted color bar. Default is grey.

+

The matplotlib colormap to use for the plotted color bar. Default is gray.

Commonly used colormaps are:

  • REGO: gist_heat
  • @@ -2962,11 +3016,11 @@

    Returns

    max_rayleighs: int = 20000, title: Optional[str] = None, ocean_color: Optional[str] = None, - land_color: str = "grey", + land_color: str = "gray", land_edgecolor: str = "#8A8A8A", borders_color: str = "#AEAEAE", borders_disable: bool = False, - cbar_colormap: str = "grey", + cbar_colormap: str = "gray", returnfig: bool = False, savefig: bool = False, savefig_filename: Optional[str] = None, @@ -2996,7 +3050,7 @@

    Returns

    as a word, or hexcode prefixed with a '#' character (ie. `#55AADD`). land_color (str): - Colour of the land. Default is `grey`. Colours can be supplied as a word, or hexcode + Colour of the land. Default is `gray`. Colours can be supplied as a word, or hexcode prefixed with a '#' character (ie. `#41BB87`). land_edgecolor (str): @@ -3011,7 +3065,7 @@

    Returns

    Disbale rendering of the borders. Default is `False`. cbar_colorcmap (str): - The matplotlib colormap to use for the plotted color bar. Default is `grey`. + The matplotlib colormap to use for the plotted color bar. Default is `gray`. Commonly used colormaps are: @@ -3086,7 +3140,11 @@

    Returns

    # # NOTE: it seems that when running this function a second time, the polygon # data is not too happy. So to handle this, we plot a copy of the polygon data - ax.add_collection(copy(self.polygon_data)) + if isinstance(self.polygon_data, list): + for polygon_data in self.polygon_data: + ax.add_collection(copy(polygon_data)) + else: + ax.add_collection(copy(self.polygon_data)) if self.contour_data is not None: for i in range(len(self.contour_data["x"])): @@ -3095,6 +3153,7 @@

    Returns

    color=self.contour_data["color"][i], linewidth=self.contour_data["linewidth"][i], linestyle=self.contour_data["linestyle"][i], + marker=self.contour_data["marker"][i], zorder=self.contour_data["zorder"][i]) # set title @@ -3103,6 +3162,9 @@

    Returns

    # add text if (rayleighs is True): + if isinstance(self.polygon_data, list): + raise ValueError("Rayleighs Keyword is currently not available for mosaics with multiple sets of data.") + # Create a colorbar, in Rayleighs, that accounts for the scaling limit we applied cbar_ticks = [float(j) / 5. for j in range(0, 6)] cbar_ticknames = [str(int(max_rayleighs / 5) * j) for j in range(0, 6)] diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/keogram/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/keogram/index.html index 06bb011..6797ba2 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/keogram/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/keogram/index.html @@ -310,7 +310,24 @@

    Returns

    x_max = images.shape[1] - 1 y_max = images.shape[0] - 1 - # Make sure all supplied points are within image bounds + # Remove any points that are not within the image CCD + parsed_x_locs = [] + parsed_y_locs = [] + for i in range(x_locs.shape[0]): + x = x_locs[i] + y = y_locs[i] + + if x < 0 or x > x_max: + continue + if y < 0 or y > y_max: + continue + + parsed_x_locs.append(x) + parsed_y_locs.append(y) + x_locs = np.array(parsed_x_locs) + y_locs = np.array(parsed_y_locs) + + # Make sure all supplied points are within image bounds # NOTE: This should be good to remove as it shouldn't hit, testing needed if len(np.where(np.logical_or(x_locs < 0, x_locs > x_max))[0]) != 0: raise ValueError("The following CCD coordinates passed in through x_locs are outside of the CCD image range: " + str(x_locs[np.where(np.logical_or(x_locs < 0, x_locs > x_max))])) @@ -319,6 +336,7 @@

    Returns

    str(y_locs[np.where(np.logical_or(y_locs < 0, y_locs > y_max))])) # Iterate points in pairs of two + path_counter = 0 for i in range(x_locs.shape[0] - 1): # Points of concern for this iteration @@ -332,7 +350,8 @@

    Returns

    dy = y_1 - y_0 length = np.sqrt(dx**2 + dy**2) if length == 0: - raise ValueError(f"Successive points (x_locs[{i}], y_locs[{i}]) and (x_locs[{i+1}], y_locs[{i+1}]) may not be the same.") + continue + dx /= length dy /= length @@ -359,7 +378,8 @@

    Returns

    indices_inside = __indices_in_polygon(vertices, (images.shape[0], images.shape[1])) if np.any(np.array(indices_inside.shape) == 0): - raise ValueError("Could not form keogram path... Try increasing 'width' or decreasing number of points in input coordinates.") + continue + row_idx, col_idx = zip(*indices_inside) if n_channels == 1: @@ -396,12 +416,19 @@

    Returns

    keo_arr[i, :, 1] = g_pixel_keogram keo_arr[i, :, 2] = b_pixel_keogram + path_counter += 1 + + if path_counter == 0: + raise ValueError( + "Could not form keogram path... First ensure that coordinates are within image range. Then try increasing 'width' or decreasing number of points in input coordinates." + ) + # Create keogram object keo_obj = Keogram(data=keo_arr, timestamp=timestamp) if preview: plt.figure() - plt.imshow(preview_img, cmap='grey', origin='lower') + plt.imshow(preview_img, cmap='gray', origin='lower') plt.axis("off") plt.title("Keogram Domain Preview") plt.show() diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/montage/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/montage/index.html index 96dec7a..eb3570d 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/montage/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/montage/index.html @@ -94,12 +94,24 @@

    Returns

    Returns: A `pyaurorax.tools.Montage` object. """ + # determine if we are single or 3 channel + n_channels = 1 + if (len(images.shape) == 3): + # single channel + n_channels = 1 + elif (len(images.shape) == 4): + # three channel + n_channels = 3 + else: + ValueError("Unable to determine number of channels based on the supplied images. Make sure you are supplying a " + + "[rows,cols,images] or [rows,cols,channels,images] sized array.") + # create the montage object # # NOTE: we presently do nothing more than repackage the data. This logic for create() # is here in case we need to further expand functionality and need it. It's also good # for consistency. - montage_obj = Montage(data=images, timestamp=timestamp) + montage_obj = Montage(data=images, timestamp=timestamp, n_channels=n_channels) # return return montage_obj diff --git a/docs/code/pyaurorax_api_reference/pyaurorax/tools/mosaic/index.html b/docs/code/pyaurorax_api_reference/pyaurorax/tools/mosaic/index.html index 6aeeefa..48c42cc 100644 --- a/docs/code/pyaurorax_api_reference/pyaurorax/tools/mosaic/index.html +++ b/docs/code/pyaurorax_api_reference/pyaurorax/tools/mosaic/index.html @@ -63,7 +63,7 @@

    Module pyaurorax.tools.mosaic

    Functions

    -def create(prepped_data: MosaicData, prepped_skymap: MosaicSkymap, frame_idx: int, cartopy_projection: cartopy.crs.Projection, min_elevation: int = 5, colormap: Optional[str] = 'gray', image_intensity_scales: Union[List, Dict, ForwardRef(None)] = None) ‑> Mosaic +def create(prepped_data: Union[MosaicData, List[MosaicData]], prepped_skymap: Union[MosaicSkymap, List[MosaicSkymap]], frame_idx: int, cartopy_projection: cartopy.crs.Projection, min_elevation: Union[int, List[int]] = 5, colormap: Union[str, List[str], ForwardRef(None)] = None, image_intensity_scales: Union[List, Dict, ForwardRef(None)] = None) ‑> Mosaic

    Create a mosaic object.

    @@ -81,7 +81,7 @@

    Args

    The minimum elevation cutoff when projecting images on the map, in degrees. Default is 5.
    cbar_colorcmap : str
    -

    The matplotlib colormap to use for the rendered image data. Default is grey.

    +

    The matplotlib colormap to use for the rendered image data. Default is gray.

    Commonly used colormaps are:

    • REGO: gist_heat
    • @@ -114,12 +114,12 @@

      Raises

      Expand source code -
      def create(prepped_data: MosaicData,
      -           prepped_skymap: MosaicSkymap,
      +
      def create(prepped_data: Union[MosaicData, List[MosaicData]],
      +           prepped_skymap: Union[MosaicSkymap, List[MosaicSkymap]],
                  frame_idx: int,
                  cartopy_projection: cartopy.crs.Projection,
      -           min_elevation: int = 5,
      -           colormap: Optional[str] = "gray",
      +           min_elevation: Union[int, List[int]] = 5,
      +           colormap: Optional[Union[str, List[str]]] = None,
                  image_intensity_scales: Optional[Union[List, Dict]] = None) -> Mosaic:
           """
           Create a mosaic object.
      @@ -141,7 +141,7 @@ 

      Raises

      The minimum elevation cutoff when projecting images on the map, in degrees. Default is `5`. cbar_colorcmap (str): - The matplotlib colormap to use for the rendered image data. Default is `grey`. + The matplotlib colormap to use for the rendered image data. Default is `gray`. Commonly used colormaps are: @@ -178,176 +178,213 @@

      Raises

      pyproj_des_proj = pyproj.CRS.from_user_input(cartopy_projection) transformer = pyproj.Transformer.from_crs(pyproj_src_proj, pyproj_des_proj, always_xy=True) - # get sites - site_list = prepped_data.site_uid_list - - # set image intensity scales - if (image_intensity_scales is None): - # defaults to scaling all sites between 0-20000 - image_intensity_scales = {} - for site_uid in prepped_skymap.site_uid_list: - image_intensity_scales[site_uid] = [__DEFAULT_SCALE_MIN, __DEFAULT_SCALE_MAX] - elif (isinstance(image_intensity_scales, list) is True): - image_intensity_scales_dict = {} - for site_uid in site_list: - image_intensity_scales_dict[site_uid] = image_intensity_scales - image_intensity_scales = image_intensity_scales_dict - elif (isinstance(image_intensity_scales, dict) is True): - # no action needed - pass - else: - raise ValueError("Invalid image_intensity_scales format. Please refer to the documentation for this function.") - - # We need a numpy array of the sites requested, that will be used to make sure any sites - # that don't have data for the requested frame are not plotted. Also empty dict for images.. - site_list_arr = np.array(site_list) - # all_images = np.zeros([len(site_list), width * height, __N_CHANNELS], dtype=np.int32) - all_images = {} - - # Grab the elevation, and filling lats/lons - elev = prepped_skymap.elevation - polyfill_lon = prepped_skymap.polyfill_lon - polyfill_lat = prepped_skymap.polyfill_lat - - # Now we begin to fill in the above arrays, one site at a time. Before doing so - # we need lists to keep track of which sites actually have data for this frame. - sites_with_data = [] - sites_with_data_idx = [] - - # We also define a list that will hold all unique timestamps pulled from each - # frame's metadata. This should be of length 1, and we can check that to make - # sure all images being plotted correspond to the same time. - unique_timestamps = [] - n_channels_dict = {} - for site in site_list: + # Convert data, skymaps, colormap indicators to lists for iteration purposed + if not isinstance(prepped_data, list): + prepped_data = [prepped_data] + if not isinstance(prepped_skymap, list): + prepped_skymap = [prepped_skymap] + if not isinstance(colormap, list): + if colormap is None: + colormap = [] + for _ in range(len(prepped_data)): + colormap.append('gray') + else: + colormap = [colormap] + if not isinstance(min_elevation, list): + tmp = [] + for _ in range(len(prepped_data)): + tmp.append(min_elevation) + min_elevation = tmp + + # Make sure all lists are same length + if (len(prepped_data) != len(prepped_skymap)): + raise ValueError("When passing lists of prepped data and prepped skymap, they must be of the same length.") + if (len(prepped_data) != len(colormap)) or (len(prepped_skymap) != len(colormap)): + raise ValueError("List of colormaps must have same length as lists of prepped data and prepped skymaps.") + + # Itarate through each set of prepped data, prepped skymap + img_poly_list = [] + for mosaic_data_idx in range(len(prepped_data)): + data = prepped_data[mosaic_data_idx] + skymap = prepped_skymap[mosaic_data_idx] + iter_cmap = colormap[mosaic_data_idx] + min_el = min_elevation[mosaic_data_idx] + + # get sites + site_list = data.site_uid_list + + # set image intensity scales + if (image_intensity_scales is None): + # defaults to scaling all sites between 0-20000 + image_intensity_scales = {} + for site_uid in skymap.site_uid_list: + image_intensity_scales[site_uid] = [__DEFAULT_SCALE_MIN, __DEFAULT_SCALE_MAX] + elif (isinstance(image_intensity_scales, list) is True): + image_intensity_scales_dict = {} + for site_uid in site_list: + image_intensity_scales_dict[site_uid] = image_intensity_scales + image_intensity_scales = image_intensity_scales_dict + elif (isinstance(image_intensity_scales, dict) is True): + # no action needed + pass + else: + raise ValueError("Invalid image_intensity_scales format. Please refer to the documentation for this function.") + + # We need a numpy array of the sites requested, that will be used to make sure any sites + # that don't have data for the requested frame are not plotted. Also empty dict for images.. + site_list_arr = np.array(site_list) + # all_images = np.zeros([len(site_list), width * height, __N_CHANNELS], dtype=np.int32) + all_images = {} + + # Grab the elevation, and filling lats/lons + elev = skymap.elevation + polyfill_lon = skymap.polyfill_lon + polyfill_lat = skymap.polyfill_lat + + # Now we begin to fill in the above arrays, one site at a time. Before doing so + # we need lists to keep track of which sites actually have data for this frame. + sites_with_data = [] + sites_with_data_idx = [] + + # We also define a list that will hold all unique timestamps pulled from each + # frame's metadata. This should be of length 1, and we can check that to make + # sure all images being plotted correspond to the same time. + unique_timestamps = [] + n_channels_dict = {} + for site in site_list: + + # set image dimensions + height = data.images_dimensions[site][0] + width = data.images_dimensions[site][1] + + # Grab the timestamp for this frame/site + meta_timestamp = data.timestamps[frame_idx] + + # Determine whether current image is single or multi-channel, and add to dictionary for reference + if len(data.images[site].shape) == 4: + n_channels = data.images[site].shape[2] + else: + n_channels = 1 + n_channels_dict[site] = n_channels - # set image dimensions - height = prepped_data.images_dimensions[site][0] - width = prepped_data.images_dimensions[site][1] + # Now, obtain the frame of interest, for this site, from the image data and flatten it + if n_channels == 1: + img = data.images[site][:, :, frame_idx] + flattened_img = np.reshape(img, (width * height)) + else: + img = data.images[site][:, :, :, frame_idx] + flattened_img = np.reshape(img, (width * height, n_channels)) - # Grab the timestamp for this frame/site - meta_timestamp = prepped_data.timestamps[frame_idx] + tmp = flattened_img - # Determine whether current image is single or multi-channel, and add to dictionary for reference - if len(prepped_data.images[site].shape) == 4: - n_channels = prepped_data.images[site].shape[2] - else: - n_channels = 1 - n_channels_dict[site] = n_channels + if (np.sum(tmp) == 0.0): + # If it's sum is zero, we know there is no data so we can simply continue. + continue - # Now, obtain the frame of interest, for this site, from the image data and flatten it - if n_channels == 1: - img = prepped_data.images[site][:, :, frame_idx] - flattened_img = np.reshape(img, (width * height)) - else: - img = prepped_data.images[site][:, :, :, frame_idx] - flattened_img = np.reshape(img, (width * height, n_channels)) + # Scale this site's data based on previously defined scaling bounds + tmp = scale_intensity(tmp, min=image_intensity_scales[site][0], max=image_intensity_scales[site][1], top=255) # type: ignore - tmp = flattened_img + # Add the timestamp to tracking list if it's unique + if meta_timestamp not in unique_timestamps: + unique_timestamps.append(meta_timestamp) - if (np.sum(tmp) == 0.0): - # If it's sum is zero, we know there is no data so we can simply continue. - continue + # Append sites to respective lists, and add image data to master list + sites_with_data.append(site) + sites_with_data_idx.append(np.where(site_list_arr == site)[0][0]) + all_images[site] = tmp.astype(np.int32) - # Scale this site's data based on previously defined scaling bounds - tmp = scale_intensity(tmp, min=image_intensity_scales[site][0], max=image_intensity_scales[site][1], top=255) # type: ignore + # This checks to make sure all images have the same timestamps + if len(unique_timestamps) != 1: + raise Exception("Error: Images have different timestamps.") - # Add the timestamp to tracking list if it's unique - if meta_timestamp not in unique_timestamps: - unique_timestamps.append(meta_timestamp) + # Create empty lists for tracking the pixel polygons and their values + lon_list = [] + lat_list = [] + cmap_vals = [] - # Append sites to respective lists, and add image data to master list - sites_with_data.append(site) - sites_with_data_idx.append(np.where(site_list_arr == site)[0][0]) - all_images[site] = tmp.astype(np.int32) + # Set up elevation increment for plotting. We start at the min elevation + # and plot groups of elevations until reaching 90 deg. + elev_delta = 0.1 + el = min_el - # This checks to make sure all images have the same timestamps - if len(unique_timestamps) != 1: - raise Exception("Error: Images have different timestamps.") + # Iterate through all elevation ranges + while el < 90: - # Create empty lists for tracking the pixel polygons and their values - lon_list = [] - lat_list = [] - cmap_vals = [] + # Only iterate through the sites that actually have data + for site_id, site_idx in zip(sites_with_data, sites_with_data_idx): + # Get this sites number of channels + n_channels = n_channels_dict[site_id] - # Set up elevation increment for plotting. We start at the min elevation - # and plot groups of elevations until reaching 90 deg. - elev_delta = 0.1 - el = min_elevation + # Get all pixels within current elevation threshold + el_idx = np.nonzero(np.logical_and(elev[site_idx] > el, elev[site_idx] <= el + elev_delta))[0] + if len(el_idx) == 0: + continue - # Iterate through all elevation ranges - while el < 90: + # Grab this level's filling lat/lons + el_lvl_fill_lats = polyfill_lat[site_idx][:, el_idx] + el_lvl_fill_lons = polyfill_lon[site_idx][:, el_idx] - # Only iterate through the sites that actually have data - for site_id, site_idx in zip(sites_with_data, sites_with_data_idx): - # Get this sites number of channels - n_channels = n_channels_dict[site_id] + # Grab this level's data values + if n_channels == 1: + el_lvl_cmap_vals = all_images[site_id][el_idx] + else: + el_lvl_cmap_vals = all_images[site_id][el_idx, :] - # Get all pixels within current elevation threshold - el_idx = np.nonzero(np.logical_and(elev[site_idx] > el, elev[site_idx] <= el + elev_delta))[0] - if len(el_idx) == 0: - continue + # # Mask any nans that may have slipped through - done as a precaution + nan_mask = ~np.isnan(el_lvl_fill_lats).any(axis=0) & ~np.isnan(el_lvl_fill_lons).any(axis=0) - # Grab this level's filling lat/lons - el_lvl_fill_lats = polyfill_lat[site_idx][:, el_idx] - el_lvl_fill_lons = polyfill_lon[site_idx][:, el_idx] + el_lvl_fill_lats = el_lvl_fill_lats[:, nan_mask] + el_lvl_fill_lons = el_lvl_fill_lons[:, nan_mask] + if n_channels == 1: + el_lvl_cmap_vals = el_lvl_cmap_vals[nan_mask] + else: + el_lvl_cmap_vals = el_lvl_cmap_vals[nan_mask, :] + + # Convert pixel values to a normalized float + el_lvl_colors = el_lvl_cmap_vals.astype(np.float32) / 255.0 + + # Append polygon lat/lons and values to master lists + if n_channels == 1: + # print(1, len(el_lvl_fill_lats), len(el_lvl_colors)) + cmap = plt.get_cmap(iter_cmap) + for k in range(len(el_lvl_fill_lats[0, :])): + lon_list.append(el_lvl_fill_lons[:, k]) + lat_list.append(el_lvl_fill_lats[:, k]) + cmap_vals.append(cmap(el_lvl_colors[k])) + else: + for k in range(len(el_lvl_fill_lats[0, :])): + lon_list.append(el_lvl_fill_lons[:, k]) + lat_list.append(el_lvl_fill_lats[:, k]) + cmap_vals.append(el_lvl_colors[k, :]) - # Grab this level's data values - if n_channels == 1: - el_lvl_cmap_vals = all_images[site_id][el_idx] - else: - el_lvl_cmap_vals = all_images[site_id][el_idx, :] + el += elev_delta - # # Mask any nans that may have slipped through - done as a precaution - nan_mask = ~np.isnan(el_lvl_fill_lats).any(axis=0) & ~np.isnan(el_lvl_fill_lons).any(axis=0) + # Use our transformer object to convert the lat/lon polygons into projection coordinates. + lons, lats = transformer.transform(np.array(lon_list), np.array(lat_list)) - el_lvl_fill_lats = el_lvl_fill_lats[:, nan_mask] - el_lvl_fill_lons = el_lvl_fill_lons[:, nan_mask] - if n_channels == 1: - el_lvl_cmap_vals = el_lvl_cmap_vals[nan_mask] - else: - el_lvl_cmap_vals = el_lvl_cmap_vals[nan_mask, :] + # Format polygons for creation of PolyCollection object + lonlat_polygons = np.empty((lons.shape[0], 5, 2)) + lonlat_polygons[:, :, 0] = lons + lonlat_polygons[:, :, 1] = lats - # Convert pixel values to a normalized float - el_lvl_colors = el_lvl_cmap_vals.astype(np.float32) / 255.0 + # generate a PolyCollection object, containing all of the Polygons shaded with + # their corresponding RGB value - # Append polygon lat/lons and values to master lists - if n_channels == 1: - # print(1, len(el_lvl_fill_lats), len(el_lvl_colors)) - cmap = plt.get_cmap(colormap) - for k in range(len(el_lvl_fill_lats[0, :])): - lon_list.append(el_lvl_fill_lons[:, k]) - lat_list.append(el_lvl_fill_lats[:, k]) - cmap_vals.append(cmap(el_lvl_colors[k])) - else: - for k in range(len(el_lvl_fill_lats[0, :])): - lon_list.append(el_lvl_fill_lons[:, k]) - lat_list.append(el_lvl_fill_lats[:, k]) - cmap_vals.append(el_lvl_colors[k, :]) - - el += elev_delta - - # Use our transformer object to convert the lat/lon polygons into projection coordinates. - lons, lats = transformer.transform(np.array(lon_list), np.array(lat_list)) - - # Format polygons for creation of PolyCollection object - lonlat_polygons = np.empty((lons.shape[0], 5, 2)) - lonlat_polygons[:, :, 0] = lons - lonlat_polygons[:, :, 1] = lats - - # generate a PolyCollection object, containing all of the Polygons shaded with - # their corresponding RGB value - - img_data_poly = matplotlib.collections.PolyCollection( - lonlat_polygons, # type: ignore - facecolors=cmap_vals, - array=None, - clim=[0.0, 1.0], - edgecolors="face", - ) + img_data_poly = matplotlib.collections.PolyCollection( + lonlat_polygons, # type: ignore + facecolors=cmap_vals, + array=None, + clim=[0.0, 1.0], + edgecolors="face", + ) + + img_poly_list.append(img_data_poly) # cast into mosaic object - mosaic = Mosaic(polygon_data=img_data_poly, cartopy_projection=cartopy_projection) + if len(img_poly_list) == 1: + mosaic = Mosaic(polygon_data=img_poly_list[0], cartopy_projection=cartopy_projection) + else: + mosaic = Mosaic(polygon_data=img_poly_list, cartopy_projection=cartopy_projection) # return return mosaic
      @@ -482,9 +519,11 @@

      Raises

      # We don't attempt to handle the same site being passed in for multiple networks if site_uid in images_dict.keys(): - print("Warning: Same site between differing networks detected. Omitting " + site_uid) + warnings.warn( + "Same site between differing networks detected. Omitting additional '%s' data" % (site_uid), + stacklevel=1, + ) continue - site_uid_list.append(site_uid) # initialize this site's data destination variables diff --git a/pyaurorax b/pyaurorax index 82600ad..1eb04fc 160000 --- a/pyaurorax +++ b/pyaurorax @@ -1 +1 @@ -Subproject commit 82600ad12a2a34828b0c34b6ae92634c111b8caa +Subproject commit 1eb04fc860ea42e067b8fee4e045f4a0a22ce20f