def startSimulation(self): self.simulator = Simulator(self.inputs["initial"], self.inputs["factors"].values(), self.inputs["model"], self.inputs["crosstab"] ) self.simulator.moveToThread(self.workThread) self.workThread.started.connect(self.simulator.sim) self.simulator.rangeChanged.connect(self.__setProgressRange) self.simulator.updateProgress.connect(self.__showProgress) self.simulator.processFinished.connect(self.simulationDone) self.simulator.processFinished.connect(self.workThread.quit) self.workThread.start()
class MolusceDialog(QDialog, Ui_Dialog): def __init__(self, iface): QDialog.__init__(self) self.setupUi(self) self.iface = iface self.modelWidget = None self.workThread = QThread() # Here we'll store all input rasters and then use this dictionary instead of # creating Raster objects each time when we need it. Be careful when processing # large rasters, you can out of memory! # Dictionary has next struct: # {"initial" : Raster(), # "final" : Raster(), # "factors" : {"layerId_1" : Raster(), # "layerId_2" : Raster(), # ... # "layerId_N" : Raster() # }, # "bandCount" : 0, # "model" : object # } # Layer ids are necessary to handle factors changes (e.g. adding new or removing # existing factor) self.inputs = dict() self.settings = QSettings("NextGIS", "MOLUSCE") self.grpSampling.setSettings(self.settings) # connect signals and slots self.btnSetInitialRaster.clicked.connect(self.setInitialRaster) self.btnSetFinalRaster.clicked.connect(self.setFinalRaster) self.btnAddFactor.clicked.connect(self.addFactor) self.btnRemoveFactor.clicked.connect(self.removeFactor) self.btnRemoveAllFactors.clicked.connect(self.removeAllFactors) self.btnUpdateStatistics.clicked.connect(self.updateStatisticsTable) self.btnCreateChangeMap.clicked.connect(self.createChangeMap) self.cmbSamplingMode.currentIndexChanged.connect(self.__modeChanged) self.cmbSimulationMethod.currentIndexChanged.connect(self.__modelChanged) self.chkRiskFunction.toggled.connect(self.__toggleLineEdit) self.chkRiskValidation.toggled.connect(self.__toggleLineEdit) self.chkMonteCarlo.toggled.connect(self.__toggleLineEdit) self.chkReuseMatrix.toggled.connect(self.__toggleLineEdit) self.btnSelectRiskFunction.clicked.connect(self.__selectSimulationOutput) self.btnSelectRiskValidation.clicked.connect(self.__selectSimulationOutput) self.btnSelectMonteCarlo.clicked.connect(self.__selectSimulationOutput) #self.btnSelectMatrix.clicked.connect() self.btnStartSimulation.clicked.connect(self.startSimulation) self.manageGui() self.__logMessage(self.tr("Start logging")) def manageGui(self): self.restoreGeometry(self.settings.value("/ui/geometry").toByteArray()) self.tabWidget.setCurrentIndex(0) self.__populateLayers() self.__populateSamplingModes() self.__populateSimulationMethods() self.__readSettings() def closeEvent(self, e): self.settings.setValue("/ui/geometry", QVariant(self.saveGeometry())) self.__writeSettings() QDialog.closeEvent(self, e) def setInitialRaster(self): layerName = self.lstLayers.selectedItems()[0].text() self.initRasterId = self.lstLayers.selectedItems()[0].data(Qt.UserRole) self.leInitRasterName.setText(layerName) rx = QRegExp("(19|2\d)\d\d") pos = rx.indexIn(layerName) year = rx.cap() self.leInitYear.setText(year) self.inputs["initial"] = Raster(unicode(utils.getLayerById(self.initRasterId).source())) self.__logMessage(self.tr("Set intial layer to %1").arg(layerName)) def setFinalRaster(self): layerName = self.lstLayers.selectedItems()[0].text() self.finalRasterId = self.lstLayers.selectedItems()[0].data(Qt.UserRole) self.leFinalRasterName.setText(layerName) rx = QRegExp("(19|2\d)\d\d") pos = rx.indexIn(layerName) year = rx.cap() self.leFinalYear.setText(year) self.inputs["final"] = Raster(unicode(utils.getLayerById(self.finalRasterId).source())) self.__logMessage(self.tr("Set final layer to %1").arg(layerName)) def addFactor(self): layerName = self.lstLayers.selectedItems()[0].text() if len(self.lstFactors.findItems(layerName, Qt.MatchExactly)) > 0: return item = QListWidgetItem(self.lstLayers.selectedItems()[0]) layerId = unicode(item.data(Qt.UserRole).toString()) self.lstFactors.insertItem(self.lstFactors.count() + 1, item) if "factors" in self.inputs: self.inputs["factors"][layerId] = Raster(unicode(utils.getLayerById(layerId).source())) else: d = dict() d[layerId] = Raster(unicode(utils.getLayerById(layerId).source())) self.inputs["factors"] = d self.inputs["bandCount"] = self.__bandCount() self.__logMessage(self.tr("Added factor layer %1").arg(layerName)) def removeFactor(self): layerId = unicode(self.lstFactors.currentItem().data(Qt.UserRole).toString()) layerName = self.lstFactors.currentItem().text() self.lstFactors.takeItem(self.lstFactors.currentRow()) del self.inputs["factors"][layerId] self.inputs["bandCount"] = self.__bandCount() self.__logMessage(self.tr("Removed factor layer %1").arg(layerName)) def removeAllFactors(self): self.lstFactors.clear() del self.inputs["factors"] del self.inputs["bandCount"] self.__logMessage(self.tr("Factors list cleared")) def updateStatisticsTable(self): self.inputs["crosstab"] = CrossTableManager(self.inputs["initial"], self.inputs["final"]) # class statistics stat = self.inputs["crosstab"].getTransitionStat() dimensions = len(stat["init"]) self.tblStatistics.clear() self.tblStatistics.setRowCount(dimensions) self.tblStatistics.setColumnCount(6) labels = [self.leInitYear.text(), self.leFinalYear.text(), u"Δ", self.leInitYear.text() + " %", self.leFinalYear.text() + " %", u"Δ %" ] self.tblStatistics.setHorizontalHeaderLabels(labels) self.__addTableColumn(0, stat["init"]) self.__addTableColumn(1, stat["final"]) self.__addTableColumn(2, stat["deltas"]) self.__addTableColumn(3, stat["initPerc"]) self.__addTableColumn(4, stat["finalPerc"]) self.__addTableColumn(5, stat["deltasPerc"]) self.tblStatistics.resizeRowsToContents() self.tblStatistics.resizeColumnsToContents() # transitional matrix transition = self.inputs["crosstab"].getTransitionMatrix() dimensions = len(transition) self.tblTransMatrix.clear() self.tblTransMatrix.setRowCount(dimensions) self.tblTransMatrix.setColumnCount(dimensions) for row in xrange(0, dimensions): for col in xrange(0, dimensions): item = QTableWidgetItem(unicode(transition[row, col])) self.tblTransMatrix.setItem(row, col, item) self.tblTransMatrix.resizeRowsToContents() self.tblTransMatrix.resizeColumnsToContents() self.__logMessage(self.tr("Class statistics and transition matrix are updated")) def createChangeMap(self): fileName = utils.saveRasterDialog(self, self.settings, self.tr("Save change map"), self.tr("GeoTIFF (*.tif *.tiff *.TIF *.TIFF)") ) if fileName.isEmpty(): return self.inputs["changeMapName"] = unicode(fileName) if ("initial" in self.inputs) and ("final" in self.inputs): self.analyst = AreaAnalyst(self.inputs["initial"], self.inputs["final"]) self.analyst.moveToThread(self.workThread) self.workThread.started.connect(self.analyst.getChangeMap) self.analyst.rangeChanged.connect(self.__setProgressRange) self.analyst.updateProgress.connect(self.__showProgress) self.analyst.processFinished.connect(self.changeMapDone) self.analyst.processFinished.connect(self.workThread.quit) self.workThread.start() def changeMapDone(self, raster): self.inputs["changeMap"] = raster self.inputs["changeMap"].save(self.inputs["changeMapName"]) self.__addRasterToCanvas(self.inputs["changeMapName"]) del self.inputs["changeMapName"] self.workThread.started.disconnect(self.analyst.getChangeMap) self.analyst.rangeChanged.disconnect(self.__setProgressRange) self.analyst.updateProgress.disconnect(self.__showProgress) self.analyst.processFinished.disconnect(self.changeMapDone) self.analyst.processFinished.disconnect(self.workThread.quit) self.analyst = None self.__restoreProgressState() def startSimulation(self): self.simulator = Simulator(self.inputs["initial"], self.inputs["factors"].values(), self.inputs["model"], self.inputs["crosstab"] ) self.simulator.moveToThread(self.workThread) self.workThread.started.connect(self.simulator.sim) self.simulator.rangeChanged.connect(self.__setProgressRange) self.simulator.updateProgress.connect(self.__showProgress) self.simulator.processFinished.connect(self.simulationDone) self.simulator.processFinished.connect(self.workThread.quit) self.workThread.start() def simulationDone(self): if self.chkRiskFunction.isChecked(): if not self.leRiskFunctionPath.text().isEmpty(): res = self.simulator.getConfidence() res.save(unicode(self.leRiskFunctionPath.text())) else: self.__logMessage(self.tr("Output path for risk function map is not set. Skipping this step")) if self.chkRiskValidation.isChecked(): if not self.leRiskValidationPath.text().isEmpty(): res = self.simulator.errorMap(self.inputs["final"]) res.save(unicode(self.leRiskValidationPath.text())) else: self.__logMessage(self.tr("Output path for estimation errors for risk classes map is not set. Skipping this step")) if self.chkMonteCarlo.isChecked(): if not self.leMonteCarloPath.text().isEmpty(): res = self.simulator.getState() res.save(unicode(self.leMonteCarloPath.text())) else: self.__logMessage(self.tr("Output path for simulated risk map is not set. Skipping this step")) self.workThread.started.disconnect(self.simulator.sim) self.simulator.rangeChanged.disconnect(self.__setProgressRange) self.simulator.updateProgress.disconnect(self.__showProgress) self.simulator.processFinished.disconnect(self.simulationDone) self.simulator.processFinished.disconnect(self.workThread.quit) self.simulator = None self.__restoreProgressState() # ****************************************************************************** def __populateLayers(self): layers = utils.getRasterLayers() relations = self.iface.legendInterface().groupLayerRelationship() for layer in sorted(layers.iteritems(), cmp=locale.strcoll, key=operator.itemgetter(1)): groupName = utils.getLayerGroup(relations, layer[0]) item = QListWidgetItem() if groupName == "": item.setText(layer[1]) item.setData(Qt.UserRole, layer[0]) else: item.setText(QString("%1 - %2").arg(layer[1]).arg(groupName)) item.setData(Qt.UserRole, layer[0]) self.lstLayers.addItem(item) def __populateSimulationMethods(self): self.cmbSimulationMethod.addItems([ self.tr("Logistic Regression"), self.tr("Artificial Neural Network"), self.tr("Weights of Evidence"), self.tr("Multi Criteria Evaluation") ]) def __populateSamplingModes(self): self.cmbSamplingMode.addItem(self.tr("All"), 0) self.cmbSamplingMode.addItem(self.tr("Normal"), 1) self.cmbSamplingMode.addItem(self.tr("Balanced"), 2) def __modeChanged(self, index): mode = self.cmbSamplingMode.itemData(index).toInt()[0] if mode == 0: self.inputs["samplingMode"] = "All" elif mode == 1: self.inputs["samplingMode"] = "Normal" elif mode == 2: self.inputs["samplingMode"] = "Balanced" def __modelChanged(self): if self.modelWidget is not None: self.widgetStackMethods.removeWidget(self.modelWidget) self.modelWidget = None del self.modelWidget modelName = self.cmbSimulationMethod.currentText() if modelName == self.tr("Logistic Regression"): self.modelWidget = logisticregressionwidget.LogisticRegressionWidget(self) elif modelName == self.tr("Artificial Neural Network"): self.modelWidget = neuralnetworkwidget.NeuralNetworkWidget(self) elif modelName == self.tr("Weights of Evidence"): self.modelWidget = weightofevidencewidget.WeightOfEvidenceWidget(self) elif modelName == self.tr("Multi Criteria Evaluation"): self.modelWidget = multicriteriaevaluationwidget.MultiCriteriaEvaluationWidget(self) self.widgetStackMethods.addWidget(self.modelWidget) self.widgetStackMethods.setCurrentWidget(self.modelWidget) def __toggleLineEdit(self, checked): senderName = self.sender().objectName() if senderName == "chkRiskFunction": if checked: self.leRiskFunctionPath.setEnabled(True) self.btnSelectRiskFunction.setEnabled(True) else: self.leRiskFunctionPath.setEnabled(False) self.btnSelectRiskFunction.setEnabled(False) elif senderName == "chkRiskValidation": if checked: self.leRiskValidationPath.setEnabled(True) self.btnSelectRiskValidation.setEnabled(True) else: self.leRiskValidationPath.setEnabled(False) self.btnSelectRiskValidation.setEnabled(False) elif senderName == "chkMonteCarlo": if checked: self.leMonteCarloPath.setEnabled(True) self.btnSelectMonteCarlo.setEnabled(True) self.lblIterations.setEnabled(True) self.spnIterations.setEnabled(True) else: self.leMonteCarloPath.setEnabled(False) self.btnSelectMonteCarlo.setEnabled(False) self.lblIterations.setEnabled(False) self.spnIterations.setEnabled(False) elif senderName == "chkReuseMatrix": if checked: self.leMatrixPath.setEnabled(True) self.btnSelectMatrix.setEnabled(True) else: self.leMatrixPath.setEnabled(False) self.btnSelectMatrix.setEnabled(False) def __selectSimulationOutput(self): senderName = self.sender().objectName() fileName = utils.saveRasterDialog(self, self.settings, self.tr("Save file"), self.tr("GeoTIFF (*.tif *.tiff *.TIF *.TIFF)") ) if fileName.isEmpty(): return if senderName == "btnSelectRiskFunction": self.leRiskFunctionPath.setText(fileName) elif senderName == "btnSelectRiskValidation": self.leRiskValidationPath.setText(fileName) elif senderName == "btnSelectMonteCarlo": self.leMonteCarloPath.setText(fileName) def __logMessage(self, message): self.txtMessages.append(QString("[%1] %2") .arg(datetime.datetime.now().strftime("%a %b %d %Y %H:%M:%S")) .arg(message) ) def __addTableColumn(self, col, values): dimensions = len(values) for r in xrange(0, dimensions): item = QTableWidgetItem(unicode(values[r])) self.tblStatistics.setItem(r, col, item) def __addRasterToCanvas(self, filePath): layer = QgsRasterLayer(filePath, QFileInfo(filePath).baseName()) if layer.isValid(): QgsMapLayerRegistry.instance().addMapLayers([layer]) else: self.__logMessage(self.tr("Can't load raster %1").arg(filePath)) def __bandCount(self): bands = 0 for k, v in self.inputs["factors"].iteritems(): bands += len(v.bands) return bands def __setProgressRange(self, message, maxValue): self.progressBar.setFormat(message) self.progressBar.setRange(0, maxValue) def __showProgress(self): self.progressBar.setValue(self.progressBar.value() + 1) def __restoreProgressState(self): self.progressBar.setFormat("%p%") self.progressBar.setRange(0, 1) self.progressBar.setValue(0) def __writeSettings(self): # samples and model tab self.settings.setValue("ui/samplingMode", self.cmbSamplingMode.itemData(self.cmbSamplingMode.currentIndex()).toInt()[0]) self.settings.setValue("ui/samplesCount", self.spnSamplesCount.value()) # simulation tab self.settings.setValue("ui/createRiskFunction", self.chkRiskFunction.isChecked()) self.settings.setValue("ui/createRiskValidation", self.chkRiskValidation.isChecked()) self.settings.setValue("ui/createMonteCarlo", self.chkMonteCarlo.isChecked()) self.settings.setValue("ui/monteCarloIterations", self.spnIterations.value()) self.settings.setValue("ui/reuseMatrix", self.chkReuseMatrix.isChecked()) def __readSettings(self): # samples and model tab samplingMode = self.settings.value("ui/samplingMode", 0).toInt()[0] self.cmbSamplingMode.setCurrentIndex(self.cmbSamplingMode.findData(samplingMode)) self.spnSamplesCount.setValue(self.settings.value("ui/samplesCount", 10000).toInt()[0]) # simulation tab self.chkRiskFunction.setChecked(self.settings.value("ui/createRiskFunction", False).toBool()) self.chkRiskValidation.setChecked(self.settings.value("ui/createRiskValidation", False).toBool()) self.chkMonteCarlo.setChecked(self.settings.value("ui/createMonteCarlo", False).toBool()) self.spnIterations.setValue(self.settings.value("ui/monteCarloIterations", 1).toInt()[0]) self.chkReuseMatrix.setChecked(self.settings.value("ui/reuseMatrix", False).toBool())