def __init__(self, dataset, mainWindow, process, pipe): """ Initialize the controller for the main window. :param dataset: Dataset model. :param mainWindow: MainWindow view. :param process: Worker subprocess. :param pipe: Message pipe for the worker subprocess. """ self.spatialData = dataset.spatialData self.temporalData = dataset.temporalData self.auxiliaryData = dataset.auxiliaryData self.selectedSpecies = dataset.selectedSpecies self.map = LeafletMap(dataset, "Landscape") self.plot = ScatterPlot(dataset) spatial = SpatialAnalysisWidget(self.map.webView) temporal = TemporalAnalysisWidget(self.plot.mplCanvas) cooccurrence = CooccurrenceAnalysisWidget() self.correlationTable = CorrelationTable(dataset, spatial, temporal) self.cooccurrenceCalculation = CooccurrenceCalculation( dataset, cooccurrence, process, pipe ) self.mainWindow = mainWindow self.mainWindow.setupWidgets( spatial, temporal, cooccurrence, self, self.cooccurrenceCalculation ) self.mainWindow.show()
class MainAction: def __init__(self, dataset, mainWindow, process, pipe): """ Initialize the controller for the main window. :param dataset: Dataset model. :param mainWindow: MainWindow view. :param process: Worker subprocess. :param pipe: Message pipe for the worker subprocess. """ self.spatialData = dataset.spatialData self.temporalData = dataset.temporalData self.auxiliaryData = dataset.auxiliaryData self.selectedSpecies = dataset.selectedSpecies self.map = LeafletMap(dataset, "Landscape") self.plot = ScatterPlot(dataset) spatial = SpatialAnalysisWidget(self.map.webView) temporal = TemporalAnalysisWidget(self.plot.mplCanvas) cooccurrence = CooccurrenceAnalysisWidget() self.correlationTable = CorrelationTable(dataset, spatial, temporal) self.cooccurrenceCalculation = CooccurrenceCalculation( dataset, cooccurrence, process, pipe ) self.mainWindow = mainWindow self.mainWindow.setupWidgets( spatial, temporal, cooccurrence, self, self.cooccurrenceCalculation ) self.mainWindow.show() # noinspection PyCallByClass, PyTypeChecker, PyArgumentList, PyBroadException def importData(self): """ Import data from a Darwin Core Archive (DwC-A) file. |br| Store them in ``Dataset``. :return: None. """ if self.spatialData: title = "Dataset Already Imported" content = "To import new data, please clear data first." self.mainWindow.alert(title, content, 3) return title, extension = "Select a DwC-A File", "DwC-A File (*.zip)" filename = self.mainWindow.openFile(title, extension) if filename: try: archiveData, archiveMeta = DatasetProcessor.extractDarwinCoreArchive(filename) if archiveMeta["coreType"] not in Dataset.supportedCores: title = "Unsupported DwC Type" content = ( "The provided file has core type of " + archiveMeta["coreType"] + ".\n" "This program only support " + ", ".join(Dataset.supportedCores) + "." ) self.mainWindow.alert(title, content, 3) return columns = [ ("individualCount", True), ("eventDate", True), ("decimalLatitude", True), ("decimalLongitude", True), ("scientificName", True), ("vernacularName", False) ] try: dataList = DatasetProcessor.extractCsv(archiveData, archiveMeta, columns) except ValueError as e: title = "Invalid DwC-A File" content = str(e) + "\nPlease select a DwC-A file with such field." self.mainWindow.alert(title, content, 3) return except: title = "Invalid DwC-A File" content = ( "The provided file is either not in DwC-A format or corrupted.\n" "Please select a valid one.\n\n" ) self.mainWindow.alert(title, content + format_exc(), 3) return for r in dataList: try: r0int = int(r[0]) r1datetime = parse(r[1]) r2float = float(r[2]) r3float = float(r[3]) if not r[4]: raise ValueError("Field \"scientificName\" is empty.") except: title = "Invalid Record Found" content = "The following record is invalid and will be ignored:\n" self.mainWindow.alert(title, content + pformat(r), 2) else: self.spatialData[r[4]] = ((r2float, r3float), r0int) self.temporalData[r[4]] = (r1datetime, r0int) self.auxiliaryData[r[4]] = r[5] title = "Dataset Successfully Imported" content = "{:,d} records have been loaded.".format(len(dataList)) self.mainWindow.alert(title, content, 0) # noinspection PyTypeChecker def setFilters(self): """ Only leave filtered data in ``Dataset``. :return: None. """ if not self.spatialData: title, content = "Empty Dataset", "Please import data first." self.mainWindow.alert(title, content, 3) else: xCoordinates = [n[0][1] for m in self.spatialData.values() for n in m] yCoordinates = [n[0][0] for m in self.spatialData.values() for n in m] timestamps = [n[0] for m in self.temporalData.values() for n in m] xCoordinateMinMax = (min(xCoordinates), max(xCoordinates)) yCoordinateMinMax = (min(yCoordinates), max(yCoordinates)) timestampMinMax = (min(timestamps), max(timestamps)) dialog = SetFiltersDialog(xCoordinateMinMax, yCoordinateMinMax, timestampMinMax) dialog.exec_() if not dialog.xCoordinateMinMax: return for k in list(self.spatialData.keys()): for i, u in enumerate(self.spatialData[k]): v = self.temporalData[k][i] if ( dialog.xCoordinateMinMax[0] <= u[0][1] <= dialog.xCoordinateMinMax[1] and dialog.yCoordinateMinMax[0] <= u[0][0] <= dialog.yCoordinateMinMax[1] and dialog.timestampMinMax[0] <= v[0] <= dialog.timestampMinMax[1] ): break else: if k in self.selectedSpecies: self.removeSpecies(k + " " + self.auxiliaryData[k]) del self.spatialData[k] del self.temporalData[k] del self.auxiliaryData[k] self.cooccurrenceCalculation.halt() self.plot.resetCache() length = len([n for m in self.spatialData.values() for n in m]) title = "Filter Result" content = "{:,d} records matches the specified range.".format(length) self.mainWindow.alert(title, content, 0) # noinspection PyCallByClass, PyTypeChecker, PyArgumentList def addSpecies(self): """ Select a species from ``Dataset.spatialData``, append it to ``Dataset.selectedSpecies``. :return: None. """ if not self.spatialData: title, content = "Empty Dataset", "Please import data first." self.mainWindow.alert(title, content, 3) elif not Species.available(): title = "Too Many Species" content = ("Selecting more than " + str(Species.nColor) + " species is not supported.") self.mainWindow.alert(title, content, 3) else: species = [(k, self.auxiliaryData[k]) for k in self.spatialData.keys() if k not in self.selectedSpecies] dialog = AddSpeciesDialog(species) dialog.exec_() if dialog.newSpecies: newSpecies, vernacularName = dialog.newSpecies self.selectedSpecies[newSpecies] = Species() newColor = self.selectedSpecies[newSpecies].color self.mainWindow.addSpeciesToLayout(newSpecies, vernacularName, newColor) self.map.add(newSpecies) self.map.refresh() self.plot.rebuild() self.correlationTable.add(newSpecies) def removeSpecies(self, oldSpecies): """ Remove the specified species from ``Dataset.selectedSpecies``. :param oldSpecies: Name of the old species to be removed. :return: None. """ oldSpeciesShort = oldSpecies for k in self.selectedSpecies.keys(): if oldSpecies.startswith(k): oldSpeciesShort = k del self.selectedSpecies[k] break self.mainWindow.removeSpeciesFromLayout(oldSpecies) self.map.remove() self.map.refresh() self.plot.rebuild() self.correlationTable.remove(oldSpeciesShort) def clearData(self): """ Clear ``Dataset``. :return: None. """ if not self.spatialData: title, content = "Empty Dataset", "Please import data first." self.mainWindow.alert(title, content, 3) else: self.spatialData.clear() self.temporalData.clear() self.auxiliaryData.clear() self.selectedSpecies.clear() self.mainWindow.removeSpeciesFromLayout() self.map.rebuild() self.map.refresh() self.plot.resetCache() self.plot.rebuild() self.correlationTable.remove() self.cooccurrenceCalculation.halt() # noinspection PyCallByClass, PyTypeChecker, PyArgumentList def about(self): """ Show information about this program. :return: None. """ title = "About Biodiversity Analysis" content = Dataset.license() self.mainWindow.alert(title, content, 4)