class LoadAssetRiskAsLayerDialog(LoadOutputAsLayerDialog):
    """
    Dialog to load asset_risk from an oq-engine output, as layer
    """
    def __init__(self,
                 drive_engine_dlg,
                 iface,
                 viewer_dock,
                 session,
                 hostname,
                 calc_id,
                 output_type='asset_risk',
                 path=None,
                 mode=None,
                 engine_version=None,
                 calculation_mode=None):
        assert output_type == 'asset_risk'
        super().__init__(drive_engine_dlg,
                         iface,
                         viewer_dock,
                         session,
                         hostname,
                         calc_id,
                         output_type=output_type,
                         path=path,
                         mode=mode,
                         engine_version=engine_version,
                         calculation_mode=calculation_mode)

        self.setWindowTitle('Load Exposure/Risk as layer')
        log_msg(
            'Extracting exposure metadata.'
            ' Watch progress in QGIS task bar',
            level='I',
            message_bar=self.iface.messageBar())
        self.extract_npz_task = ExtractNpzTask('Extract exposure metadata',
                                               QgsTask.CanCancel, self.session,
                                               self.hostname, self.calc_id,
                                               'exposure_metadata',
                                               self.finalize_init,
                                               self.on_extract_error)
        QgsApplication.taskManager().addTask(self.extract_npz_task)

    def finalize_init(self, extracted_npz):
        self.exposure_metadata = extracted_npz
        self.tag_names = sorted(self.exposure_metadata['tagnames'])
        self.exposure_categories = sorted(self.exposure_metadata['names'])
        self.risk_categories = sorted(self.exposure_metadata['multi_risk'])
        self.perils = set(
            [cat.rsplit('-', 1)[-1] for cat in self.risk_categories])

        self.populate_out_dep_widgets()

        self.adjustSize()
        self.taxonomies_gbx.toggled.emit(False)
        self.tag_gbx.toggled.emit(False)
        self.set_ok_button()
        self.show()
        self.init_done.emit(self)

    def populate_out_dep_widgets(self):
        self.visualize_gbx = QGroupBox('Visualize')
        self.visualize_gbx_h_layout = QHBoxLayout()
        self.exposure_rbn = QRadioButton('Exposure')
        self.risk_rbn = QRadioButton('Risk')
        self.exposure_rbn.toggled.connect(self.on_visualize_changed)
        self.risk_rbn.toggled.connect(self.on_visualize_changed)
        self.visualize_gbx_h_layout.addWidget(self.exposure_rbn)
        self.visualize_gbx_h_layout.addWidget(self.risk_rbn)
        self.visualize_gbx.setLayout(self.visualize_gbx_h_layout)
        self.vlayout.addWidget(self.visualize_gbx)
        self.create_selector("peril",
                             "Peril",
                             filter_ckb=False,
                             on_text_changed=self.on_peril_changed)
        self.peril_cbx.setDisabled(True)
        self.peril_lbl.setVisible(False)
        self.peril_cbx.setVisible(False)
        self.create_selector("category", "Category", filter_ckb=False)
        self.peril_cbx.addItems(sorted(self.perils))
        self.taxonomies_gbx = QGroupBox()
        self.taxonomies_gbx.setTitle('Filter by taxonomy')
        self.taxonomies_gbx.setCheckable(True)
        self.taxonomies_gbx.setChecked(False)
        self.taxonomies_gbx_v_layout = QVBoxLayout()
        self.taxonomies_gbx.setLayout(self.taxonomies_gbx_v_layout)
        self.taxonomies_lbl = QLabel("Taxonomies")
        self.taxonomies_multisel = MultiSelectComboBox(self)
        self.taxonomies_multisel.add_unselected_items(
            sorted([
                taxonomy for taxonomy in self.exposure_metadata['taxonomy']
                if taxonomy != '?'
            ]))
        self.taxonomies_gbx_v_layout.addWidget(self.taxonomies_lbl)
        self.taxonomies_gbx_v_layout.addWidget(self.taxonomies_multisel)
        self.taxonomies_gbx.toggled[bool].connect(
            self.on_taxonomies_gbx_toggled)
        self.vlayout.addWidget(self.taxonomies_gbx)
        self.tag_gbx = QGroupBox()
        self.tag_gbx.setTitle('Filter by tag')
        self.tag_gbx.setCheckable(True)
        self.tag_gbx.setChecked(False)
        self.tag_gbx_v_layout = QVBoxLayout()
        self.tag_gbx.setLayout(self.tag_gbx_v_layout)
        self.tag_values_lbl = QLabel("Tag values")
        self.tag_values_multisel = MultiSelectComboBox(self)
        self.create_selector("tag",
                             "Tag",
                             add_to_layout=self.tag_gbx_v_layout,
                             on_text_changed=self.on_tag_changed)
        self.tag_cbx.addItems([
            tag_name for tag_name in self.tag_names if tag_name != 'taxonomy'
        ])
        self.tag_gbx_v_layout.addWidget(self.tag_values_lbl)
        self.tag_gbx_v_layout.addWidget(self.tag_values_multisel)
        self.tag_gbx.toggled[bool].connect(self.on_tag_gbx_toggled)
        self.vlayout.addWidget(self.tag_gbx)
        self.higher_on_top_chk = QCheckBox('Render higher values on top')
        self.higher_on_top_chk.setChecked(True)
        self.vlayout.addWidget(self.higher_on_top_chk)
        self.create_zonal_layer_selector()
        if self.zonal_layer_path:
            zonal_layer = self.load_zonal_layer(self.zonal_layer_path)
            self.populate_zonal_layer_cbx(zonal_layer)
        else:
            self.pre_populate_zonal_layer_cbx()
        self.exposure_rbn.setChecked(True)

    def on_taxonomies_gbx_toggled(self, is_checked):
        for widget in self.taxonomies_gbx.findChildren(QWidget):
            widget.setVisible(is_checked)

    def on_tag_gbx_toggled(self, is_checked):
        for widget in self.tag_gbx.findChildren(QWidget):
            widget.setVisible(is_checked)

    def on_visualize_changed(self):
        self.peril_cbx.setEnabled(self.risk_rbn.isChecked())
        self.peril_lbl.setVisible(self.risk_rbn.isChecked())
        self.peril_cbx.setVisible(self.risk_rbn.isChecked())
        if self.exposure_rbn.isChecked():
            self.category_cbx.clear()
            self.category_cbx.addItems(self.exposure_categories)
        else:  # 'Risk'
            self.peril_cbx.setCurrentIndex(0)
            self.peril_cbx.currentTextChanged.emit(
                self.peril_cbx.currentText())

    def on_peril_changed(self, peril):
        categories = [
            category.rsplit('-', 1)[0] for category in self.risk_categories
            if peril in category
        ]
        self.category_cbx.clear()
        self.category_cbx.addItems(sorted(categories))

    def on_tag_changed(self, tag_name):
        tag_values = sorted([
            value for value in self.exposure_metadata[tag_name] if value != '?'
        ])
        self.tag_values_multisel.clear()
        self.tag_values_multisel.add_unselected_items(tag_values)

    def set_ok_button(self):
        self.ok_button.setEnabled(self.category_cbx.currentIndex() != -1)

    def build_layer_name(self, rlz_or_stat=None, **kwargs):
        if self.exposure_rbn.isChecked():
            self.default_field_name = self.category_cbx.currentText()
        else:  # 'Risk'
            self.default_field_name = "%s-%s" % (
                self.category_cbx.currentText(), self.peril_cbx.currentText())
        if self.exposure_rbn.isChecked():
            layer_name = 'Exposure: %s' % self.category_cbx.currentText()
        else:  # Risk
            layer_name = 'Risk: %s %s' % (self.peril_cbx.currentText(),
                                          self.category_cbx.currentText())
        return layer_name

    def get_field_types(self, **kwargs):
        field_types = {
            name: self.dataset[name].dtype.char
            for name in self.dataset.dtype.names
            if name not in ['lon', 'lat'] and name not in self.tag_names
        }
        return field_types

    def read_npz_into_layer(self, field_types, **kwargs):
        with edit(self.layer):
            lons = self.dataset['lon']
            lats = self.dataset['lat']
            feats = []
            for row_idx, row in enumerate(self.dataset):
                # add a feature
                feat = QgsFeature(self.layer.fields())
                for field_name in field_types:
                    value = row[field_name].item()
                    if isinstance(value, bytes):
                        value = value.decode('utf8')
                    feat.setAttribute(field_name, value)
                feat.setGeometry(
                    QgsGeometry.fromPointXY(
                        QgsPointXY(lons[row_idx], lats[row_idx])))
                feats.append(feat)
            added_ok = self.layer.addFeatures(feats)
            if not added_ok:
                msg = 'There was a problem adding features to the layer.'
                log_msg(msg, level='C', message_bar=self.iface.messageBar())
        return self.layer

    def accept(self):
        log_msg('Loading output started. Watch progress in QGIS task bar',
                level='I',
                message_bar=self.iface.messageBar())
        self.iface.layerTreeView().currentLayerChanged.disconnect(
            self.on_currentLayerChanged)
        self.hide()
        extract_params = self.get_extract_params()
        self.download_asset_risk(extract_params)

    def get_extract_params(self):
        params = {}
        if self.tag_gbx.isChecked():
            tag_name = self.tag_cbx.currentText()
            params[tag_name] = self.tag_values_multisel.get_selected_items()
        if self.taxonomies_gbx.isChecked():
            params['taxonomy'] = self.taxonomies_multisel.get_selected_items()
        return params

    def download_asset_risk(self, extract_params):
        self.extract_npz_task = ExtractNpzTask('Extract asset_risk',
                                               QgsTask.CanCancel,
                                               self.session,
                                               self.hostname,
                                               self.calc_id,
                                               'asset_risk',
                                               self.on_asset_risk_downloaded,
                                               self.on_extract_error,
                                               params=extract_params)
        QgsApplication.taskManager().addTask(self.extract_npz_task)

    def on_asset_risk_downloaded(self, extracted_npz):
        self.npz_file = extracted_npz
        self.dataset = self.npz_file['array']
        with WaitCursorManager('Creating layer...', self.iface.messageBar()):
            self.layer = self.build_layer()
            self.style_maps(
                self.layer,
                self.default_field_name,
                self.iface,
                self.output_type,
                perils=self.perils,
                render_higher_on_top=self.higher_on_top_chk.isChecked())
        if (self.zonal_layer_cbx.currentText()
                and self.zonal_layer_gbx.isChecked()):
            self.aggregate_by_zone()
        else:
            self.loading_completed.emit(self)
        QDialog.accept(self)
