Ejemplo n.º 1
0
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface

        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'AcATaMa_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        print("** INITIALIZING AcATaMa")

        self.menu_name_plugin = self.tr("Accuracy Assessment of Thematic Maps")
        self.pluginIsActive = False
        self.dockwidget = None

        self.about_dialog = AboutDialog()
Ejemplo n.º 2
0
class AcATaMa(object):
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface

        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'AcATaMa_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        print("** INITIALIZING AcATaMa")

        self.menu_name_plugin = self.tr("Accuracy Assessment of Thematic Maps")
        self.pluginIsActive = False
        self.dockwidget = None

        self.about_dialog = AboutDialog()

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate("AcATaMa", message)

    def initGui(self):
        ### Main dockwidget menu
        # Create action that will start plugin configuration
        icon_path = ':/plugins/AcATaMa/icons/acatama.svg'
        self.dockable_action = QAction(QIcon(icon_path), "AcATaMa",
                                       self.iface.mainWindow())
        # connect the action to the run method
        self.dockable_action.triggered.connect(self.run)
        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.dockable_action)
        self.iface.addPluginToMenu(self.menu_name_plugin, self.dockable_action)

        # Plugin info
        # Create action that will start plugin configuration
        icon_path = ':/plugins/AcATaMa/icons/about.svg'
        self.about_action = QAction(QIcon(icon_path), self.tr('About'),
                                    self.iface.mainWindow())
        # connect the action to the run method
        self.about_action.triggered.connect(self.about)
        # Add toolbar button and menu item
        self.iface.addPluginToMenu(self.menu_name_plugin, self.about_action)

    def about(self):
        self.about_dialog.show()

    #--------------------------------------------------------------------------

    def run(self):
        """Run method that loads and starts the plugin"""

        if not self.pluginIsActive:
            self.pluginIsActive = True

            #print "** STARTING AcATaMa"

            # dockwidget may not exist if:
            #    first run of plugin
            #    removed on close (see self.onClosePlugin method)
            if self.dockwidget == None:
                # Create the dockwidget (after translation) and keep reference
                self.dockwidget = AcATaMaDockWidget()

            # connect to provide cleanup on closing of dockwidget
            self.dockwidget.closingPlugin.connect(self.onClosePlugin)
            # reload
            self.dockwidget.QPBtn_PluginClearReload.clicked.connect(
                self.clear_reload_plugin)

            # show the dockwidget
            # TODO: fix to allow choice of dock location
            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
            self.dockwidget.show()

    #--------------------------------------------------------------------------

    def onClosePlugin(self):
        """Cleanup necessary items here when plugin dockwidget is closed"""
        print("** CLOSING AcATaMa")
        if ClassificationDialog.is_opened:
            self.dockwidget.classification_dialog.closing()
            self.dockwidget.classification_dialog.reject(is_ok_to_close=True)

        if AccuracyAssessmentDialog.is_opened:
            self.dockwidget.accuracy_assessment_dialog.closing()
            self.dockwidget.accuracy_assessment_dialog.reject(
                is_ok_to_close=True)

        self.removes_temporary_files()

        # disconnects
        self.dockwidget.closingPlugin.disconnect(self.onClosePlugin)

        # remove this statement if dockwidget is to remain
        # for reuse if plugin is reopened
        # Commented next statement since it causes QGIS crashe
        # when closing the docked window:
        # self.dockwidget = None
        self.dockwidget.deleteLater()
        self.dockwidget = None

        self.pluginIsActive = False

        from qgis.utils import reloadPlugin
        reloadPlugin("AcATaMa")

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        print("** UNLOAD AcATaMa")
        self.removes_temporary_files()
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(self.menu_name_plugin,
                                    self.dockable_action)
        self.iface.removePluginMenu(self.menu_name_plugin, self.about_action)
        self.iface.removeToolBarIcon(self.dockable_action)

        if self.dockwidget:
            self.iface.removeDockWidget(self.dockwidget)

    def clear_reload_plugin(self):
        # first prompt
        quit_msg = "Are you sure you want to: clean tmp files, delete unsaved classification, " \
                   "clean all fields and reload plugin?"
        reply = QMessageBox.question(
            None, 'Clear all and reload the AcATaMa plugin.', quit_msg,
            QMessageBox.Yes, QMessageBox.No)
        if reply == QMessageBox.No:
            return

        self.onClosePlugin()
        from qgis.utils import plugins
        plugins["AcATaMa"].run()

    def removes_temporary_files(self):
        if not self.dockwidget:
            return
        # unload all layers instances from Qgis saved in tmp dir
        try:
            d = self.dockwidget.tmp_dir
            files_in_tmp_dir = [
                os.path.join(d, f) for f in os.listdir(d)
                if os.path.isfile(os.path.join(d, f))
            ]
        except:
            files_in_tmp_dir = []

        for file_tmp in files_in_tmp_dir:
            unload_layer(file_tmp)

        # clear self.dockwidget.tmp_dir
        if self.dockwidget.tmp_dir and os.path.isdir(self.dockwidget.tmp_dir):
            shutil.rmtree(self.dockwidget.tmp_dir, ignore_errors=True)
        self.dockwidget.tmp_dir = None

        # clear qgis main canvas
        self.iface.mapCanvas().clearCache()
        self.iface.mapCanvas().refresh()
