def test_classification_thresholds(self): """Test for classification_thresholds method.""" thresholds = default_classification_thresholds(flood_hazard_classes) wet_class = flood_hazard_classes['classes'][0] dry_class = flood_hazard_classes['classes'][1] expected = { 'dry': [ dry_class['numeric_default_min'], dry_class['numeric_default_max'] ], 'wet': [ wet_class['numeric_default_min'], wet_class['numeric_default_max'] ] } self.assertDictEqual(thresholds, expected) unit_knots_key = unit_knots['key'] thresholds = default_classification_thresholds( cyclone_au_bom_hazard_classes, unit_knots_key) category_5_class = cyclone_au_bom_hazard_classes['classes'][0] category_4_class = cyclone_au_bom_hazard_classes['classes'][1] category_3_class = cyclone_au_bom_hazard_classes['classes'][2] category_2_class = cyclone_au_bom_hazard_classes['classes'][3] category_1_class = cyclone_au_bom_hazard_classes['classes'][4] tropical_depression_class = cyclone_au_bom_hazard_classes['classes'][5] expected = { 'tropical_depression': [ tropical_depression_class['numeric_default_min'], tropical_depression_class['numeric_default_max'] [unit_knots_key] ], 'category_1': [ category_1_class['numeric_default_min'][unit_knots_key], category_1_class['numeric_default_max'][unit_knots_key] ], 'category_2': [ category_2_class['numeric_default_min'][unit_knots_key], category_2_class['numeric_default_max'][unit_knots_key] ], 'category_3': [ category_3_class['numeric_default_min'][unit_knots_key], category_3_class['numeric_default_max'][unit_knots_key] ], 'category_4': [ category_4_class['numeric_default_min'][unit_knots_key], category_4_class['numeric_default_max'][unit_knots_key] ], 'category_5': [ category_5_class['numeric_default_min'][unit_knots_key], category_5_class['numeric_default_max'] ] } self.assertDictEqual(thresholds, expected)
def test_classification_thresholds(self): """Test for classification_thresholds method.""" thresholds = default_classification_thresholds(flood_hazard_classes) wet_class = flood_hazard_classes['classes'][0] dry_class = flood_hazard_classes['classes'][1] expected = { 'dry': [ dry_class['numeric_default_min'], dry_class['numeric_default_max'] ], 'wet': [ wet_class['numeric_default_min'], wet_class['numeric_default_max'] ] } self.assertDictEqual(thresholds, expected) unit_knots_key = unit_knots['key'] thresholds = default_classification_thresholds( cyclone_au_bom_hazard_classes, unit_knots_key) category_5_class = cyclone_au_bom_hazard_classes['classes'][0] category_4_class = cyclone_au_bom_hazard_classes['classes'][1] category_3_class = cyclone_au_bom_hazard_classes['classes'][2] category_2_class = cyclone_au_bom_hazard_classes['classes'][3] category_1_class = cyclone_au_bom_hazard_classes['classes'][4] tropical_depression_class = cyclone_au_bom_hazard_classes['classes'][5] expected = { 'tropical_depression': [ tropical_depression_class['numeric_default_min'], tropical_depression_class['numeric_default_max'][ unit_knots_key] ], 'category_1': [ category_1_class['numeric_default_min'][unit_knots_key], category_1_class['numeric_default_max'][unit_knots_key] ], 'category_2': [ category_2_class['numeric_default_min'][unit_knots_key], category_2_class['numeric_default_max'][unit_knots_key] ], 'category_3': [ category_3_class['numeric_default_min'][unit_knots_key], category_3_class['numeric_default_max'][unit_knots_key] ], 'category_4': [ category_4_class['numeric_default_min'][unit_knots_key], category_4_class['numeric_default_max'][unit_knots_key] ], 'category_5': [ category_5_class['numeric_default_min'][unit_knots_key], category_5_class['numeric_default_max'] ] } self.assertDictEqual(thresholds, expected)
def activate_classification(self, exposure, classification=None): """Set active to True for classification for the exposure. If classification = None, all classification set active = False. :param exposure: Exposure definition. :type exposure: dict :param classification: Classification definition. :type classification: dict """ if self.layer_mode == layer_mode_continuous: selected_unit = self.parent.step_kw_unit.selected_unit()['key'] target = self.thresholds.get(exposure['key']) if target is None: self.thresholds[exposure['key']] = {} target = self.thresholds.get(exposure['key']) else: selected_unit = None target = self.value_maps.get(exposure['key']) if target is None: self.value_maps[exposure['key']] = {} target = self.value_maps.get(exposure['key']) if classification is not None: if classification['key'] not in target: if self.layer_mode == layer_mode_continuous: default_classes = default_classification_thresholds( classification, selected_unit) target[classification['key']] = { 'classes': default_classes, 'active': True } else: default_classes = default_classification_value_maps( classification) target[classification['key']] = { 'classes': default_classes, 'active': True } return for classification_key, value in target.items(): if classification is None: value['active'] = False continue if classification_key == classification['key']: value['active'] = True else: value['active'] = False
def activate_classification(self, exposure, classification=None): """Set active to True for classification for the exposure. If classification = None, all classification set active = False. :param exposure: Exposure definition. :type exposure: dict :param classification: Classification definition. :type classification: dict """ if self.layer_mode == layer_mode_continuous: selected_unit = self.parent.step_kw_unit.selected_unit()['key'] target = self.thresholds.get(exposure['key']) if target is None: self.thresholds[exposure['key']] = {} target = self.thresholds.get(exposure['key']) else: selected_unit = None target = self.value_maps.get(exposure['key']) if target is None: self.value_maps[exposure['key']] = {} target = self.value_maps.get(exposure['key']) if classification is not None: if classification['key'] not in target: if self.layer_mode == layer_mode_continuous: default_classes = default_classification_thresholds( classification, selected_unit) target[classification['key']] = { 'classes': default_classes, 'active': True } else: default_classes = default_classification_value_maps( classification) target[classification['key']] = { 'classes': default_classes, 'active': True } return for classification_key, value in target.items(): if classification is None: value['active'] = False continue if classification_key == classification['key']: value['active'] = True else: value['active'] = False
def create_keyword_file(self, algorithm): """Create keyword file for the raster file created. Basically copy a template from keyword file in converter data and add extra keyword (usually a title) :param algorithm: Which re-sampling algorithm to use. valid options are 'nearest' (for nearest neighbour), 'invdist' (for inverse distance), 'average' (for moving average). Defaults to 'nearest' if not specified. Note that passing re-sampling alg parameters is currently not supported. If None is passed it will be replaced with 'nearest'. :type algorithm: str """ keyword_io = KeywordIO() # Set thresholds for each exposure mmi_default_classes = default_classification_thresholds( earthquake_mmi_scale) mmi_default_threshold = { earthquake_mmi_scale['key']: { 'active': True, 'classes': mmi_default_classes } } generic_default_classes = default_classification_thresholds( generic_hazard_classes) generic_default_threshold = { generic_hazard_classes['key']: { 'active': True, 'classes': generic_default_classes } } threshold_keyword = {} for exposure in exposure_all: # Not all exposure is supported by earthquake_mmi_scale if exposure in earthquake_mmi_scale['exposures']: threshold_keyword[exposure['key']] = mmi_default_threshold else: threshold_keyword[exposure['key']] = generic_default_threshold extra_keywords = { extra_keyword_earthquake_latitude['key']: self.latitude, extra_keyword_earthquake_longitude['key']: self.longitude, extra_keyword_earthquake_magnitude['key']: self.magnitude, extra_keyword_earthquake_depth['key']: self.depth, extra_keyword_earthquake_description['key']: self.description, extra_keyword_earthquake_location['key']: self.location, extra_keyword_earthquake_event_time['key']: self.time.strftime('%Y-%m-%dT%H:%M:%S'), extra_keyword_time_zone['key']: self.time_zone, extra_keyword_earthquake_x_minimum['key']: self.x_minimum, extra_keyword_earthquake_x_maximum['key']: self.x_maximum, extra_keyword_earthquake_y_minimum['key']: self.y_minimum, extra_keyword_earthquake_y_maximum['key']: self.y_maximum, extra_keyword_earthquake_event_id['key']: self.event_id } for key, value in self.extra_keywords.items(): extra_keywords[key] = value # Delete empty element. empty_keys = [] for key, value in extra_keywords.items(): if value is None: empty_keys.append(key) for empty_key in empty_keys: extra_keywords.pop(empty_key) keywords = { 'hazard': hazard_earthquake['key'], 'hazard_category': hazard_category_single_event['key'], 'keyword_version': inasafe_keyword_version, 'layer_geometry': layer_geometry_raster['key'], 'layer_mode': layer_mode_continuous['key'], 'layer_purpose': layer_purpose_hazard['key'], 'continuous_hazard_unit': unit_mmi['key'], 'classification': earthquake_mmi_scale['key'], 'thresholds': threshold_keyword, 'extra_keywords': extra_keywords, 'active_band': 1 } if self.algorithm_name: layer_path = os.path.join( self.output_dir, '%s-%s.tif' % (self.output_basename, algorithm)) else: layer_path = os.path.join(self.output_dir, '%s.tif' % self.output_basename) # append title and source to the keywords file if len(self.title.strip()) == 0: keyword_title = self.output_basename else: keyword_title = self.title keywords['title'] = keyword_title hazard_layer = QgsRasterLayer(layer_path, keyword_title) if not hazard_layer.isValid(): raise InvalidLayerError() keyword_io.write_keywords(hazard_layer, keywords)
def setup_left_panel(self): """Setup the UI for left panel. Generate all exposure, combobox, and edit button. """ hazard = self.parent.step_kw_subcategory.selected_subcategory() left_panel_heading = QLabel(tr('Classifications')) left_panel_heading.setFont(big_font) self.left_layout.addWidget(left_panel_heading) inner_left_layout = QGridLayout() row = 0 for exposure in exposure_all: special_case = False # Filter out unsupported exposure for the hazard if exposure in hazard['disabled_exposures']: # Remove from the storage if the exposure is disabled if self.layer_mode == layer_mode_continuous: if exposure['key'] in self.thresholds: self.thresholds.pop(exposure['key']) else: if exposure['key'] in self.value_maps: self.value_maps.pop(exposure['key']) continue # Trick for EQ raster for population #3853 if exposure == exposure_population and hazard == hazard_earthquake: if is_raster_layer(self.parent.layer): if self.layer_mode == layer_mode_continuous: self.use_default_thresholds = True special_case = True # Set classification for EQ Raster for Population self.thresholds[exposure_population['key']] = { earthquake_mmi_scale['key']: { 'classes': default_classification_thresholds( earthquake_mmi_scale), 'active': True } } # Add label # Hazard on Exposure Classifications label = tr( '{hazard_name} on {exposure_name} Classifications').format( hazard_name=hazard['name'], exposure_name=exposure['name'] ) exposure_label = QLabel(label) # Add combo box exposure_combo_box = QComboBox() hazard_classifications = hazard.get('classifications') exposure_combo_box.addItem(tr('No classifications')) exposure_combo_box.setItemData( 0, None, Qt.UserRole) current_index = 0 i = 0 # Iterate through all available hazard classifications for hazard_classification in hazard_classifications: # Skip if the classification is not for the exposure if 'exposures' in hazard_classification: if exposure not in hazard_classification['exposures']: continue exposure_combo_box.addItem(hazard_classification['name']) exposure_combo_box.setItemData( i + 1, hazard_classification, Qt.UserRole) if self.layer_mode == layer_mode_continuous: current_hazard_classifications = self.thresholds.get( exposure['key']) else: current_hazard_classifications = self.value_maps.get( exposure['key']) if current_hazard_classifications: current_hazard_classification = \ current_hazard_classifications.get( hazard_classification['key']) if current_hazard_classification: is_active = current_hazard_classification.get('active') if is_active: current_index = i + 1 i += 1 # Set current classification exposure_combo_box.setCurrentIndex(current_index) # Add edit button exposure_edit_button = QPushButton(tr('Edit')) # For special case. Raster EQ on Population. if special_case: mmi_index = exposure_combo_box.findText( earthquake_mmi_scale['name']) exposure_combo_box.setCurrentIndex(mmi_index) exposure_combo_box.setEnabled(False) exposure_edit_button.setEnabled(False) tool_tip_message = tr( 'InaSAFE use default classification for Raster Earthquake ' 'hazard on population.') exposure_label.setToolTip(tool_tip_message) exposure_combo_box.setToolTip(tool_tip_message) exposure_edit_button.setToolTip(tool_tip_message) else: if current_index == 0: # Disable if there is no classification chosen. exposure_edit_button.setEnabled(False) exposure_edit_button.clicked.connect( partial(self.edit_button_clicked, edit_button=exposure_edit_button, exposure_combo_box=exposure_combo_box, exposure=exposure)) exposure_combo_box.currentIndexChanged.connect( partial( self.classifications_combo_box_changed, exposure=exposure, exposure_combo_box=exposure_combo_box, edit_button=exposure_edit_button)) # Arrange in layout inner_left_layout.addWidget(exposure_label, row, 0) inner_left_layout.addWidget(exposure_combo_box, row, 1) inner_left_layout.addWidget(exposure_edit_button, row, 2) # Adding to step's attribute self.exposures.append(exposure) self.exposure_combo_boxes.append(exposure_combo_box) self.exposure_edit_buttons.append(exposure_edit_button) self.exposure_labels.append(label) if special_case: self.special_case_index = len(self.exposures) - 1 row += 1 self.left_layout.addLayout(inner_left_layout) # To push the inner_left_layout up self.left_layout.addStretch(1)
def setup_left_panel(self): """Setup the UI for left panel. Generate all exposure, combobox, and edit button. """ hazard = self.parent.step_kw_subcategory.selected_subcategory() left_panel_heading = QLabel(tr('Classifications')) left_panel_heading.setFont(big_font) self.left_layout.addWidget(left_panel_heading) inner_left_layout = QGridLayout() row = 0 for exposure in exposure_all: special_case = False # Filter out unsupported exposure for the hazard if exposure in hazard['disabled_exposures']: # Remove from the storage if the exposure is disabled if self.layer_mode == layer_mode_continuous: if exposure['key'] in self.thresholds: self.thresholds.pop(exposure['key']) else: if exposure['key'] in self.value_maps: self.value_maps.pop(exposure['key']) continue # Trick for EQ raster for population #3853 if exposure == exposure_population and hazard == hazard_earthquake: if is_raster_layer(self.parent.layer): if self.layer_mode == layer_mode_continuous: self.use_default_thresholds = True special_case = True # Set classification for EQ Raster for Population self.thresholds[exposure_population['key']] = { earthquake_mmi_scale['key']: { 'classes': default_classification_thresholds( earthquake_mmi_scale), 'active': True } } # Add label # Hazard on Exposure Classifications label = tr( '{hazard_name} on {exposure_name} Classifications').format( hazard_name=hazard['name'], exposure_name=exposure['name'] ) exposure_label = QLabel(label) # Add combo box exposure_combo_box = QComboBox() hazard_classifications = hazard.get('classifications') exposure_combo_box.addItem(tr('No classifications')) exposure_combo_box.setItemData( 0, None, Qt.UserRole) current_index = 0 i = 0 # Iterate through all available hazard classifications for hazard_classification in hazard_classifications: # Skip if the classification is not for the exposure if 'exposures' in hazard_classification: if exposure not in hazard_classification['exposures']: continue exposure_combo_box.addItem(hazard_classification['name']) exposure_combo_box.setItemData( i + 1, hazard_classification, Qt.UserRole) if self.layer_mode == layer_mode_continuous: current_hazard_classifications = self.thresholds.get( exposure['key']) else: current_hazard_classifications = self.value_maps.get( exposure['key']) if current_hazard_classifications: current_hazard_classification = \ current_hazard_classifications.get( hazard_classification['key']) if current_hazard_classification: is_active = current_hazard_classification.get('active') if is_active: current_index = i + 1 i += 1 # Set current classification exposure_combo_box.setCurrentIndex(current_index) # Add edit button exposure_edit_button = QPushButton(tr('Edit')) # For special case. Raster EQ on Population. if special_case: mmi_index = exposure_combo_box.findText( earthquake_mmi_scale['name']) exposure_combo_box.setCurrentIndex(mmi_index) exposure_combo_box.setEnabled(False) exposure_edit_button.setEnabled(False) tool_tip_message = tr( 'InaSAFE use default classification for Raster Earthquake ' 'hazard on population.') exposure_label.setToolTip(tool_tip_message) exposure_combo_box.setToolTip(tool_tip_message) exposure_edit_button.setToolTip(tool_tip_message) else: if current_index == 0: # Disable if there is no classification chosen. exposure_edit_button.setEnabled(False) exposure_edit_button.clicked.connect( partial(self.edit_button_clicked, edit_button=exposure_edit_button, exposure_combo_box=exposure_combo_box, exposure=exposure)) exposure_combo_box.currentIndexChanged.connect( partial( self.classifications_combo_box_changed, exposure=exposure, exposure_combo_box=exposure_combo_box, edit_button=exposure_edit_button)) # Arrange in layout inner_left_layout.addWidget(exposure_label, row, 0) inner_left_layout.addWidget(exposure_combo_box, row, 1) inner_left_layout.addWidget(exposure_edit_button, row, 2) # Adding to step's attribute self.exposures.append(exposure) self.exposure_combo_boxes.append(exposure_combo_box) self.exposure_edit_buttons.append(exposure_edit_button) self.exposure_labels.append(label) if special_case: self.special_case_index = len(self.exposures) - 1 row += 1 self.left_layout.addLayout(inner_left_layout) # To push the inner_left_layout up self.left_layout.addStretch(1)
def create_keyword_file(self, algorithm): """Create keyword file for the raster file created. Basically copy a template from keyword file in converter data and add extra keyword (usually a title) :param algorithm: Which re-sampling algorithm to use. valid options are 'nearest' (for nearest neighbour), 'invdist' (for inverse distance), 'average' (for moving average). Defaults to 'nearest' if not specified. Note that passing re-sampling alg parameters is currently not supported. If None is passed it will be replaced with 'nearest'. :type algorithm: str """ keyword_io = KeywordIO() # Set thresholds for each exposure mmi_default_classes = default_classification_thresholds( earthquake_mmi_scale ) mmi_default_threshold = { earthquake_mmi_scale['key']: { 'active': True, 'classes': mmi_default_classes } } generic_default_classes = default_classification_thresholds( generic_hazard_classes ) generic_default_threshold = { generic_hazard_classes['key']: { 'active': True, 'classes': generic_default_classes } } threshold_keyword = {} for exposure in exposure_all: # Not all exposure is supported by earthquake_mmi_scale if exposure in earthquake_mmi_scale['exposures']: threshold_keyword[exposure['key']] = mmi_default_threshold else: threshold_keyword[ exposure['key']] = generic_default_threshold extra_keywords = { extra_keyword_earthquake_latitude['key']: self.latitude, extra_keyword_earthquake_longitude['key']: self.longitude, extra_keyword_earthquake_magnitude['key']: self.magnitude, extra_keyword_earthquake_depth['key']: self.depth, extra_keyword_earthquake_description['key']: self.description, extra_keyword_earthquake_location['key']: self.location, extra_keyword_earthquake_event_time['key']: self.time.strftime( '%Y-%m-%dT%H:%M:%S'), extra_keyword_time_zone['key']: self.time_zone, extra_keyword_earthquake_x_minimum['key']: self.x_minimum, extra_keyword_earthquake_x_maximum['key']: self.x_maximum, extra_keyword_earthquake_y_minimum['key']: self.y_minimum, extra_keyword_earthquake_y_maximum['key']: self.y_maximum, extra_keyword_earthquake_event_id['key']: self.event_id } for key, value in list(self.extra_keywords.items()): extra_keywords[key] = value # Delete empty element. empty_keys = [] for key, value in list(extra_keywords.items()): if value is None: empty_keys.append(key) for empty_key in empty_keys: extra_keywords.pop(empty_key) keywords = { 'hazard': hazard_earthquake['key'], 'hazard_category': hazard_category_single_event['key'], 'keyword_version': inasafe_keyword_version, 'layer_geometry': layer_geometry_raster['key'], 'layer_mode': layer_mode_continuous['key'], 'layer_purpose': layer_purpose_hazard['key'], 'continuous_hazard_unit': unit_mmi['key'], 'classification': earthquake_mmi_scale['key'], 'thresholds': threshold_keyword, 'extra_keywords': extra_keywords, 'active_band': 1 } if self.algorithm_name: layer_path = os.path.join( self.output_dir, '%s-%s.tif' % ( self.output_basename, algorithm)) else: layer_path = os.path.join( self.output_dir, '%s.tif' % self.output_basename) # append title and source to the keywords file if len(self.title.strip()) == 0: keyword_title = self.output_basename else: keyword_title = self.title keywords['title'] = keyword_title hazard_layer = QgsRasterLayer(layer_path, keyword_title) if not hazard_layer.isValid(): raise InvalidLayerError() keyword_io.write_keywords(hazard_layer, keywords)