Ejemplo n.º 2
0
class SelectSvVariablesDialog(QDialog, FORM_CLASS):
    """
    Modal dialog giving to the user the possibility to select
    social vulnerability variables to import from the oq-platform
    """
    def __init__(self, downloader):
        QDialog.__init__(self)
        # Set up the user interface from Designer.
        self.setupUi(self)
        self.indicator_lbl = QLabel('Select Indicators')
        self.indicator_multiselect = MultiSelectComboBox(self)
        self.scroll_area_contents.layout().addWidget(self.indicator_lbl)
        self.scroll_area_contents.layout().addWidget(
            self.indicator_multiselect)
        self.country_lbl = QLabel('Select Countries')
        self.country_multiselect = MultiSelectComboBox(self)
        self.scroll_area_contents.layout().addWidget(self.country_lbl)
        self.scroll_area_contents.layout().addWidget(self.country_multiselect)
        self.ok_button = self.buttonBox.button(QDialogButtonBox.Ok)
        self.set_ok_button()
        # login to platform, to be able to retrieve sv indices
        self.sv_downloader = downloader
        self.indicators_info_dict = {}
        with WaitCursorManager('Filling list of indicators...'):
            self.fill_names()
        with WaitCursorManager('Filling list of themes...'):
            self.fill_themes()
        with WaitCursorManager('Filling list of countries...'):
            self.fill_countries()
        self.indicator_multiselect.item_was_clicked.connect(
            self.update_indicator_info)
        self.indicator_multiselect.selection_changed.connect(
            self.set_ok_button)
        self.country_multiselect.selection_changed.connect(self.set_ok_button)

    @pyqtSlot(str)
    def on_theme_cbx_currentIndexChanged(self):
        theme = self.theme_cbx.currentText()
        with WaitCursorManager():
            self.fill_subthemes(theme)

    @pyqtSlot()
    def on_filter_btn_clicked(self):
        with WaitCursorManager():
            self.fill_names()

    def set_ok_button(self):
        self.ok_button.setEnabled(
            self.indicator_multiselect.selected_count() > 0
            and self.country_multiselect.selected_count() > 0)

    def fill_themes(self):
        self.theme_cbx.clear()
        # load list of themes from the platform
        self.theme_cbx.addItems([None])
        try:
            themes = self.sv_downloader.get_themes()
            self.theme_cbx.addItems(themes)
        except SvNetworkError as e:
            raise SvNetworkError(
                "Unable to download social vulnerability themes: %s" % e)
        # populate the subsequent combo boxes accordingly with the currently
        # selected item
        current_theme = self.theme_cbx.currentText()
        self.fill_subthemes(current_theme)

    def fill_subthemes(self, theme):
        self.subtheme_cbx.clear()
        # load list of subthemes from the platform
        self.subtheme_cbx.addItems([None])
        if theme:
            try:
                subthemes = self.sv_downloader.get_subthemes_by_theme(theme)
                self.subtheme_cbx.addItems(subthemes)
            except SvNetworkError as e:
                raise SvNetworkError("Unable to download social vulnerability"
                                     " subthemes: %s" % e)

    def fill_names(self):
        self.indicator_multiselect.clear()
        # load list of social vulnerability variable names from the platform
        name_filter = self.name_filter_le.text()
        keywords = self.keywords_le.text()
        theme = self.theme_cbx.currentText()
        subtheme = self.subtheme_cbx.currentText()
        try:
            filter_result_dict = self.sv_downloader.get_indicators_info(
                name_filter, keywords, theme, subtheme)
            self.indicators_info_dict.update(filter_result_dict)
            names = sorted([
                code + ': ' + filter_result_dict[code]['name']
                for code in filter_result_dict
            ])
            self.indicator_multiselect.add_unselected_items(names)
        except SvNetworkError as e:
            raise SvNetworkError(
                "Unable to download social vulnerability names: %s" % e)

    def update_indicator_info(self, text, status):
        if status:
            hint_text = text
            indicator_code = text.split(':')[0]
            indicator_info_dict = self.indicators_info_dict[indicator_code]
            hint_text += '\n\n' + 'Description:\n' + indicator_info_dict[
                'description']
            hint_text += '\n\n' + 'Source:\n' + indicator_info_dict['source']
            hint_text += ('\n\n' + 'Aggregation method:\n' +
                          indicator_info_dict['aggregation_method'])
        else:
            hint_text = ''
        self.indicator_details.setText(hint_text)

    def fill_countries(self):
        # load from platform a list of countries for which socioeconomic data
        # are available
        try:
            countries_dict = self.sv_downloader.get_countries_info()
            names = sorted([
                countries_dict[iso] + ' (' + iso + ')'
                for iso in countries_dict
            ])
            self.country_multiselect.add_unselected_items(names)
        except SvNetworkError as e:
            raise SvNetworkError(
                "Unable to download the list of countries: %s" % e)
