def _check_args_one_step(predictor_matrix, permuted_flag_matrix, scalar_channel_flags, shuffle_profiles_together, num_bootstrap_reps): """Checks input args for `run_*_test_one_step`. :param predictor_matrix: See doc for `run_forward_test_one_step` or `run_backwards_test_one_step`. :param permuted_flag_matrix: Same. :param scalar_channel_flags: Same. :param shuffle_profiles_together: Same. :param num_bootstrap_reps: Same. :return: num_bootstrap_reps: Same as input but maxxed with 1. """ error_checking.assert_is_numpy_array_without_nan(predictor_matrix) num_predictor_dim = len(predictor_matrix.shape) error_checking.assert_is_geq(num_predictor_dim, 3) error_checking.assert_is_leq(num_predictor_dim, 3) error_checking.assert_is_boolean_numpy_array(permuted_flag_matrix) these_expected_dim = numpy.array(predictor_matrix.shape[1:], dtype=int) error_checking.assert_is_numpy_array(permuted_flag_matrix, exact_dimensions=these_expected_dim) error_checking.assert_is_boolean_numpy_array(scalar_channel_flags) these_expected_dim = numpy.array([predictor_matrix.shape[-1]], dtype=int) error_checking.assert_is_numpy_array(scalar_channel_flags, exact_dimensions=these_expected_dim) error_checking.assert_is_boolean(shuffle_profiles_together) error_checking.assert_is_integer(num_bootstrap_reps) return numpy.maximum(num_bootstrap_reps, 1)
def plot_2d_grid_without_coords(significance_matrix, axes_object, marker_type=DEFAULT_MARKER_TYPE, marker_size=DEFAULT_MARKER_SIZE, marker_colour=DEFAULT_MARKER_COLOUR, marker_edge_width=DEFAULT_MARKER_EDGE_WIDTH): """Plots 2-D significance grid with markers. M = number of rows in grid N = number of columns in grid :param significance_matrix: M-by-N numpy array of Boolean flags, indicating where some value is significant. :param axes_object: Will plot on these axes (instance of `matplotlib.axes._subplots.AxesSubplot`). :param marker_type: Marker type (in any format accepted by matplotlib). :param marker_size: Marker size. :param marker_colour: Marker colour as length-3 numpy array. :param marker_edge_width: Marker-edge width. """ error_checking.assert_is_boolean_numpy_array(significance_matrix) error_checking.assert_is_numpy_array(significance_matrix, num_dimensions=2) error_checking.assert_is_numpy_array(marker_colour) sig_rows, sig_columns = numpy.where(significance_matrix) axes_object.plot(sig_columns + 0.5, sig_rows + 0.5, linestyle='None', marker=marker_type, markerfacecolor=marker_colour, markeredgecolor=marker_colour, markersize=marker_size, markeredgewidth=marker_edge_width)
def get_region_properties(binary_image_matrix, property_names=DEFAULT_REGION_PROP_NAMES): """Computes region properties for one shape (polygon). M = number of rows in grid N = number of columns in grid :param binary_image_matrix: M-by-N Boolean numpy array. If binary_image_matrix[i, j] = True, grid point [i, j] is inside the polygon. Otherwise, grid point [i, j] is outside the polygon. :param property_names: 1-D list of region properties to compute. :return: property_dict: Dictionary, where each key is a string from `property_names` and each item is the corresponding value. """ error_checking.assert_is_boolean_numpy_array(binary_image_matrix) error_checking.assert_is_numpy_array(binary_image_matrix, num_dimensions=2) error_checking.assert_is_string_list(property_names) error_checking.assert_is_numpy_array( numpy.array(property_names), num_dimensions=1) regionprops_object = skimage.measure.regionprops( binary_image_matrix.astype(int))[0] property_dict = {} for this_name in property_names: if this_name == ORIENTATION_NAME: property_dict.update({this_name: RADIANS_TO_DEGREES * getattr( regionprops_object, _stat_name_new_to_orig(this_name))}) else: property_dict.update({this_name: getattr( regionprops_object, _stat_name_new_to_orig(this_name))}) return property_dict
def _check_region_dict(list_of_cam_matrices, region_dict, pmm_flag): """Error-checks dictionary with regions of interest. :param list_of_cam_matrices: See doc for `_check_in_and_out_matrices`. :param region_dict: Dictionary with the following keys. region_dict['list_of_mask_matrices']: Same as `list_of_cam_matrices`, except that all numpy arrays. Grid cells marked True are in a region of interest. region_dict['list_of_polygon_objects']: Triple-nested list of polygons (instances of `shapely.geometry.Polygon`), demarcating regions of interest. list_of_polygon_objects[i][j][k] is the [k]th region of interest for the [j]th input matrix for the [i]th example. region_dict['percentile_threshold']: Percentile threshold used to create regions of interest. This is applied separately to each class-activation matrix for each example. region_dict['min_class_activation']: Minimum class activation used to create regions of interest. For a grid cell to be in a region of interest, it must meet both this and the percentile threshold. :param pmm_flag: Boolean flag. If True, inputs should contain PMM (probability-matched mean) composites. """ error_checking.assert_is_geq(region_dict[PERCENTILE_THRESHOLD_KEY], 50.) error_checking.assert_is_less_than( region_dict[PERCENTILE_THRESHOLD_KEY], 100. ) error_checking.assert_is_greater(region_dict[MIN_CLASS_ACTIVATION_KEY], 0.) list_of_mask_matrices = region_dict[MASK_MATRICES_KEY] list_of_polygon_objects = region_dict[POLYGON_OBJECTS_KEY] num_input_matrices = len(list_of_cam_matrices) assert len(list_of_mask_matrices) == num_input_matrices assert len(list_of_polygon_objects) == num_input_matrices for j in range(num_input_matrices): if list_of_cam_matrices[j] is None: assert list_of_mask_matrices[j] is None continue error_checking.assert_is_boolean_numpy_array(list_of_mask_matrices[j]) these_expected_dim = numpy.array( list_of_cam_matrices[j].shape, dtype=int ) error_checking.assert_is_numpy_array( list_of_mask_matrices[j], exact_dimensions=these_expected_dim ) if pmm_flag: num_examples = 1 else: num_examples = list_of_cam_matrices[j].shape[0] assert len(list_of_polygon_objects[j]) == num_examples for i in range(num_examples): error_checking.assert_is_list(list_of_polygon_objects[j][i])
def plot_many_2d_grids_without_coords( significance_matrix, axes_object_matrix, marker_type=DEFAULT_MARKER_TYPE, marker_size=DEFAULT_MARKER_SIZE, marker_colour=DEFAULT_MARKER_COLOUR, marker_edge_width=DEFAULT_MARKER_EDGE_WIDTH, row_major=True): """Plots many 2-D significance grid with markers. M = number of rows in grid N = number of columns in grid C = number of grids :param significance_matrix: M-by-N-by-C numpy array of Boolean flags, indicating where some value is significant. :param axes_object_matrix: See doc for `plotting_utils.create_paneled_figure`. :param marker_type: Marker type (in any format accepted by matplotlib). :param marker_size: Marker size. :param marker_colour: Marker colour as length-3 numpy array. :param marker_edge_width: Marker-edge width. :param row_major: Boolean flag. If True, panels will be filled along rows first, then down columns. If False, down columns first, then along rows. """ error_checking.assert_is_boolean_numpy_array(significance_matrix) error_checking.assert_is_numpy_array(significance_matrix, num_dimensions=3) error_checking.assert_is_numpy_array(marker_colour) error_checking.assert_is_boolean(row_major) if row_major: order_string = 'C' else: order_string = 'F' num_grids = significance_matrix.shape[-1] num_panel_rows = axes_object_matrix.shape[0] num_panel_columns = axes_object_matrix.shape[1] for k in range(num_grids): this_panel_row, this_panel_column = numpy.unravel_index( k, (num_panel_rows, num_panel_columns), order=order_string) plot_2d_grid_without_coords( significance_matrix=significance_matrix[..., k], axes_object=axes_object_matrix[this_panel_row, this_panel_column], marker_type=marker_type, marker_size=marker_size, marker_colour=marker_colour, marker_edge_width=marker_edge_width)
def plot_many_2d_grids(data_matrix, field_names, axes_objects, panel_names=None, plot_grid_lines=True, colour_map_objects=None, colour_norm_objects=None, refl_opacity=DEFAULT_OPACITY, plot_colour_bar_flags=None, panel_name_font_size=DEFAULT_FONT_SIZE, colour_bar_font_size=DEFAULT_FONT_SIZE, colour_bar_length=DEFAULT_COLOUR_BAR_LENGTH): """Plots many 2-D grids in paneled figure. M = number of rows in grid N = number of columns in grid C = number of fields :param data_matrix: M-by-N-by-C numpy array of radar values. :param field_names: length-C list of field names. :param axes_objects: length-C list of axes handles (instances of `matplotlib.axes._subplots.AxesSubplot`). :param panel_names: length-C list of panel names (to be printed at bottom of each panel). If None, panel names will not be printed. :param plot_grid_lines: Boolean flag. If True, will plot grid lines over radar images. :param colour_map_objects: length-C list of colour schemes (instances of `matplotlib.pyplot.cm` or similar). If None, will use default colour scheme for each field. :param colour_norm_objects: length-C list of colour-normalizers (instances of `matplotlib.colors.BoundaryNorm` or similar). If None, will use default normalizer for each field. :param refl_opacity: Opacity for reflectivity colour scheme. Used only if `colour_map_objects is None and colour_norm_objects is None`. :param plot_colour_bar_flags: length-C numpy array of Boolean flags. If `plot_colour_bar_flags[k] == True`, will plot colour bar for [k]th panel. If None, will plot no colour bars. :param panel_name_font_size: Font size for panel names. :param colour_bar_font_size: Font size for colour-bar tick marks. :param colour_bar_length: Length of colour bars (as fraction of axis length). :return: colour_bar_objects: length-C list of colour bars. If `plot_colour_bar_flags[k] == False`, colour_bar_objects[k] will be None. """ error_checking.assert_is_numpy_array(data_matrix, num_dimensions=3) num_fields = data_matrix.shape[-1] these_expected_dim = numpy.array([num_fields], dtype=int) error_checking.assert_is_string_list(field_names) error_checking.assert_is_numpy_array(numpy.array(field_names), exact_dimensions=these_expected_dim) error_checking.assert_is_numpy_array(numpy.array(axes_objects), exact_dimensions=these_expected_dim) if panel_names is None: panel_names = [None] * num_fields else: error_checking.assert_is_string_list(panel_names) error_checking.assert_is_numpy_array( numpy.array(panel_names), exact_dimensions=these_expected_dim) if colour_map_objects is None or colour_norm_objects is None: colour_map_objects = [None] * num_fields colour_norm_objects = [None] * num_fields else: error_checking.assert_is_numpy_array( numpy.array(colour_map_objects), exact_dimensions=these_expected_dim) error_checking.assert_is_numpy_array( numpy.array(colour_norm_objects), exact_dimensions=these_expected_dim) if plot_colour_bar_flags is None: plot_colour_bar_flags = numpy.full(num_fields, 0, dtype=bool) error_checking.assert_is_boolean_numpy_array(plot_colour_bar_flags) error_checking.assert_is_numpy_array(plot_colour_bar_flags, exact_dimensions=these_expected_dim) colour_bar_objects = [None] * num_fields for k in range(num_fields): this_colour_map_object, this_colour_norm_object = ( plot_2d_grid_without_coords( field_matrix=data_matrix[..., k], field_name=field_names[k], axes_object=axes_objects[k], annotation_string=panel_names[k], font_size=panel_name_font_size, plot_grid_lines=plot_grid_lines, colour_map_object=copy.deepcopy(colour_map_objects[k]), colour_norm_object=copy.deepcopy(colour_norm_objects[k]), refl_opacity=refl_opacity)) if not plot_colour_bar_flags[k]: continue colour_bar_objects[k] = plotting_utils.plot_colour_bar( axes_object_or_matrix=axes_objects[k], data_matrix=data_matrix[..., k], colour_map_object=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation_string='horizontal', font_size=colour_bar_font_size, fraction_of_axis_length=colour_bar_length, extend_min=field_names[k] in SHEAR_VORT_DIV_NAMES, extend_max=True) return colour_bar_objects
def write_classifications(convective_flag_matrix, grid_metadata_dict, valid_time_unix_sec, option_dict, netcdf_file_name): """Writes echo classifications to NetCDF file. :param convective_flag_matrix: M-by-N numpy array of Boolean flags (True if convective, False if not). :param grid_metadata_dict: See doc for `find_convective_pixels`. :param valid_time_unix_sec: Same. :param option_dict: Same. :param netcdf_file_name: Path to output file. """ # Error-checking. error_checking.assert_is_boolean_numpy_array(convective_flag_matrix) error_checking.assert_is_numpy_array(convective_flag_matrix, num_dimensions=2) error_checking.assert_is_integer(valid_time_unix_sec) option_dict = _check_input_args(option_dict) peakedness_neigh_metres = option_dict[PEAKEDNESS_NEIGH_KEY] max_peakedness_height_m_asl = option_dict[MAX_PEAKEDNESS_HEIGHT_KEY] min_height_fraction_for_peakedness = option_dict[MIN_HEIGHT_FRACTION_KEY] halve_resolution_for_peakedness = option_dict[HALVE_RESOLUTION_KEY] min_echo_top_m_asl = option_dict[MIN_ECHO_TOP_KEY] echo_top_level_dbz = option_dict[ECHO_TOP_LEVEL_KEY] min_size_pixels = option_dict[MIN_SIZE_KEY] min_composite_refl_criterion1_dbz = ( option_dict[MIN_COMPOSITE_REFL_CRITERION1_KEY]) min_composite_refl_criterion5_dbz = ( option_dict[MIN_COMPOSITE_REFL_CRITERION5_KEY]) min_composite_refl_aml_dbz = option_dict[MIN_COMPOSITE_REFL_AML_KEY] if min_composite_refl_criterion1_dbz is None: min_composite_refl_criterion1_dbz = -1. file_system_utils.mkdir_recursive_if_necessary(file_name=netcdf_file_name) netcdf_dataset = netCDF4.Dataset(netcdf_file_name, 'w', format='NETCDF3_64BIT_OFFSET') netcdf_dataset.setncattr(PEAKEDNESS_NEIGH_KEY, peakedness_neigh_metres) netcdf_dataset.setncattr(MAX_PEAKEDNESS_HEIGHT_KEY, max_peakedness_height_m_asl) netcdf_dataset.setncattr(MIN_HEIGHT_FRACTION_KEY, min_height_fraction_for_peakedness) netcdf_dataset.setncattr(HALVE_RESOLUTION_KEY, int(halve_resolution_for_peakedness)) netcdf_dataset.setncattr(MIN_ECHO_TOP_KEY, min_echo_top_m_asl) netcdf_dataset.setncattr(ECHO_TOP_LEVEL_KEY, echo_top_level_dbz) netcdf_dataset.setncattr(MIN_SIZE_KEY, min_size_pixels) netcdf_dataset.setncattr(MIN_COMPOSITE_REFL_CRITERION1_KEY, min_composite_refl_criterion1_dbz) netcdf_dataset.setncattr(MIN_COMPOSITE_REFL_CRITERION5_KEY, min_composite_refl_criterion5_dbz) netcdf_dataset.setncattr(MIN_COMPOSITE_REFL_AML_KEY, min_composite_refl_aml_dbz) netcdf_dataset.setncattr(VALID_TIME_KEY, valid_time_unix_sec) netcdf_dataset.createDimension(ROW_DIMENSION_KEY, convective_flag_matrix.shape[0]) netcdf_dataset.createDimension(COLUMN_DIMENSION_KEY, convective_flag_matrix.shape[1]) grid_point_latitudes_deg, grid_point_longitudes_deg = ( grids.get_latlng_grid_points( min_latitude_deg=grid_metadata_dict[MIN_LATITUDE_KEY], min_longitude_deg=grid_metadata_dict[MIN_LONGITUDE_KEY], lat_spacing_deg=grid_metadata_dict[LATITUDE_SPACING_KEY], lng_spacing_deg=grid_metadata_dict[LONGITUDE_SPACING_KEY], num_rows=convective_flag_matrix.shape[0], num_columns=convective_flag_matrix.shape[1])) netcdf_dataset.createVariable(LATITUDES_KEY, datatype=numpy.float32, dimensions=ROW_DIMENSION_KEY) netcdf_dataset.variables[LATITUDES_KEY][:] = grid_point_latitudes_deg netcdf_dataset.createVariable(LONGITUDES_KEY, datatype=numpy.float32, dimensions=COLUMN_DIMENSION_KEY) netcdf_dataset.variables[LONGITUDES_KEY][:] = grid_point_longitudes_deg netcdf_dataset.createVariable(FLAG_MATRIX_KEY, datatype=numpy.int32, dimensions=(ROW_DIMENSION_KEY, COLUMN_DIMENSION_KEY)) netcdf_dataset.variables[FLAG_MATRIX_KEY][:] = convective_flag_matrix netcdf_dataset.close()
def plot_many_2d_grids_without_coords(field_matrix, field_name_by_panel, num_panel_rows=None, figure_object=None, axes_object_matrix=None, panel_names=None, colour_map_object_by_panel=None, colour_norm_object_by_panel=None, plot_colour_bar_by_panel=None, font_size=DEFAULT_FONT_SIZE, row_major=True): """Plots 2-D colour map in each panel (one per field/height pair). M = number of rows in spatial grid N = number of columns in spatial grid P = number of panels (field/height pairs) This method uses the default colour scheme for each radar field. If `num_panel_rows is None`, this method needs arguments `figure_object` and `axes_object_matrix` -- and vice-versa. :param field_matrix: M-by-N-by-P numpy array of radar values. :param field_name_by_panel: length-P list of field names. :param num_panel_rows: Number of rows in paneled figure (different than M, which is number of rows in spatial grid). :param figure_object: See doc for `plotting_utils.create_paneled_figure`. :param axes_object_matrix: See above. :param panel_names: length-P list of panel names (will be printed at bottoms of panels). If you do not want panel names, make this None. :param colour_map_object_by_panel: length-P list of `matplotlib.pyplot.cm` objects. If this is None, the default will be used for each field. :param colour_norm_object_by_panel: length-P list of `matplotlib.colors.BoundaryNorm` objects. If this is None, the default will be used for each field. :param plot_colour_bar_by_panel: length-P numpy array of Boolean flags. If plot_colour_bar_by_panel[k] = True, horizontal colour bar will be plotted under [k]th panel. If you want to plot colour bar for every panel, leave this as None. :param font_size: Font size. :param row_major: Boolean flag. If True, panels will be filled along rows first, then down columns. If False, down columns first, then along rows. :return: figure_object: See doc for `plotting_utils.create_paneled_figure`. :return: axes_object_matrix: Same. :raises: ValueError: if `colour_map_object_by_panel` or `colour_norm_object_by_panel` has different length than number of panels. """ error_checking.assert_is_boolean(row_major) error_checking.assert_is_numpy_array(field_matrix, num_dimensions=3) num_panels = field_matrix.shape[2] if panel_names is None: panel_names = [None] * num_panels if plot_colour_bar_by_panel is None: plot_colour_bar_by_panel = numpy.full(num_panels, True, dtype=bool) these_expected_dim = numpy.array([num_panels], dtype=int) error_checking.assert_is_numpy_array(numpy.array(panel_names), exact_dimensions=these_expected_dim) error_checking.assert_is_numpy_array(numpy.array(field_name_by_panel), exact_dimensions=these_expected_dim) error_checking.assert_is_boolean_numpy_array(plot_colour_bar_by_panel) error_checking.assert_is_numpy_array(plot_colour_bar_by_panel, exact_dimensions=these_expected_dim) if (colour_map_object_by_panel is None or colour_norm_object_by_panel is None): colour_map_object_by_panel = [None] * num_panels colour_norm_object_by_panel = [None] * num_panels error_checking.assert_is_list(colour_map_object_by_panel) error_checking.assert_is_list(colour_norm_object_by_panel) if len(colour_map_object_by_panel) != num_panels: error_string = ( 'Number of colour maps ({0:d}) should equal number of panels ' '({1:d}).').format(len(colour_map_object_by_panel), num_panels) raise ValueError(error_string) if len(colour_norm_object_by_panel) != num_panels: error_string = ( 'Number of colour-normalizers ({0:d}) should equal number of panels' ' ({1:d}).').format(len(colour_norm_object_by_panel), num_panels) raise ValueError(error_string) if figure_object is None: error_checking.assert_is_integer(num_panel_rows) error_checking.assert_is_geq(num_panel_rows, 1) error_checking.assert_is_leq(num_panel_rows, num_panels) num_panel_columns = int(numpy.ceil(float(num_panels) / num_panel_rows)) figure_object, axes_object_matrix = ( plotting_utils.create_paneled_figure(num_rows=num_panel_rows, num_columns=num_panel_columns, shared_x_axis=False, shared_y_axis=False, keep_aspect_ratio=True)) else: error_checking.assert_is_numpy_array(axes_object_matrix, num_dimensions=2) num_panel_rows = axes_object_matrix.shape[0] num_panel_columns = axes_object_matrix.shape[1] if row_major: order_string = 'C' else: order_string = 'F' for k in range(num_panels): this_panel_row, this_panel_column = numpy.unravel_index( k, (num_panel_rows, num_panel_columns), order=order_string) # this_colour_map_object, this_colour_norm_object = ( # plot_2d_grid_without_coords( # field_matrix=field_matrix[..., k], # field_name=field_name_by_panel[k], # axes_object=axes_object_matrix[ # this_panel_row, this_panel_column], # annotation_string=panel_names[k], font_size=font_size, # colour_map_object=colour_map_object_by_panel[k], # colour_norm_object=colour_norm_object_by_panel[k] # ) # ) this_colour_map_object, this_colour_norm_object = ( plot_2d_grid_without_coords( field_matrix=field_matrix[..., k], field_name=field_name_by_panel[k], axes_object=axes_object_matrix[this_panel_row, this_panel_column], annotation_string=None, font_size=font_size, colour_map_object=colour_map_object_by_panel[k], colour_norm_object=colour_norm_object_by_panel[k])) if not plot_colour_bar_by_panel[k]: continue this_extend_min_flag = field_name_by_panel[k] in SHEAR_VORT_DIV_NAMES this_colour_bar_object = plotting_utils.plot_colour_bar( axes_object_or_matrix=axes_object_matrix[this_panel_row, this_panel_column], data_matrix=field_matrix[..., k], colour_map_object=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation_string='horizontal', extend_min=this_extend_min_flag, extend_max=True, fraction_of_axis_length=0.75, font_size=font_size) this_colour_bar_object.set_label(panel_names[k].replace('\n', '; '), fontsize=font_size, fontweight='bold') for k in range(num_panel_rows * num_panel_columns): if k < num_panels: continue this_panel_row, this_panel_column = numpy.unravel_index( k, (num_panel_rows, num_panel_columns), order=order_string) axes_object_matrix[this_panel_row, this_panel_column].axis('off') return figure_object, axes_object_matrix
def test_assert_is_boolean_numpy_array_true(self): """Checks assert_is_boolean_numpy_array when condition is true.""" error_checking.assert_is_boolean_numpy_array(BOOLEAN_NUMPY_ARRAY)
def plot_many_2d_grids_without_coords( field_matrix, field_name_by_panel, num_panel_rows, panel_names=None, colour_map_object_by_panel=None, colour_norm_object_by_panel=None, plot_colour_bar_by_panel=None, figure_width_inches=DEFAULT_FIGURE_WIDTH_INCHES, figure_height_inches=DEFAULT_FIGURE_HEIGHT_INCHES, font_size=DEFAULT_FONT_SIZE, row_major=True): """Plots 2-D colour map in each panel (one per field/height pair). M = number of rows in spatial grid N = number of columns in spatial grid P = number of panels (field/height pairs) This method uses the default colour scheme for each radar field. :param field_matrix: M-by-N-by-P numpy array of radar values. :param field_name_by_panel: length-P list of field names. :param num_panel_rows: Number of rows in paneled figure (different than M, which is number of rows in spatial grid). :param panel_names: length-P list of panel names (will be printed at bottoms of panels). If you do not want panel names, make this None. :param colour_map_object_by_panel: length-P list of `matplotlib.pyplot.cm` objects. If this is None, the default will be used for each field. :param colour_norm_object_by_panel: length-P list of `matplotlib.colors.BoundaryNorm` objects. If this is None, the default will be used for each field. :param plot_colour_bar_by_panel: length-P numpy array of Boolean flags. If plot_colour_bar_by_panel[k] = True, horizontal colour bar will be plotted under [k]th panel. If you want to plot colour bar for every panel, leave this as None. :param figure_width_inches: Figure width. :param figure_height_inches: Figure height. :param font_size: Font size. :param row_major: Boolean flag. If True, panels will be filled along rows first, then down columns. If False, down columns first, then along rows. :return: figure_object: Instance of `matplotlib.figure.Figure`. :return: axes_objects_2d_list: 2-D list, where each item is an instance of `matplotlib.axes._subplots.AxesSubplot`. :raises: ValueError: if `colour_map_object_by_panel` or `colour_norm_object_by_panel` has different length than number of panels. """ error_checking.assert_is_numpy_array(field_matrix, num_dimensions=3) error_checking.assert_is_boolean(row_major) if row_major: order_string = 'C' else: order_string = 'F' num_panels = field_matrix.shape[2] if panel_names is None: panel_names = [None] * num_panels if plot_colour_bar_by_panel is None: plot_colour_bar_by_panel = numpy.full(num_panels, True, dtype=bool) these_expected_dim = numpy.array([num_panels], dtype=int) error_checking.assert_is_numpy_array( numpy.array(panel_names), exact_dimensions=these_expected_dim) error_checking.assert_is_numpy_array( numpy.array(field_name_by_panel), exact_dimensions=these_expected_dim) error_checking.assert_is_boolean_numpy_array(plot_colour_bar_by_panel) error_checking.assert_is_numpy_array( plot_colour_bar_by_panel, exact_dimensions=these_expected_dim) if (colour_map_object_by_panel is None or colour_norm_object_by_panel is None): colour_map_object_by_panel = [None] * num_panels colour_norm_object_by_panel = [None] * num_panels error_checking.assert_is_list(colour_map_object_by_panel) error_checking.assert_is_list(colour_norm_object_by_panel) if len(colour_map_object_by_panel) != num_panels: error_string = ( 'Number of colour maps ({0:d}) should equal number of panels ' '({1:d}).' ).format(len(colour_map_object_by_panel), num_panels) raise ValueError(error_string) if len(colour_norm_object_by_panel) != num_panels: error_string = ( 'Number of colour-normalizers ({0:d}) should equal number of panels' ' ({1:d}).' ).format(len(colour_norm_object_by_panel), num_panels) raise ValueError(error_string) error_checking.assert_is_integer(num_panel_rows) error_checking.assert_is_geq(num_panel_rows, 1) error_checking.assert_is_leq(num_panel_rows, num_panels) num_panel_columns = int(numpy.ceil( float(num_panels) / num_panel_rows )) figure_object, axes_objects_2d_list = plotting_utils.init_panels( num_panel_rows=num_panel_rows, num_panel_columns=num_panel_columns, figure_width_inches=figure_width_inches, figure_height_inches=figure_height_inches) for k in range(num_panels): this_panel_row, this_panel_column = numpy.unravel_index( k, (num_panel_rows, num_panel_columns), order=order_string ) if plot_colour_bar_by_panel[k]: this_annotation_string = None else: this_annotation_string = panel_names[k] this_colour_map_object, this_colour_norm_object = ( plot_2d_grid_without_coords( field_matrix=field_matrix[..., k], field_name=field_name_by_panel[k], axes_object=axes_objects_2d_list[ this_panel_row][this_panel_column], annotation_string=this_annotation_string, font_size=font_size, colour_map_object=colour_map_object_by_panel[k], colour_norm_object=colour_norm_object_by_panel[k] ) ) if not plot_colour_bar_by_panel[k]: continue this_extend_min_flag = field_name_by_panel[k] in SHEAR_VORT_DIV_NAMES plotting_utils.add_colour_bar( axes_object_or_list=axes_objects_2d_list[ this_panel_row][this_panel_column], values_to_colour=field_matrix[..., k], colour_map=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation='horizontal', font_size=font_size, extend_min=this_extend_min_flag, extend_max=True, fraction_of_axis_length=0.9) axes_objects_2d_list[this_panel_row][this_panel_column].set_xlabel( panel_names[k], fontsize=font_size) for k in range(num_panel_rows * num_panel_columns): if k < num_panels: continue this_panel_row, this_panel_column = numpy.unravel_index( k, (num_panel_rows, num_panel_columns), order=order_string ) axes_objects_2d_list[this_panel_row][this_panel_column].axis('off') return figure_object, axes_objects_2d_list
def write_polygons(output_file_name, positive_objects_grid_coords, positive_panel_row_by_polygon, positive_panel_column_by_polygon, positive_mask_matrix, negative_objects_grid_coords=None, negative_panel_row_by_polygon=None, negative_panel_column_by_polygon=None, negative_mask_matrix=None, full_storm_id_string=None, storm_time_unix_sec=None): """Writes human polygons for one image to NetCDF file. P = number of positive regions of interest N = number of negative regions of interest :param output_file_name: Path to output (NetCDF) file. :param positive_objects_grid_coords: length-P list of polygons created by `polygons_from_pixel_to_grid_coords`, containing positive regions of interest. :param positive_panel_row_by_polygon: length-P numpy array of corresponding panel rows (non-negative integers). :param positive_panel_column_by_polygon: length-P numpy array of corresponding panel columns (non-negative integers). :param positive_mask_matrix: Binary mask for positive regions of interest, created by `polygons_to_mask`. :param negative_objects_grid_coords: length-N list of polygons created by `polygons_from_pixel_to_grid_coords`, containing negative regions of interest. :param negative_panel_row_by_polygon: length-N numpy array of corresponding panel rows (non-negative integers). :param negative_panel_column_by_polygon: length-N numpy array of corresponding panel columns (non-negative integers). :param negative_mask_matrix: Binary mask for negative regions of interest, created by `polygons_to_mask`. :param full_storm_id_string: Full storm ID (if polygons were drawn for composite, this should be None). :param storm_time_unix_sec: Valid time (if polygons were drawn for composite, this should be None). """ is_composite = (full_storm_id_string is None and storm_time_unix_sec is None) if is_composite: full_storm_id_string = DUMMY_STORM_ID_STRING storm_time_unix_sec = -1 error_checking.assert_is_string(full_storm_id_string) error_checking.assert_is_integer(storm_time_unix_sec) error_checking.assert_is_boolean_numpy_array(positive_mask_matrix) error_checking.assert_is_numpy_array(positive_mask_matrix, num_dimensions=4) _check_polygons(polygon_objects_grid_coords=positive_objects_grid_coords, num_panel_rows=positive_mask_matrix.shape[0], num_panel_columns=positive_mask_matrix.shape[1], panel_row_by_polygon=positive_panel_row_by_polygon, panel_column_by_polygon=positive_panel_column_by_polygon) if negative_objects_grid_coords is None: negative_objects_grid_coords = [] negative_panel_row_by_polygon = numpy.array([], dtype=int) negative_panel_column_by_polygon = numpy.array([], dtype=int) negative_mask_matrix = numpy.full(positive_mask_matrix.shape, False, dtype=bool) error_checking.assert_is_boolean_numpy_array(negative_mask_matrix) error_checking.assert_is_numpy_array(negative_mask_matrix, exact_dimensions=numpy.array( positive_mask_matrix.shape, dtype=int)) _check_polygons(polygon_objects_grid_coords=negative_objects_grid_coords, num_panel_rows=negative_mask_matrix.shape[0], num_panel_columns=negative_mask_matrix.shape[1], panel_row_by_polygon=negative_panel_row_by_polygon, panel_column_by_polygon=negative_panel_column_by_polygon) (positive_vertex_rows, positive_vertex_columns, these_vertex_to_poly_indices ) = _polygon_list_to_vertex_list(positive_objects_grid_coords) positive_panel_row_by_vertex = numpy.array([ positive_panel_row_by_polygon[k] if k >= 0 else numpy.nan for k in these_vertex_to_poly_indices ]) positive_panel_column_by_vertex = numpy.array([ positive_panel_column_by_polygon[k] if k >= 0 else numpy.nan for k in these_vertex_to_poly_indices ]) if len(positive_vertex_rows) == 0: positive_vertex_rows = numpy.full(1, SENTINEL_VALUE - 1) positive_vertex_columns = numpy.full(1, SENTINEL_VALUE - 1) positive_panel_row_by_vertex = numpy.full(1, -1, dtype=int) positive_panel_column_by_vertex = numpy.full(1, -1, dtype=int) (negative_vertex_rows, negative_vertex_columns, these_vertex_to_poly_indices ) = _polygon_list_to_vertex_list(negative_objects_grid_coords) negative_panel_row_by_vertex = numpy.array([ negative_panel_row_by_polygon[k] if k >= 0 else numpy.nan for k in these_vertex_to_poly_indices ]) negative_panel_column_by_vertex = numpy.array([ negative_panel_column_by_polygon[k] if k >= 0 else numpy.nan for k in these_vertex_to_poly_indices ]) file_system_utils.mkdir_recursive_if_necessary(file_name=output_file_name) dataset_object = netCDF4.Dataset(output_file_name, 'w', format='NETCDF3_64BIT_OFFSET') dataset_object.setncattr(STORM_ID_KEY, full_storm_id_string) dataset_object.setncattr(STORM_TIME_KEY, storm_time_unix_sec) dataset_object.createDimension(PANEL_ROW_DIMENSION_KEY, positive_mask_matrix.shape[0]) dataset_object.createDimension(PANEL_COLUMN_DIMENSION_KEY, positive_mask_matrix.shape[1]) dataset_object.createDimension(GRID_ROW_DIMENSION_KEY, positive_mask_matrix.shape[2]) dataset_object.createDimension(GRID_COLUMN_DIMENSION_KEY, positive_mask_matrix.shape[3]) dataset_object.createDimension(POSITIVE_VERTEX_DIM_KEY, len(positive_vertex_rows)) dataset_object.createDimension(NEGATIVE_VERTEX_DIM_KEY, len(negative_vertex_rows)) dataset_object.createVariable(POSITIVE_VERTEX_ROWS_KEY, datatype=numpy.float32, dimensions=POSITIVE_VERTEX_DIM_KEY) dataset_object.variables[ POSITIVE_VERTEX_ROWS_KEY][:] = positive_vertex_rows dataset_object.createVariable(POSITIVE_VERTEX_COLUMNS_KEY, datatype=numpy.float32, dimensions=POSITIVE_VERTEX_DIM_KEY) dataset_object.variables[POSITIVE_VERTEX_COLUMNS_KEY][:] = ( positive_vertex_columns) dataset_object.createVariable(POSITIVE_PANEL_ROW_BY_VERTEX_KEY, datatype=numpy.int32, dimensions=POSITIVE_VERTEX_DIM_KEY) dataset_object.variables[ POSITIVE_PANEL_ROW_BY_VERTEX_KEY][:] = positive_panel_row_by_vertex dataset_object.createVariable(POSITIVE_PANEL_COLUMN_BY_VERTEX_KEY, datatype=numpy.int32, dimensions=POSITIVE_VERTEX_DIM_KEY) dataset_object.variables[ POSITIVE_PANEL_COLUMN_BY_VERTEX_KEY][:] = positive_panel_column_by_vertex dataset_object.createVariable(NEGATIVE_VERTEX_ROWS_KEY, datatype=numpy.float32, dimensions=NEGATIVE_VERTEX_DIM_KEY) dataset_object.variables[ NEGATIVE_VERTEX_ROWS_KEY][:] = negative_vertex_rows dataset_object.createVariable(NEGATIVE_VERTEX_COLUMNS_KEY, datatype=numpy.float32, dimensions=NEGATIVE_VERTEX_DIM_KEY) dataset_object.variables[NEGATIVE_VERTEX_COLUMNS_KEY][:] = ( negative_vertex_columns) dataset_object.createVariable(NEGATIVE_PANEL_ROW_BY_VERTEX_KEY, datatype=numpy.int32, dimensions=NEGATIVE_VERTEX_DIM_KEY) dataset_object.variables[ NEGATIVE_PANEL_ROW_BY_VERTEX_KEY][:] = negative_panel_row_by_vertex dataset_object.createVariable(NEGATIVE_PANEL_COLUMN_BY_VERTEX_KEY, datatype=numpy.int32, dimensions=NEGATIVE_VERTEX_DIM_KEY) dataset_object.variables[ NEGATIVE_PANEL_COLUMN_BY_VERTEX_KEY][:] = negative_panel_column_by_vertex dataset_object.createVariable( POSITIVE_MASK_MATRIX_KEY, datatype=numpy.int32, dimensions=(PANEL_ROW_DIMENSION_KEY, PANEL_COLUMN_DIMENSION_KEY, GRID_ROW_DIMENSION_KEY, GRID_COLUMN_DIMENSION_KEY)) dataset_object.variables[POSITIVE_MASK_MATRIX_KEY][:] = ( positive_mask_matrix.astype(int)) dataset_object.createVariable( NEGATIVE_MASK_MATRIX_KEY, datatype=numpy.int32, dimensions=(PANEL_ROW_DIMENSION_KEY, PANEL_COLUMN_DIMENSION_KEY, GRID_ROW_DIMENSION_KEY, GRID_COLUMN_DIMENSION_KEY)) dataset_object.variables[NEGATIVE_MASK_MATRIX_KEY][:] = ( negative_mask_matrix.astype(int)) dataset_object.close()