Пример #1
0
 def browser_dialog_to_load_file(self, combo_box, dialog_title,
                                 file_filters):
     file_path, _ = QFileDialog.getOpenFileName(self, dialog_title, "",
                                                file_filters)
     if file_path != '' and os.path.isfile(file_path):
         # load to qgis and update combobox list
         load_and_select_filepath_in(combo_box, file_path)
Пример #2
0
    def clipping_thematic_raster(self):
        # first check input files requirements
        if not valid_file_selected_in(self.QCBox_ThematicRaster, "thematic raster"):
            return
        if not valid_file_selected_in(self.QCBox_AreaOfInterest, "area of interest shape"):
            return

        # first select the target dir for save the clipping file
        filename, ext = os.path.splitext(get_current_file_path_in(self.QCBox_ThematicRaster))
        ext = ext if ext in [".tif", ".TIF", ".img", ".IMG"] else ".tif"
        suggested_filename = filename + "_clip" + ext

        file_out, _ = QFileDialog.getSaveFileName(self, self.tr("Select the output file to save the clipping file"),
                                                  suggested_filename,
                                                  self.tr("GeoTiff files (*.tif);;Img files (*.img);;All files (*.*)"))
        if file_out == '':
            return

        # clipping
        clip_file = do_clipping_with_shape(
            self.QCBox_ThematicRaster.currentLayer(),
            self.QCBox_AreaOfInterest.currentLayer(), file_out,
            get_nodata_value(self.QCBox_ThematicRaster.currentLayer()))
        # copy the style
        thematic_basename = os.path.splitext(get_current_file_path_in(self.QCBox_ThematicRaster))[0]
        if os.path.isfile(thematic_basename + ".qml"):
            copyfile(thematic_basename + ".qml", os.path.splitext(file_out)[0] + ".qml")
        # unload old thematic file
        unload_layer(get_current_file_path_in(self.QCBox_ThematicRaster))
        # load to qgis and update combobox list
        load_and_select_filepath_in(self.QCBox_ThematicRaster, clip_file)
        self.select_thematic_raster(self.QCBox_ThematicRaster.currentLayer())

        iface.messageBar().pushMessage("AcATaMa", "Clipping the thematic raster with shape, completed",
                                       level=Qgis.Success)
Пример #3
0
    def fileDialog_loadClassificationConfig(self):
        file_path, _ = QFileDialog.getOpenFileName(self, self.tr("Restore the configuration and classification status"),
                                                   "", self.tr("Yaml (*.yaml *.yml);;All files (*.*)"))

        if file_path != '' and os.path.isfile(file_path):
            # load classification status from yaml file
            import yaml
            with open(file_path, 'r') as yaml_file:
                try:
                    yaml_config = yaml.load(yaml_file)
                except yaml.YAMLError as err:
                    iface.messageBar().pushMessage("AcATaMa", "Error while read the yaml file classification config",
                                                   level=Qgis.Critical)
                    return
            # load the sampling file save in yaml config
            sampling_filepath = yaml_config["sampling_layer"]
            if not os.path.isfile(sampling_filepath):
                iface.messageBar().pushMessage("AcATaMa",
                                               "Error the sampling file saved in this config file, not exists",
                                               level=Qgis.Critical)
                # TODO: ask for new location of the sampling file
                return

            sampling_layer = load_and_select_filepath_in(self.QCBox_SamplingFile, sampling_filepath)

            # restore configuration and classification status
            classification = Classification(sampling_layer)
            classification.load_config(yaml_config)

            # reload sampling file status in accuracy assessment
            self.set_sampling_file_accuracy_assessment()

            iface.messageBar().pushMessage("AcATaMa", "File loaded successfully", level=Qgis.Success)