Ejemplo n.º 3
0
class TransformationDialog(QDialog, FORM_CLASS):
    """
    Modal dialog giving to the user the possibility to transform
    one or multiple attributes in the active layer, using one of the available
    algorithms and variants.
    """
    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        self.attr_name_user_def = False
        self.use_advanced = False
        # Set up the user interface from Designer.
        self.setupUi(self)
        self.fields_lbl = QLabel('Fields to transform')
        self.fields_multiselect = MultiSelectComboBox(self)
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.fields_lbl)
        hlayout.addWidget(self.fields_multiselect)
        self.vertical_layout.insertLayout(1, hlayout)
        self.adjustSize()
        self.ok_button = self.buttonBox.button(QDialogButtonBox.Ok)
        self.fill_fields_multiselect()

        alg_list = list(TRANSFORMATION_ALGS.keys())
        self.algorithm_cbx.addItems(alg_list)
        if self.algorithm_cbx.currentText() in ['RANK', 'QUADRATIC']:
            self.reload_variant_cbx()
        self.inverse_ckb.setDisabled(
            self.algorithm_cbx.currentText() in ['LOG10'])
        self.warning_lbl.hide()
        self.warning_lbl.setText(
            "<font color='red'>"
            "WARNING: the original attribute will be overwritten by the"
            " results of the transformation (it can not be undone)"
            "</font>")
        self.fields_multiselect.selection_changed.connect(self.set_ok_button)
        self.fields_multiselect.selection_changed.connect(
            self.set_new_field_editable)
        self.fields_multiselect.selection_changed.connect(
            self.update_default_fieldname)
        self.set_ok_button()
        self.set_new_field_editable()

    def set_ok_button(self):
        self.ok_button.setEnabled(self.fields_multiselect.selected_count() > 0)

    def set_new_field_editable(self):
        n_fields_selected = self.fields_multiselect.selected_count()
        self.new_field_name_lbl.setEnabled(n_fields_selected == 1)
        self.new_field_name_txt.setEnabled(n_fields_selected == 1)

    @pyqtSlot(int)
    def on_overwrite_ckb_stateChanged(self):
        overwrite_checked = self.overwrite_ckb.isChecked()
        self.new_field_name_lbl.setDisabled(overwrite_checked)
        self.new_field_name_txt.setDisabled(overwrite_checked)
        self.track_new_field_ckb.setDisabled(overwrite_checked)
        if overwrite_checked:
            self.attr_name_user_def = False
            self.warning_lbl.show()
        else:
            self.warning_lbl.hide()
        self.update_default_fieldname()

    @pyqtSlot()
    def on_calc_btn_clicked(self):
        self.close()
        # layer is put in editing mode. If the user clicks on ok, the field
        # calculator will update the layers attributes.
        # if the user clicks cancel, the field calculator does nothing.
        # the layer stays in editing mode with the use_advanced flag set.
        # the calling code should take care of doing layer.commitChanges()
        # if the flag is set to true.
        self.use_advanced = True
        self.iface.activeLayer().startEditing()
        self.iface.actionOpenFieldCalculator().trigger()

    @pyqtSlot(str)
    def on_algorithm_cbx_currentIndexChanged(self):
        self.reload_variant_cbx()
        self.update_default_fieldname()

    @pyqtSlot(str)
    def on_variant_cbx_currentIndexChanged(self):
        self.update_default_fieldname()

    @pyqtSlot()
    def on_new_field_name_txt_editingFinished(self):
        self.attr_name_user_def = True
        new_field_name = self.new_field_name_txt.text()
        # if the name of the new field is empty, automatically assign a name
        if not new_field_name:
            self.update_default_fieldname()

    @pyqtSlot(str)
    def on_new_field_name_txt_textEdited(self):
        # we assume exactly one item is in the selected list
        input_field_name = self._extract_field_name(
            self.fields_multiselect.get_selected_items()[0])
        new_field_name = self.new_field_name_txt.text()
        # if the name of the new field is equal to the name of the input field,
        # automatically check the 'overwrite' checkbox (and consequently
        # display the warning)
        if new_field_name == input_field_name:
            self.overwrite_ckb.setChecked(True)

    def reload_variant_cbx(self):
        self.variant_cbx.clear()
        self.variant_cbx.setEnabled(True)
        if self.algorithm_cbx.currentText() == 'RANK':
            self.variant_cbx.addItems(RANK_VARIANTS)
        elif self.algorithm_cbx.currentText() == 'QUADRATIC':
            self.variant_cbx.addItems(QUADRATIC_VARIANTS)
        elif self.algorithm_cbx.currentText() == 'LOG10':
            self.variant_cbx.addItems(LOG10_VARIANTS)
        else:
            self.variant_cbx.setDisabled(True)
        self.inverse_ckb.setDisabled(
            self.algorithm_cbx.currentText() in ['LOG10'])

    def _extract_field_name(self, field_name_plus_alias):
        # attribute_name is something like 'ABCDEFGHIL (Readable name)'
        # and we want to use only the heading code
        return field_name_plus_alias.split('(')[0].strip()

    def update_default_fieldname(self):
        if self.fields_multiselect.selected_count() != 1:
            self.new_field_name_txt.setText('')
            self.attr_name_user_def = False
            return
        if (not self.attr_name_user_def or not self.new_field_name_txt.text()):
            attribute_name = self._extract_field_name(
                self.fields_multiselect.get_selected_items()[0])
            algorithm_name = self.algorithm_cbx.currentText()
            variant = self.variant_cbx.currentText()
            inverse = self.inverse_ckb.isChecked()
            if self.overwrite_ckb.isChecked():
                new_attr_name = attribute_name
            else:
                try:
                    new_attr_name = ProcessLayer(
                        self.iface.activeLayer()).transform_attribute(
                            attribute_name,
                            algorithm_name,
                            variant,
                            inverse,
                            simulate=True)
                except TypeError as exc:
                    log_msg(str(exc),
                            level='C',
                            message_bar=self.iface.messageBar(),
                            exception=exc)
                    return
            self.new_field_name_txt.setText(new_attr_name)
            self.attr_name_user_def = False

    def fill_fields_multiselect(self):
        names_plus_aliases = []
        for field_idx, field in enumerate(self.iface.activeLayer().fields()):
            if field.typeName() in NUMERIC_FIELD_TYPES:
                alias = self.iface.activeLayer().attributeAlias(field_idx)
                if '(' in field.name():
                    msg = ('Please remove parentheses from the name of field'
                           ' %s before attempting to transform it, otherwise'
                           ' the tool will not be able to distinguish between'
                           ' the alias and the part of the name included'
                           ' between parentheses. For instance, you may'
                           ' replace "(" with "[" to avoid ambiguity.' %
                           field.name())
                    log_msg(msg,
                            level='W',
                            message_bar=self.iface.messageBar())
                else:
                    name_plus_alias = field.name()
                    if alias:
                        name_plus_alias += ' (%s)' % alias
                    names_plus_aliases.append(name_plus_alias)
        self.fields_multiselect.add_unselected_items(names_plus_aliases)