Ejemplo n.º 3
0
    def setup_gui(self):
        # ######### plugin info ######### #
        self.about_dialog = AboutDialog()
        self.QPBtn_PluginInfo.setText("v{}".format(VERSION))
        self.QPBtn_PluginInfo.clicked.connect(self.about_dialog.show)
        self.QPBtn_PluginDocs.clicked.connect(
            lambda: webbrowser.open("https://smbyc.github.io/AcATaMa"))

        # ######### load thematic raster image ######### #
        # set properties to QgsMapLayerComboBox
        self.QCBox_ThematicRaster.setCurrentIndex(-1)
        self.QCBox_ThematicRaster.setFilters(QgsMapLayerProxyModel.RasterLayer)
        # call to browse the thematic raster file
        self.QPBtn_browseThematicRaster.clicked.connect(
            lambda: self.browser_dialog_to_load_file(
                self.QCBox_ThematicRaster,
                dialog_title=self.tr(
                    "Select the thematic raster image to evaluate"),
                file_filters=self.tr(
                    "Raster files (*.tif *.img);;All files (*.*)")))
        # select and check the thematic raster
        self.QCBox_ThematicRaster.layerChanged.connect(
            self.select_thematic_raster)

        # ######### shape area of interest ######### #
        self.widget_AreaOfInterest.setHidden(True)
        # set properties to QgsMapLayerComboBox
        self.QCBox_AreaOfInterest.setCurrentIndex(-1)
        self.QCBox_AreaOfInterest.setFilters(
            QgsMapLayerProxyModel.PolygonLayer)
        # call to browse the shape area
        self.QPBtn_browseAreaOfInterest.clicked.connect(
            lambda: self.browser_dialog_to_load_file(
                self.QCBox_AreaOfInterest,
                dialog_title=self.tr("Select the vector file"),
                file_filters=self.tr(
                    "Vector files (*.gpkg *.shp);;All files (*.*)")))
        # do clip
        self.QPBtn_ClippingThematic.clicked.connect(
            self.clipping_thematic_raster)

        # ######### create categorical  ######### # TODO
        # self.widget_CategRaster.setHidden(True)
        # # handle connect when the list of layers changed
        # # call to browse the categorical raster
        # self.browseCategRaster.clicked.connect(lambda: self.fileDialog_browse(
        #     self.selectCategRaster,
        #     dialog_title=self.tr("Select the categorical raster file"),
        #     dialog_types=self.tr("Raster files (*.tif *.img);;All files (*.*)"),
        #     layer_type="raster"))

        # ######### simple random sampling ######### #
        self.widget_SimpRSwithCR.setHidden(True)
        # set properties to QgsMapLayerComboBox
        self.QCBox_CategRaster_SimpRS.setCurrentIndex(-1)
        self.QCBox_CategRaster_SimpRS.setFilters(
            QgsMapLayerProxyModel.RasterLayer)
        # call to browse the categorical raster
        self.QPBtn_browseCategRaster_SimpRS.clicked.connect(
            lambda: self.browser_dialog_to_load_file(
                self.QCBox_CategRaster_SimpRS,
                dialog_title=self.tr("Select the categorical raster file"),
                file_filters=self.tr(
                    "Raster files (*.tif *.img);;All files (*.*)")))
        # select and check the categorical raster
        self.QCBox_CategRaster_SimpRS.layerChanged.connect(
            self.select_categorical_raster_SimpRS)
        # generate and random sampling options
        self.widget_generate_SimpRS.generate_sampling_widget_options.setHidden(
            True)
        self.widget_generate_SimpRS.random_sampling_widget_options.setHidden(
            True)
        # save config
        self.widget_generate_SimpRS.widget_save_sampling_config.setHidden(True)
        iface.mapCanvas().layersChanged.connect(
            lambda: self.update_generated_sampling_list_in(
                self.widget_generate_SimpRS.QCBox_SamplingToSave))
        self.widget_generate_SimpRS.QPBtn_SaveSamplingConf.clicked.connect(
            lambda: self.fileDialog_saveSamplingConf(
                self.widget_generate_SimpRS.QCBox_SamplingToSave))
        # generate sampling
        self.widget_generate_SimpRS.QPBtn_GenerateSampling.clicked.connect(
            lambda: do_simple_random_sampling(self))
        # update progress bar limits
        self.numberOfSamples_SimpRS.valueChanged.connect(
            lambda: self.widget_generate_SimpRS.QPBar_GenerateSampling.
            setValue(0))
        self.numberOfSamples_SimpRS.valueChanged.connect(
            self.widget_generate_SimpRS.QPBar_GenerateSampling.setMaximum)

        # ######### stratified random sampling ######### #
        # set properties to QgsMapLayerComboBox
        self.QCBox_CategRaster_StraRS.setCurrentIndex(-1)
        self.QCBox_CategRaster_StraRS.setFilters(
            QgsMapLayerProxyModel.RasterLayer)
        # call to browse the categorical raster
        self.QPBtn_browseCategRaster_StraRS.clicked.connect(
            lambda: self.browser_dialog_to_load_file(
                self.QCBox_CategRaster_StraRS,
                dialog_title=self.tr("Select the categorical raster file"),
                file_filters=self.tr(
                    "Raster files (*.tif *.img);;All files (*.*)")))
        # select and check the categorical raster
        self.QCBox_CategRaster_StraRS.layerChanged.connect(
            self.select_categorical_raster_StraRS)
        self.QCBox_band_CategRaster_StraRS.currentIndexChanged.connect(
            self.reset_StraRS_method)
        self.nodata_CategRaster_StraRS.valueChanged.connect(
            self.reset_StraRS_method)
        # init variable for save tables content
        self.srs_tables = {}
        # fill table of categorical raster
        self.widget_TotalExpectedSE.setHidden(True)
        self.QCBox_StraRS_Method.currentIndexChanged.connect(
            lambda: fill_stratified_sampling_table(self))
        # for each item changed in table, save and update it
        self.TotalExpectedSE.valueChanged.connect(
            lambda: update_stratified_sampling_table(self, "TotalExpectedSE"))
        self.QTableW_StraRS.itemChanged.connect(
            lambda: update_stratified_sampling_table(self, "TableContent"))
        # generate and random sampling options
        self.widget_generate_StraRS.generate_sampling_widget_options.setHidden(
            True)
        self.widget_generate_StraRS.random_sampling_widget_options.setHidden(
            True)
        # save config
        self.widget_generate_StraRS.widget_save_sampling_config.setHidden(True)
        iface.mapCanvas().layersChanged.connect(
            lambda: self.update_generated_sampling_list_in(
                self.widget_generate_StraRS.QCBox_SamplingToSave))
        self.widget_generate_StraRS.QPBtn_SaveSamplingConf.clicked.connect(
            lambda: self.fileDialog_saveSamplingConf(
                self.widget_generate_StraRS.QCBox_SamplingToSave))
        # generate sampling
        self.widget_generate_StraRS.QPBtn_GenerateSampling.clicked.connect(
            lambda: do_stratified_random_sampling(self))

        # disable sampling tab at start
        self.scrollAreaWidgetContents_S.setDisabled(True)

        # ######### Classification sampling tab ######### #
        # set properties to QgsMapLayerComboBox
        self.QCBox_SamplingFile.setCurrentIndex(-1)
        self.QCBox_SamplingFile.setFilters(QgsMapLayerProxyModel.PointLayer)
        # show the classification file settings in plugin when it is selected
        self.QCBox_SamplingFile.layerChanged.connect(
            self.update_the_status_of_classification)
        # call to browse the sampling file
        self.QPBtn_browseSamplingFile.clicked.connect(
            lambda: self.browser_dialog_to_load_file(
                self.QCBox_SamplingFile,
                dialog_title=self.tr(
                    "Select the Sampling points file to classify"),
                file_filters=self.tr(
                    "Vector files (*.gpkg *.shp);;All files (*.*)")))
        # call to reload sampling file
        self.QPBtn_reloadSamplingFile.clicked.connect(
            self.reload_sampling_file)
        # call to load and save classification config
        self.QPBtn_loadClassificationConfig.clicked.connect(
            self.fileDialog_loadClassificationConfig)
        self.QPBtn_saveClassificationConfig.clicked.connect(
            self.fileDialog_saveClassificationConfig)
        # save sampling + classification
        self.QPBtn_saveSamplingClassification.clicked.connect(
            self.fileDialog_saveSamplingClassification)
        # change grid config
        self.grid_columns.valueChanged.connect(
            lambda: self.set_grid_setting("column"))
        self.grid_rows.valueChanged.connect(
            lambda: self.set_grid_setting("row"))
        # disable group box that depends of sampling file
        self.QGBox_SamplingClassification.setDisabled(True)
        self.QGBox_saveSamplingClassified.setDisabled(True)

        # connect the action to the run method
        self.QPBtn_OpenClassificationDialog.clicked.connect(
            self.open_classification_dialog)

        # ######### Accuracy Assessment tab ######### #
        # set properties to QgsMapLayerComboBox
        self.QCBox_SamplingFile_AA.setCurrentIndex(-1)
        self.QCBox_SamplingFile_AA.setFilters(QgsMapLayerProxyModel.PointLayer)
        # set and show the classification file status in AA
        self.QCBox_SamplingFile_AA.layerChanged.connect(
            self.set_sampling_file_accuracy_assessment)
        # compute the AA and open the result dialog
        self.QPBtn_ComputeViewAccurasyAssessment.clicked.connect(
            self.open_accuracy_assessment_results)