Пример #4
0
    def load_config(self, yaml_config):
        from AcATaMa.gui.acatama_dockwidget import AcATaMaDockWidget as AcATaMa
        # restore the thematic raster
        if yaml_config["thematic_raster"]["path"]:
            # thematic raster
            load_and_select_filepath_in(AcATaMa.dockwidget.QCBox_ThematicRaster,
                                        yaml_config["thematic_raster"]["path"])
            AcATaMa.dockwidget.select_thematic_raster(AcATaMa.dockwidget.QCBox_ThematicRaster.currentLayer())
            # band number
            if "band" in yaml_config["thematic_raster"]:
                AcATaMa.dockwidget.QCBox_band_ThematicRaster.setCurrentIndex(yaml_config["thematic_raster"]["band"] - 1)
            # nodata
            AcATaMa.dockwidget.nodata_ThematicRaster.setValue(yaml_config["thematic_raster"]["nodata"])

        # restore the classification settings
        AcATaMa.dockwidget.grid_columns.setValue(yaml_config["grid_view_widgets"]["columns"])
        AcATaMa.dockwidget.grid_rows.setValue(yaml_config["grid_view_widgets"]["rows"])
        self.dialog_size = yaml_config["dialog_size"]
        self.grid_columns = yaml_config["grid_view_widgets"]["columns"]
        self.grid_rows = yaml_config["grid_view_widgets"]["rows"]
        self.current_sample_idx = yaml_config["current_sample_idx"]
        self.fit_to_sample = yaml_config["fit_to_sample"]
        self.is_completed = yaml_config["is_completed"]
        # restore the buttons config
        self.buttons_config = yaml_config["classification_buttons"]
        # restore the view widget config
        self.view_widgets_config = yaml_config["view_widgets_config"]

        # support load the old format of config file TODO: delete
        for x in self.view_widgets_config.values():
            if "render_file" in x:
                x["render_file_path"] = x["render_file"]
                del x["render_file"]
            if "name" in x:
                x["view_name"] = x["name"]
                del x["name"]
            if "layer_name" not in x:
                x["layer_name"] = None

        # restore the samples order
        points_ordered = []
        for shape_id in yaml_config["points_order"]:
            # point saved exist in shape file
            if shape_id in [p.shape_id for p in self.points]:
                points_ordered.append([p for p in self.points if p.shape_id == shape_id][0])
        # added new point inside shape file that not exists in yaml config
        for new_point_id in set([p.shape_id for p in self.points]) - set(yaml_config["points_order"]):
            points_ordered.append([p for p in self.points if p.shape_id == new_point_id][0])
        # reassign points loaded and ordered
        self.points = points_ordered
        # restore point status classification
        for status in yaml_config["points"].values():
            if status["shape_id"] in [p.shape_id for p in self.points]:
                point_to_restore = [p for p in self.points if p.shape_id == status["shape_id"]][0]
                point_to_restore.classif_id = status["classif_id"]
                if point_to_restore.classif_id is not None:
                    point_to_restore.is_classified = True
        # update the status and labels plugin with the current sampling classification
        self.reload_classification_status()
        AcATaMa.dockwidget.update_the_status_of_classification()
        # define if this classification was made with thematic classes
        if self.buttons_config and yaml_config["thematic_raster"]["path"] and \
           True in [bc["thematic_class"] is not None and bc["thematic_class"] != "" for bc in self.buttons_config.values()]:
            self.with_thematic_classes = True

        # restore accuracy assessment conf
        if "accuracy_assessment_sampling_file" in yaml_config and yaml_config["accuracy_assessment_sampling_file"]:
            load_and_select_filepath_in(AcATaMa.dockwidget.QCBox_SamplingFile_AA,
                                        yaml_config["accuracy_assessment_sampling_file"])
        if "accuracy_assessment_dialog" in yaml_config:
            from AcATaMa.core.accuracy_assessment import AccuracyAssessment
            accuracy_assessment = AccuracyAssessment(self)
            area_unit, success = QgsUnitTypes.stringToAreaUnit(yaml_config["accuracy_assessment_dialog"]["area_unit"])
            if success:
                accuracy_assessment.area_unit = area_unit
            accuracy_assessment.z_score = yaml_config["accuracy_assessment_dialog"]["z_score"]
            accuracy_assessment.csv_separator = yaml_config["accuracy_assessment_dialog"]["csv_separator"]
            accuracy_assessment.csv_decimal = yaml_config["accuracy_assessment_dialog"]["csv_decimal"]
            self.accuracy_assessment = accuracy_assessment
Пример #5
0
    def __init__(self, sampling_layer, columns, rows):
        QDialog.__init__(self)
        self.sampling_layer = sampling_layer
        self.setupUi(self)
        ClassificationDialog.instance = self

        # flags
        self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint
                            | Qt.WindowMaximizeButtonHint)

        # get classification or init new instance
        if sampling_layer in Classification.instances:
            self.classification = Classification.instances[sampling_layer]
        else:
            self.classification = Classification(sampling_layer)
            self.classification.grid_columns = columns
            self.classification.grid_rows = rows

        #### settings the classification dialog

        # set dialog title
        self.setWindowTitle("Classification of samples for " +
                            sampling_layer.name())
        # resize the classification dialog
        if self.classification.dialog_size:
            self.resize(*self.classification.dialog_size)

        # disable enter action
        self.QPBtn_SetClassification.setAutoDefault(False)
        self.QPBtn_unclassifySampleButton.setAutoDefault(False)

        # go to sample ID action
        self.GoTo_ID_Button.clicked.connect(self.go_to_sample_id)
        self.GoTo_ID.returnPressed.connect(self.go_to_sample_id)
        self.GoTo_ID.textChanged.connect(
            lambda: self.GoTo_ID.setStyleSheet(""))

        # open in Google Earth
        self.QPBtn_OpenInGE.clicked.connect(
            self.open_current_point_in_google_engine)

        # set properties and default value for the fit to sample spinBox based on sampling file
        layer_dist_unit = self.sampling_layer.crs().mapUnits()
        str_unit = QgsUnitTypes.toString(layer_dist_unit)
        abbr_unit = QgsUnitTypes.toAbbreviatedString(layer_dist_unit)
        self.radiusFitToSample.setSuffix(" {}".format(abbr_unit))
        self.radiusFitToSample.setToolTip(
            "Units in {} for set the zoom radius to the current sample\n"
            "(units based on sampling file selected)".format(str_unit))
        self.radiusFitToSample.setRange(
            0,
            360 if layer_dist_unit == QgsUnitTypes.DistanceDegrees else 10e6)
        self.radiusFitToSample.setDecimals(4 if layer_dist_unit in [
            QgsUnitTypes.DistanceKilometers, QgsUnitTypes.
            DistanceNauticalMiles, QgsUnitTypes.DistanceMiles, QgsUnitTypes.
            DistanceDegrees
        ] else 1)
        self.radiusFitToSample.setSingleStep(0.0001 if layer_dist_unit in [
            QgsUnitTypes.DistanceKilometers, QgsUnitTypes.
            DistanceNauticalMiles, QgsUnitTypes.DistanceMiles, QgsUnitTypes.
            DistanceDegrees
        ] else 1)
        self.radiusFitToSample.setValue(self.classification.fit_to_sample)

        # set total samples
        self.QPBar_SamplesNavigation.setMaximum(len(
            self.classification.points))

        # actions for fit and go to current sample
        self.radiusFitToSample.valueChanged.connect(
            lambda: self.show_and_go_to_current_sample(highlight=False))
        self.currentSample.clicked.connect(
            lambda: self.show_and_go_to_current_sample(highlight=True))

        # move through samples
        self.nextSample.clicked.connect(self.next_sample)
        self.nextSampleNotClassified.clicked.connect(
            self.next_sample_not_classified)
        self.previousSample.clicked.connect(self.previous_sample)
        self.previousSampleNotClassified.clicked.connect(
            self.previous_sample_not_classified)

        # dialog buttons box
        self.closeButton.rejected.connect(self.closing)
        # disable enter action
        self.closeButton.button(QDialogButtonBox.Close).setAutoDefault(False)

        # init current point
        self.current_sample_idx = self.classification.current_sample_idx
        self.current_sample = None
        self.set_current_sample()
        # set classification buttons
        self.classification_btns_config = ClassificationButtonsConfig(
            self.classification.buttons_config)
        self.create_classification_buttons(
            buttons_config=self.classification.buttons_config)
        self.QPBtn_SetClassification.clicked.connect(
            self.open_set_classification_dialog)
        self.QPBtn_unclassifySampleButton.clicked.connect(
            self.unclassify_sample)

        # create dynamic size of the view render widgets windows
        # inside the grid with columns x rows divide by splitters
        h_splitters = []
        view_widgets = []
        for row in range(self.classification.grid_rows):
            splitter = QSplitter(Qt.Horizontal)
            for column in range(self.classification.grid_columns):
                new_view_widget = ClassificationViewWidget()
                splitter.addWidget(new_view_widget)
                h_splitters.append(splitter)
                view_widgets.append(new_view_widget)
        v_splitter = QSplitter(Qt.Vertical)
        for splitter in h_splitters:
            v_splitter.addWidget(splitter)
        # add to classification dialog
        self.widget_view_windows.layout().addWidget(v_splitter)
        # save instances
        ClassificationDialog.view_widgets = view_widgets
        # setup view widget
        [
            view_widget.setup_view_widget(sampling_layer)
            for view_widget in ClassificationDialog.view_widgets
        ]
        for idx, view_widget in enumerate(ClassificationDialog.view_widgets):
            view_widget.id = idx
        # set the label names for each view
        for num_view, view_widget in enumerate(
                ClassificationDialog.view_widgets):
            view_widget.QLabel_ViewID.setText("View {}:".format(num_view + 1))
        # restore view widgets status
        for config_id, view_config in self.classification.view_widgets_config.items(
        ):
            for view_widget in ClassificationDialog.view_widgets:
                if config_id == view_widget.id:
                    view_widget = ClassificationDialog.view_widgets[config_id]
                    # select the file for this view widget if exists and is loaded in Qgis
                    layer_name = view_config["layer_name"]
                    if not layer_name and view_config["render_file_path"]:
                        layer_name = os.path.splitext(
                            os.path.basename(
                                view_config["render_file_path"]))[0]
                    file_index = view_widget.QCBox_RenderFile.findText(
                        layer_name, Qt.MatchFixedString)

                    if file_index != -1:
                        # select layer if exists in Qgis
                        with block_signals_to(view_widget.QCBox_RenderFile):
                            view_widget.QCBox_RenderFile.setCurrentIndex(
                                file_index)
                    elif view_config["render_file_path"] and os.path.isfile(
                            view_config["render_file_path"]):
                        # load file and select in view if this exists and not load in Qgis
                        load_and_select_filepath_in(
                            view_widget.QCBox_RenderFile,
                            view_config["render_file_path"],
                            layer_name=layer_name)
                    elif view_config["render_file_path"] and not os.path.isfile(
                            view_config["render_file_path"]):
                        self.MsgBar.pushMessage(
                            "Could not to load the layer '{}' in the view {}: no such file {}"
                            .format(
                                layer_name,
                                "'{}'".format(view_config["view_name"]) if
                                view_config["view_name"] else view_widget.id +
                                1, view_config["render_file_path"]),
                            level=Qgis.Warning,
                            duration=-1)
                    else:
                        self.MsgBar.pushMessage(
                            "Could not to load the layer '{}' in the view {} (for network layers use save/load a Qgis project)"
                            .format(
                                layer_name,
                                "'{}'".format(view_config["view_name"]) if
                                view_config["view_name"] else view_widget.id +
                                1),
                            level=Qgis.Warning,
                            duration=-1)
                    # TODO: restore size by view widget
                    # view_widget.resize(*view_config["view_size"])
                    view_widget.QLabel_ViewName.setText(
                        view_config["view_name"])
                    view_widget.scaleFactor.setValue(
                        view_config["scale_factor"])
                    # active render layer in canvas
                    view_widget.set_render_layer(
                        view_widget.QCBox_RenderFile.currentLayer())
Пример #6
0
def restore(file_path):
    from AcATaMa.gui.acatama_dockwidget import AcATaMaDockWidget as AcATaMa

    # load the yaml file
    import yaml
    with open(file_path, 'r') as yaml_file:
        try:
            yaml_config = yaml.load(yaml_file, Loader=yaml.FullLoader)
        except yaml.YAMLError as err:
            iface.messageBar().pushMessage("AcATaMa", "Error while read the AcATaMa configuration file: {}".format(err),
                                           level=Qgis.Critical)
            return

    # ######### general configuration ######### #
    if "general" in yaml_config:
        AcATaMa.dockwidget.tabWidget.setCurrentIndex(yaml_config["general"]["tab_activated"])

    # restore the thematic raster
    if yaml_config["thematic_raster"]["path"]:
        # thematic raster
        load_and_select_filepath_in(AcATaMa.dockwidget.QCBox_ThematicRaster,
                                    yaml_config["thematic_raster"]["path"])
        AcATaMa.dockwidget.select_thematic_raster(AcATaMa.dockwidget.QCBox_ThematicRaster.currentLayer())
        # band number
        if "band" in yaml_config["thematic_raster"]:
            AcATaMa.dockwidget.QCBox_band_ThematicRaster.setCurrentIndex(yaml_config["thematic_raster"]["band"] - 1)
        # nodata
        AcATaMa.dockwidget.nodata_ThematicRaster.setValue(yaml_config["thematic_raster"]["nodata"])

    # ######### classification configuration ######### #
    # restore the classification settings
    # load the sampling file save in yaml config
    sampling_filepath = yaml_config["sampling_layer"]
    if os.path.isfile(sampling_filepath):
        sampling_layer = load_and_select_filepath_in(AcATaMa.dockwidget.QCBox_SamplingFile, sampling_filepath)
        classification = Classification(sampling_layer)

        AcATaMa.dockwidget.grid_columns.setValue(yaml_config["grid_view_widgets"]["columns"])
        AcATaMa.dockwidget.grid_rows.setValue(yaml_config["grid_view_widgets"]["rows"])
        classification.dialog_size = yaml_config["dialog_size"]
        classification.grid_columns = yaml_config["grid_view_widgets"]["columns"]
        classification.grid_rows = yaml_config["grid_view_widgets"]["rows"]
        classification.current_sample_idx = yaml_config["current_sample_idx"]
        classification.fit_to_sample = yaml_config["fit_to_sample"]
        classification.is_completed = yaml_config["is_completed"]
        # restore the buttons config
        classification.buttons_config = yaml_config["classification_buttons"]
        # restore the view widget config
        classification.view_widgets_config = yaml_config["view_widgets_config"]

        # support load the old format of config file TODO: delete
        for x in classification.view_widgets_config.values():
            if "render_file" in x:
                x["render_file_path"] = x["render_file"]
                del x["render_file"]
            if "name" in x:
                x["view_name"] = x["name"]
                del x["name"]
            if "layer_name" not in x:
                x["layer_name"] = None

        # restore the samples order
        points_ordered = []
        for shape_id in yaml_config["points_order"]:
            # point saved exist in shape file
            if shape_id in [p.shape_id for p in classification.points]:
                points_ordered.append([p for p in classification.points if p.shape_id == shape_id][0])
        # added new point inside shape file that not exists in yaml config
        for new_point_id in set([p.shape_id for p in classification.points]) - set(yaml_config["points_order"]):
            points_ordered.append([p for p in classification.points if p.shape_id == new_point_id][0])
        # reassign points loaded and ordered
        classification.points = points_ordered
        # restore point status classification
        for status in yaml_config["points"].values():
            if status["shape_id"] in [p.shape_id for p in classification.points]:
                point_to_restore = [p for p in classification.points if p.shape_id == status["shape_id"]][0]
                point_to_restore.classif_id = status["classif_id"]
                if point_to_restore.classif_id is not None:
                    point_to_restore.is_classified = True
        # update the status and labels plugin with the current sampling classification
        classification.reload_classification_status()
        AcATaMa.dockwidget.update_the_status_of_classification()
        # define if this classification was made with thematic classes
        if classification.buttons_config and yaml_config["thematic_raster"]["path"] and \
                True in [bc["thematic_class"] is not None and bc["thematic_class"] != "" for bc in classification.buttons_config.values()]:
            classification.with_thematic_classes = True
    else:
        classification = None

    # ######### accuracy assessment ######### #
    # restore accuracy assessment settings
    # support load the old format of config file TODO: delete
    if "accuracy_assessment_sampling_file" in yaml_config and yaml_config["accuracy_assessment_sampling_file"]:
        load_and_select_filepath_in(AcATaMa.dockwidget.QCBox_SamplingFile_AA,
                                    yaml_config["accuracy_assessment_sampling_file"])
    if "accuracy_assessment_sampling_type" in yaml_config:
        AcATaMa.dockwidget.QCBox_SamplingType_AA.setCurrentIndex(yaml_config["accuracy_assessment_sampling_type"])

    if "accuracy_assessment_dialog" in yaml_config and classification:
        from AcATaMa.core.accuracy_assessment import AccuracyAssessment
        accuracy_assessment = AccuracyAssessment(classification)
        area_unit, success = QgsUnitTypes.stringToAreaUnit(yaml_config["accuracy_assessment_dialog"]["area_unit"])
        if success:
            accuracy_assessment.area_unit = area_unit
        accuracy_assessment.z_score = yaml_config["accuracy_assessment_dialog"]["z_score"]
        accuracy_assessment.csv_separator = yaml_config["accuracy_assessment_dialog"]["csv_separator"]
        accuracy_assessment.csv_decimal = yaml_config["accuracy_assessment_dialog"]["csv_decimal"]
        classification.accuracy_assessment = accuracy_assessment
    # support load the old format end here

    if "accuracy_assessment" in yaml_config and "sampling_file" in yaml_config["accuracy_assessment"]:
        load_and_select_filepath_in(AcATaMa.dockwidget.QCBox_SamplingFile_AA,
                                    yaml_config["accuracy_assessment"]["sampling_file"])
    if "accuracy_assessment" in yaml_config and "sampling_type" in yaml_config["accuracy_assessment"]:
        AcATaMa.dockwidget.QCBox_SamplingType_AA.setCurrentIndex(yaml_config["accuracy_assessment"]["sampling_type"])

    if "accuracy_assessment" in yaml_config and "dialog" in yaml_config["accuracy_assessment"] and classification:
        from AcATaMa.core.accuracy_assessment import AccuracyAssessment
        accuracy_assessment = AccuracyAssessment(classification)
        area_unit, success = QgsUnitTypes.stringToAreaUnit(yaml_config["accuracy_assessment"]["dialog"]["area_unit"])
        if success:
            accuracy_assessment.area_unit = area_unit
        accuracy_assessment.z_score = yaml_config["accuracy_assessment"]["dialog"]["z_score"]
        accuracy_assessment.csv_separator = yaml_config["accuracy_assessment"]["dialog"]["csv_separator"]
        accuracy_assessment.csv_decimal = yaml_config["accuracy_assessment"]["dialog"]["csv_decimal"]
        classification.accuracy_assessment = accuracy_assessment

    # reload sampling file status in accuracy assessment
    AcATaMa.dockwidget.set_sampling_file_accuracy_assessment()