Newer
Older
# -*- coding: utf-8 -*-
"""
/***************************************************************************

Benjamin Jakimow
committed
EO Time Series Viewer
copyright : (C) 2017 by HU-Berlin
email : benjamin.jakimow@geo.hu-berlin.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
# noinspection PyPep8Naming

benjamin.jakimow@geo.hu-berlin.de
committed
File "D:\Programs\OSGeo4W\apps\Python27\lib\multiprocessing\managers.py", line
528, in start
self._address = reader.recv()
EOFError

benjamin.jakimow@geo.hu-berlin.de
committed
see https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing
see https://github.com/CleanCut/green/issues/103

benjamin.jakimow@geo.hu-berlin.de
committed
"""

benjamin.jakimow@geo.hu-berlin.de
committed
path = os.path.abspath(os.path.join(sys.exec_prefix, '../../bin/pythonw.exe'))
if os.path.exists(path):
multiprocessing.set_executable(path)
sys.argv = [ None ]
import qgis.utils
from qgis.core import *
from qgis.gui import *

benjamin.jakimow@geo.hu-berlin.de
committed
import qgis.utils
from eotimeseriesviewer.utils import *
from eotimeseriesviewer.timeseries import *
from eotimeseriesviewer.mapcanvas import MapCanvas
from eotimeseriesviewer.profilevisualization import SpectralTemporalVisualization
from eotimeseriesviewer.temporalprofiles import TemporalProfileLayer
from eotimeseriesviewer.mapvisualization import MapView, MapWidget
import eotimeseriesviewer.settings as eotsvSettings
from eotimeseriesviewer import SpectralProfile, SpectralLibrary, SpectralLibraryPanel
from eotimeseriesviewer.externals.qps.maptools import MapTools, CursorLocationMapTool, QgsMapToolSelect, QgsMapToolSelectionHandler
from eotimeseriesviewer.externals.qps.cursorlocationvalue import CursorLocationInfoModel, CursorLocationInfoDock
import eotimeseriesviewer.labeling
EXTRA_SPECLIB_FIELDS = [
QgsField('date', QVariant.String, 'varchar'),
QgsField('doy', QVariant.Int, 'int'),
QgsField('sensor', QVariant.String, 'varchar')
]

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
class AboutDialogUI(QDialog, loadUI('aboutdialog.ui')):
def __init__(self, parent=None):
"""Constructor."""
super(AboutDialogUI, self).__init__(parent)
# Set up the user interface from Designer.
# After setupUI you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

Benjamin Jakimow
committed
self.init()
def init(self):
self.mTitle = self.windowTitle()
self.listWidget.currentItemChanged.connect(lambda: self.setAboutTitle())
self.setAboutTitle()
# page About
from eotimeseriesviewer import PATH_LICENSE, __version__, PATH_CHANGELOG, PATH_ABOUT
self.labelVersion.setText('{}'.format(__version__))
def readTextFile(path):
if os.path.isfile(path):
f = open(path, encoding='utf-8')
txt = f.read()
f.close()
else:
txt = 'unable to read {}'.format(path)
return txt
# page Changed
self.tbAbout.setHtml(readTextFile(PATH_ABOUT))

Benjamin Jakimow
committed
self.tbChanges.setHtml(readTextFile(PATH_CHANGELOG + '.html'))
self.tbLicense.setHtml(readTextFile(os.path.splitext(PATH_LICENSE)[0] + '.html'))

Benjamin Jakimow
committed
def setAboutTitle(self, suffix=None):
item = self.listWidget.currentItem()
if item:
title = '{} | {}'.format(self.mTitle, item.text())
else:
title = self.mTitle
if suffix:
title += ' ' + suffix
self.setWindowTitle(title)
class TimeSeriesViewerUI(QMainWindow,
loadUI('timeseriesviewer.ui')):
sigAboutToBeClosed = pyqtSignal()
def __init__(self, parent=None):
"""Constructor."""
super(TimeSeriesViewerUI, self).__init__(parent)
# Set up the user interface from Designer.
# After setupUI you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)

Benjamin Jakimow
committed
self.setCentralWidget(self.mMapWidget)
self.addActions(self.findChildren(QAction))
from eotimeseriesviewer import TITLE, icon, __version__
self.mMapToolActions = []
self.setWindowTitle('{} ({})'.format(TITLE, __version__))
self.setWindowIcon(icon())
if sys.platform == 'darwin':
self.menuBar().setNativeMenuBar(False)
# set button default actions -> this will show the action icons as well
# I don't know why this is not possible in the QDesigner when QToolButtons are
# placed outside a toolbar
area = None
def addDockWidget(dock:QDockWidget):
"""
shortcut to add a created dock and return it
:param dock:
:return:
"""
dock.setParent(self)
self.addDockWidget(area, dock)
return dock
area = Qt.LeftDockWidgetArea
# self.dockRendering = addDockWidget(docks.RenderingDockUI(self))
from eotimeseriesviewer.mapvisualization import MapViewDock
self.dockMapViews = addDockWidget(MapViewDock(self))
# self.tabifyDockWidget(self.dockMapViews, self.dockRendering)
# self.tabifyDockWidget(self.dockSensors, self.dockCursorLocation)
area = Qt.BottomDockWidgetArea
# from timeseriesviewer.mapvisualization import MapViewDockUI
# self.dockMapViews = addDockWidget(MapViewDockUI(self))
self.dockTimeSeries = addDockWidget(TimeSeriesDock(self))
self.dockTimeSeries.initActions(self)
from eotimeseriesviewer.profilevisualization import ProfileViewDockUI
self.dockProfiles = addDockWidget(ProfileViewDockUI(self))
from eotimeseriesviewer.labeling import LabelingDock
self.dockLabeling = addDockWidget(LabelingDock(self))

Benjamin Jakimow
committed
self.dockAdvancedDigitizingDockWidget = addDockWidget(QgsAdvancedDigitizingDockWidget(self.dockLabeling.labelingWidget().canvas(), self))
self.dockAdvancedDigitizingDockWidget.setVisible(False)
panel = SpectralLibraryPanel(self)
self.dockSpectralLibrary = addDockWidget(panel)
self.tabifyDockWidget(self.dockTimeSeries, self.dockSpectralLibrary)
self.tabifyDockWidget(self.dockTimeSeries, self.dockProfiles)

Benjamin Jakimow
committed
self.tabifyDockWidget(self.dockTimeSeries, self.dockLabeling)

benjamin.jakimow@geo.hu-berlin.de
committed
area = Qt.RightDockWidgetArea
self.dockTaskManager = QgsDockWidget('Task Manager')
self.dockTaskManager.setWidget(QgsTaskManagerWidget(QgsApplication.taskManager()))
self.dockTaskManager.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
self.dockTaskManager = addDockWidget(self.dockTaskManager)

benjamin.jakimow@geo.hu-berlin.de
committed
from eotimeseriesviewer.systeminfo import SystemInfoDock
from eotimeseriesviewer.sensorvisualization import SensorDockUI
self.dockSystemInfo = addDockWidget(SystemInfoDock(self))
self.dockSystemInfo.setVisible(False)
self.dockSensors = addDockWidget(SensorDockUI(self))
self.dockCursorLocation = addDockWidget(CursorLocationInfoDock(self))
self.tabifyDockWidget(self.dockTaskManager, self.dockCursorLocation)
self.tabifyDockWidget(self.dockTaskManager, self.dockSystemInfo)
self.tabifyDockWidget(self.dockTaskManager, self.dockSensors)
for dock in self.findChildren(QDockWidget):
if len(dock.actions()) > 0:
s = ""
self.menuPanels.addAction(dock.toggleViewAction())
def registerMapToolAction(self, a:QAction)->QAction:
"""
Registers this action as map tools action. If triggered, all other mapt tool actions with be set unchecked
:param a: QAction
:return: QAction
"""
assert isinstance(a, QAction)
if a not in self.mMapToolActions:
self.mMapToolActions.append(a)
a.setCheckable(True)
a.toggled.connect(lambda b, action=a: self.onMapToolActionToggled(b, action))
def onMapToolActionToggled(self, b:bool, action:QAction):
"""
Reacts on togglinga map tool
:param b:
:param action:
"""
assert isinstance(action, QAction)
otherActions = [a for a in self.mMapToolActions if a != action]
# enable / disable the other maptool actions
if b is True:
for a in otherActions:
assert isinstance(a, QAction)
a.setChecked(False)
else:
otherSelected = [a for a in otherActions if a.isChecked()]
if len(otherSelected) == 0:
action.setChecked(True)
b = self.actionIdentify.isChecked()
self.optionIdentifyCursorLocation.setEnabled(b)
self.optionIdentifySpectralProfile.setEnabled(b)
self.optionIdentifyTemporalProfile.setEnabled(b)
self.optionMoveCenter.setEnabled(b)
def closeEvent(self, a0:QCloseEvent):
self.sigAboutToBeClosed.emit()
"""
def resizeEvent(self, event:QResizeEvent):
super(TimeSeriesViewerUI, self).resizeEvent(event)
if False and not self.mInitResized:
pass
w = 0.5
minH = int(self.size().height() * w)
print(minH)
#self.mCentralWidget.setMinimumHeight(minH)
for d in self.findChildren(QDockWidget):
w = d.widget()
assert isinstance(d, QDockWidget)
print((d.objectName(), d.minimumHeight(), d.sizePolicy().verticalPolicy()))
d.setMinimumHeight(0)
s = ""
#self.mCentralWidget.setMinimumWidth(int(self.size().width() * w))
#self.mInitResized = True
"""
Qgis.Info: 'INFO',
Qgis.Critical: 'INFO',
Qgis.Warning: 'WARNING',
Qgis.Success: 'SUCCESS',

benjamin.jakimow@geo.hu-berlin.de
committed
def showMessage(message, title, level):
v = QgsMessageViewer()
v.setTitle(title)
#print('DEBUG MSG: {}'.format(message))
v.setMessage(message, QgsMessageOutput.MessageHtml \
if message.startswith('<html>')
else QgsMessageOutput.MessageText)
v.showMessage(True)
class TimeSeriesViewer(QgisInterface, QObject):
_instance = None
@staticmethod
def instance():
"""
Returns the TimeSeriesViewer instance
:return:
"""
return TimeSeriesViewer._instance
sigCurrentLocationChanged = pyqtSignal([SpatialPoint],
[SpatialPoint, QgsMapCanvas])
sigCurrentSpectralProfilesChanged = pyqtSignal(list)
sigCurrentTemporalProfilesChanged = pyqtSignal(list)
sigCloses = pyqtSignal()
"""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
"""
QObject.__init__(self)
QgisInterface.__init__(self)
QApplication.processEvents()

Benjamin Jakimow
committed
TimeSeriesViewer._instance = self
self.ui = TimeSeriesViewerUI()
mvd = self.ui.dockMapViews
dts = self.ui.dockTimeSeries

Benjamin Jakimow
committed
mw = self.ui.mMapWidget
self.mMapLayerStore = self.mapWidget().mMapLayerStore
import eotimeseriesviewer.utils
eotimeseriesviewer.utils.MAP_LAYER_STORES.insert(0, self.mapLayerStore())
from eotimeseriesviewer.timeseries import TimeSeriesDock
from eotimeseriesviewer.mapvisualization import MapViewDock, MapWidget
assert isinstance(mvd, MapViewDock)
assert isinstance(mw, MapWidget)
assert isinstance(dts, TimeSeriesDock)
def onClosed():
TimeSeriesViewer._instance = None
self.ui.sigAboutToBeClosed.connect(onClosed)
QgsApplication.instance().messageLog().messageReceived.connect(self.logMessage)
assert isinstance(qgis.utils.iface, QgisInterface)

Benjamin Jakimow
committed
# init empty time series
self.mTimeSeries = TimeSeries()

Benjamin Jakimow
committed
self.mTimeSeries.setDateTimePrecision(DateTimePrecision.Day)

benjamin.jakimow@geo.hu-berlin.de
committed
self.mSpatialMapExtentInitialized = False
self.mTimeSeries.sigTimeSeriesDatesAdded.connect(self.onTimeSeriesChanged)
self.mTimeSeries.sigTimeSeriesDatesRemoved.connect(self.onTimeSeriesChanged)
self.mTimeSeries.sigSensorAdded.connect(self.onSensorAdded)
dts.setTimeSeries(self.mTimeSeries)
self.ui.dockSensors.setTimeSeries(self.mTimeSeries)
mw.setTimeSeries(self.mTimeSeries)
mvd.setTimeSeries(self.mTimeSeries)
mvd.setMapWidget(mw)
self.spectralTemporalVis = SpectralTemporalVisualization(self.mTimeSeries, self.ui.dockProfiles)
assert isinstance(self, TimeSeriesViewer)
self.spectralTemporalVis.sigMoveToDate.connect(self.setCurrentDate)
mw.sigSpatialExtentChanged.connect(self.timeSeries().setCurrentSpatialExtent)
mw.sigVisibleDatesChanged.connect(self.timeSeries().setVisibleDates)
mw.sigMapViewAdded.connect(self.onMapViewAdded)
mw.sigCurrentLocationChanged.connect(self.setCurrentLocation)

Benjamin Jakimow
committed
tb = self.ui.toolBarTimeControl
assert isinstance(tb, QToolBar)
tb.addAction(mw.actionFirstDate)
tb.addAction(mw.actionBackwardFast)
tb.addAction(mw.actionBackward)
tb.addAction(mw.actionForward)
tb.addAction(mw.actionForwardFast)
tb.addAction(mw.actionLastDate)
tstv = self.ui.dockTimeSeries.timeSeriesTreeView
assert isinstance(tstv, TimeSeriesTreeView)
tstv.sigMoveToDateRequest.connect(self.setCurrentDate)
self.mCurrentMapLocation = None
self.mCurrentMapSpectraLoading = 'TOP'
self.ui.actionLockMapPanelSize.toggled.connect(self.lockCentralWidgetSize)
def initMapToolAction(action, key):
assert isinstance(action, QAction)
action.triggered.connect(lambda: self.setMapTool(key))
action.setProperty('eotsv/maptoolkey', key)
self.ui.registerMapToolAction(action)
initMapToolAction(self.ui.actionPan, MapTools.Pan)
initMapToolAction(self.ui.actionZoomIn, MapTools.ZoomIn)
initMapToolAction(self.ui.actionZoomOut, MapTools.ZoomOut)
initMapToolAction(self.ui.actionZoomPixelScale, MapTools.ZoomPixelScale)
initMapToolAction(self.ui.actionZoomFullExtent, MapTools.ZoomFull)
initMapToolAction(self.ui.actionIdentify, MapTools.CursorLocation)
initMapToolAction(self.ui.actionSelectFeatures, MapTools.SelectFeature)
assert isinstance(self.ui.actionSelectFeatures, QAction)
self.ui.optionSelectFeaturesRectangle.triggered.connect(self.onSelectFeatureOptionTriggered)
self.ui.optionSelectFeaturesPolygon.triggered.connect(self.onSelectFeatureOptionTriggered)
self.ui.optionSelectFeaturesFreehand.triggered.connect(self.onSelectFeatureOptionTriggered)
self.ui.optionSelectFeaturesRadius.triggered.connect(self.onSelectFeatureOptionTriggered)
m = QMenu()
m.addAction(self.ui.optionSelectFeaturesRectangle)
m.addAction(self.ui.optionSelectFeaturesPolygon)
m.addAction(self.ui.optionSelectFeaturesFreehand)
m.addAction(self.ui.optionSelectFeaturesRadius)
self.ui.actionSelectFeatures.setMenu(m)
# create edit toolbar
tb = self.ui.toolBarVectorFeatures
assert isinstance(tb, QToolBar)

Benjamin Jakimow
committed
tb.addAction(self.ui.dockLabeling.labelingWidget().actionToggleEditing())
tb.addAction(self.ui.dockLabeling.labelingWidget().actionSaveEdits())
tb.addAction(self.ui.dockLabeling.labelingWidget().actionAddFeature())
labelingWidget = self.ui.dockLabeling.labelingWidget()
from .labeling import LabelingWidget
assert isinstance(labelingWidget, LabelingWidget)
labelingWidget.sigMapExtentRequested.connect(self.setSpatialExtent)
labelingWidget.sigMapCenterRequested.connect(self.setSpatialCenter)
labelingWidget.sigVectorLayerChanged.connect(
self.ui.dockLabeling.labelingWidget().currentVectorSource()))

Benjamin Jakimow
committed
initMapToolAction(self.ui.dockLabeling.labelingWidget().actionAddFeature(), MapTools.AddFeature)
# set default map tool
self.ui.dockCursorLocation.sigLocationRequest.connect(self.ui.actionIdentifyCursorLocationValues.trigger)
self.ui.dockCursorLocation.mLocationInfoModel.setNodeExpansion(CursorLocationInfoModel.ALWAYS_EXPAND)
# D.actionIdentifyMapLayers.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('identifyMapLayers'))
self.ui.actionAddMapView.triggered.connect(mvd.createMapView)
self.ui.actionAddTSD.triggered.connect(lambda: self.addTimeSeriesImages(None))
self.ui.actionAddVectorData.triggered.connect(lambda: self.addVectorData())
self.ui.actionRemoveTSD.triggered.connect(lambda: self.mTimeSeries.removeTSDs(dts.selectedTimeSeriesDates()))
self.ui.actionRefresh.triggered.connect(mw.refresh)
self.ui.actionLoadTS.triggered.connect(self.loadTimeSeriesDefinition)
self.ui.actionClearTS.triggered.connect(self.clearTimeSeries)
self.ui.actionSaveTS.triggered.connect(self.saveTimeSeriesDefinition)
self.ui.actionAddTSExample.triggered.connect(lambda: self.loadExampleTimeSeries(loadAsync=False))
self.ui.actionLoadTimeSeriesStack.triggered.connect(self.loadTimeSeriesStack)
#self.ui.actionShowCrosshair.toggled.connect(mw.setCrosshairVisibility)
self.ui.actionExportMapsToImages.triggered.connect(lambda: self.exportMapsToImages())

Benjamin Jakimow
committed
self.spectralTemporalVis.ui.actionLoadProfileRequest.triggered.connect(self.activateIdentifyTemporalProfileMapTool)
self.ui.dockSpectralLibrary.SLW.actionSelectProfilesFromMap.triggered.connect(self.activateIdentifySpectralProfileMapTool)

Benjamin Jakimow
committed
self.ui.actionAbout.triggered.connect(lambda: AboutDialogUI(self.ui).exec_())
self.ui.actionSettings.triggered.connect(self.onShowSettingsDialog)
from eotimeseriesviewer import DOCUMENTATION, SpectralLibrary, SpectralLibraryPanel, SpectralLibraryWidget
self.ui.actionShowOnlineHelp.triggered.connect(lambda: webbrowser.open(DOCUMENTATION))
SLW = self.ui.dockSpectralLibrary.spectralLibraryWidget()
assert isinstance(SLW, SpectralLibraryWidget)
SLW.setMapInteraction(True)
SLW.setCurrentProfilesMode(SpectralLibraryWidget.CurrentProfilesMode.automatically)
SLW.sigMapExtentRequested.connect(self.setSpatialExtent)
SLW.sigMapCenterRequested.connect(self.setSpatialCenter)
# add time-specific fields
sl = self.spectralLibrary()
assert isinstance(sl, SpectralLibrary)
sl.setName('EOTS Spectral Library')
sl.startEditing()
for field in EXTRA_SPECLIB_FIELDS:
sl.addAttribute(field)
assert sl.commitChanges()
self.mMapLayerStore.addMapLayer(sl)
temporalProfileLayer = self.spectralTemporalVis.temporalProfileLayer()
assert isinstance(temporalProfileLayer, QgsVectorLayer)
temporalProfileLayer.setName('EOTS Temporal Profiles')
self.mMapLayerStore.addMapLayer(temporalProfileLayer)
eotimeseriesviewer.labeling.MAP_LAYER_STORES.append(self.mMapLayerStore)
eotimeseriesviewer.labeling.registerLabelShortcutEditorWidget()
self.initQGISConnection()
for toolBar in self.ui.findChildren(QToolBar):
fixMenuButtons(toolBar)
self.ui.dockTimeSeries.setFloating(True)
self.ui.dockTimeSeries.setFloating(False)
def lockCentralWidgetSize(self, b:bool):
"""
Locks or release the current central widget size
:param b:
"""
w = self.ui.centralWidget()
size = w.size()
if b:
w.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
w.setMinimumSize(size)
else:
w.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred))
w.setMinimumSize(0, 0)
def sensors(self)->typing.List[SensorInstrument]:

Benjamin Jakimow
committed
"""
Returns the list of Sensors
:return: [list-of-Sensors]
"""
return self.mTimeSeries.sensors()
def activateIdentifyTemporalProfileMapTool(self, *args):
"""
Activates the collection of temporal profiles
"""
self.ui.actionIdentify.trigger()
self.ui.optionIdentifyTemporalProfile.setChecked(True)
def activateIdentifySpectralProfileMapTool(self, *args):
"""
Activates the collection of spectral profiles
"""
self.ui.actionIdentify.trigger()
self.ui.optionIdentifySpectralProfile.setChecked(True)
def _createProgressDialog(self, title='Load Data')->QProgressDialog:
"""
Creates a QProgressDialog to load image data
:return: QProgressDialog
"""
progressDialog = QProgressDialog(self.ui)
progressDialog.setWindowTitle(title)
progressDialog.setMinimumDuration(500)
progressDialog.setValue(0)
progressDialog.setWindowFlags(progressDialog.windowFlags() & ~Qt.WindowContextHelpButtonHint)
return progressDialog
def exportMapsToImages(self, path=None, format='PNG'):
"""
Exports the map canvases to local images.
:param path: directory to save the images in
:param format: rastr format, e.g. 'PNG' or 'JPG'
"""
from .mapcanvas import MapCanvas
from .mapvisualization import MapView
from .settings import Keys, setValue, value
import string
if path is None:
d = SaveAllMapsDialog()
path = value(Keys.MapImageExportDirectory, default=None)
if isinstance(path, str):
d.setDirectory(path)
if d.exec() != QDialog.Accepted:
s = ""
return
format = d.fileType().lower()
path = d.directory()
else:
format = format.lower()
mapCanvases = self.mapCanvases()
n = len(mapCanvases)
progressDialog = self._createProgressDialog(title='Save Map Images...')
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
progressDialog.setRange(0, n)
valid_chars = "-_.() {}{}".format(string.ascii_letters, string.digits)
for i, mapCanvas in enumerate(mapCanvases):
if progressDialog.wasCanceled():
return
assert isinstance(mapCanvas, MapCanvas)
mapCanvas.timedRefresh()
tsd = mapCanvas.tsd()
mv = mapCanvas.mapView()
assert isinstance(mv, MapView)
mapCanvas.waitWhileRendering()
imgPath = '{}.{}.{}'.format(tsd.date(), mv.title(), format)
imgPath = ''.join(c for c in imgPath if c in valid_chars)
imgPath = imgPath.replace(' ', '_')
imgPath = os.path.join(path, imgPath)
mapCanvas.saveAsImage(imgPath, None, format)
progressDialog.setValue(i + 1)
progressDialog.setLabelText('{}/{} maps saved'.format(i+1, n))
if progressDialog.wasCanceled():
return
setValue(Keys.MapImageExportDirectory, path)
def onMapViewAdded(self, mapView:MapView):
"""
:param mapView:
:return:
"""
mapView.addLayer(self.spectralTemporalVis.temporalProfileLayer())
mapView.addLayer(self.spectralLibrary())
def temporalProfileLayer(self)->TemporalProfileLayer:
"""
Returns the TemporalProfileLayer
:return:
"""
from eotimeseriesviewer.profilevisualization import SpectralTemporalVisualization
return self.spectralTemporalVis.temporalProfileLayer()
def spectralLibrary(self)->SpectralLibrary:
"""
Returns the SpectraLibrary of the SpectralLibrary dock
:return: SpectraLibrary
"""
from .externals.qps.speclib.spectrallibraries import SpectralLibraryPanel
if isinstance(self.ui.dockSpectralLibrary, SpectralLibraryPanel):
return self.ui.dockSpectralLibrary.SLW.speclib()
else:
return None
def actionZoomActualSize(self):
return self.ui.actionZoomPixelScale
def actionZoomFullExtent(self):
return self.ui.actionZoomFullExtent
def actionZoomIn(self):
return self.ui.actionZoomIn
def actionZoomOut(self):
return self.ui.actionZoomOut

Benjamin Jakimow
committed
def setCurrentDate(self, tsd):
Moves the viewport of the scroll window to a specific TimeSeriesDate
:param tsd: TimeSeriesDate or numpy.datetime64
tsd = self.timeSeries().findDate(tsd)
if isinstance(tsd, TimeSeriesDate):
self.ui.mMapWidget.setCurrentDate(tsd)
def mapCanvases(self)->typing.List[MapCanvas]:

Benjamin Jakimow
committed
"""
Returns all MapCanvases of the spatial visualization
:return: [list-of-MapCanvases]
"""

Benjamin Jakimow
committed
return self.ui.mMapWidget.mapCanvases()

Benjamin Jakimow
committed
def mapLayerStore(self)->QgsMapLayerStore:
"""
Returns the QgsMapLayerStore which is used to register QgsMapLayers
:return: QgsMapLayerStore
"""
return self.mMapLayerStore
def onMoveToFeature(self, layer:QgsMapLayer, feature:QgsFeature):
"""
Move the spatial center of map visualization to `feature`.
:param layer: QgsMapLayer
:param feature: QgsFeature
"""
g = feature.geometry()
if isinstance(g, QgsGeometry):
c = g.centroid()
x, y = c.asPoint()
crs = layer.crs()
center = SpatialPoint(crs, x, y)

Benjamin Jakimow
committed
self.ui.mMapWidget.setSpatialCenter(center)
def onSelectFeatureOptionTriggered(self):
a = self.sender()
m = self.ui.actionSelectFeatures.menu()
if isinstance(a, QAction) and isinstance(m, QMenu) and a in m.actions():
for option in m.actions():
assert isinstance(option, QAction)
if option == a:
self.ui.actionSelectFeatures.setIcon(a.icon())
self.ui.actionSelectFeatures.setToolTip(a.toolTip())
option.setChecked(option == a)
self.onSelectFeatureTriggered()
def onSelectFeatureTriggered(self):
self.setMapTool(MapTools.SelectFeature)

Benjamin Jakimow
committed
def initQGISConnection(self):
"""
Initializes interactions between TimeSeriesViewer and the QGIS instances
:return:
"""
iface = qgis.utils.iface
assert isinstance(iface, QgisInterface)
self.ui.actionImportExtent.triggered.connect(lambda: self.setSpatialExtent(SpatialExtent.fromMapCanvas(iface.mapCanvas())))
self.ui.actionExportExtent.triggered.connect(lambda: iface.mapCanvas().setExtent(self.spatialExtent().toCrs(iface.mapCanvas().mapSettings().destinationCrs())))
self.ui.actionExportCenter.triggered.connect(lambda: iface.mapCanvas().setCenter(self.spatialCenter().toCrs(iface.mapCanvas().mapSettings().destinationCrs())))
self.ui.actionImportCenter.triggered.connect(lambda: self.setSpatialCenter(SpatialPoint.fromMapCanvasCenter(iface.mapCanvas())))
def onSyncRequest(qgisChanged:bool):
if self.ui.optionSyncMapCenter.isChecked():

Benjamin Jakimow
committed
self.ui.mMapWidget.syncQGISCanvasCenter(qgisChanged)

Benjamin Jakimow
committed
self.ui.mMapWidget.sigSpatialExtentChanged.connect(lambda: onSyncRequest(False))
iface.mapCanvas().extentsChanged.connect(lambda: onSyncRequest(True))
from eotimeseriesviewer.settings import SettingsDialog
d = SettingsDialog(self.ui)
r = d.exec_()
if r == QDialog.Accepted:
self.applySettings()
s = ""
else:
pass
s =""
def applySettings(self):
"""

Benjamin Jakimow
committed
Reads the QSettings object and applies its values to related widget components

Benjamin Jakimow
committed
from eotimeseriesviewer.settings import value, Keys, defaultValues, setValue

Benjamin Jakimow
committed
# the default values

Benjamin Jakimow
committed
defaults = defaultValues()
for key in list(Keys):
if value(key) == None and key in defaults.keys():

Benjamin Jakimow
committed
setValue(key, defaults[key])
v = value(Keys.DateTimePrecision)
if isinstance(v, DateTimePrecision):
self.mTimeSeries.setDateTimePrecision(v)
v = value(Keys.SensorMatching)
if isinstance(v, SensorMatching):
self.mTimeSeries.setSensorMatching(v)
v = value(Keys.SensorSpecs)
if isinstance(v, dict):
sensors = dict()
for s in self.sensors():
sensors[s.id()] = s
for sid, specs in v.items():
assert isinstance(sid, str)
assert isinstance(specs, dict)
sensor = sensors.get(sid)
if isinstance(sensor, SensorInstrument):
if 'name' in specs.keys():
sensor.setName(specs['name'])
v = value(Keys.MapUpdateInterval)
if isinstance(v, int) and v > 0:

Benjamin Jakimow
committed
self.ui.mMapWidget.mMapRefreshTimer.start(v)
v = value(Keys.MapBackgroundColor)
if isinstance(v, QColor):
self.ui.dockMapViews.setMapBackgroundColor(v)

Benjamin Jakimow
committed
v = value(Keys.MapTextFormat)
if isinstance(v, QgsTextFormat):
self.ui.dockMapViews.setMapTextFormat(v)
v = value(Keys.MapSize)
if isinstance(v, QSize):

Benjamin Jakimow
committed
self.ui.mMapWidget.setMapSize(v)
def setMapTool(self, mapToolKey, *args, **kwds):
"""
Sets the active QgsMapTool for all canvases know to the EOTSV.
:param mapToolKey: str, see MapTools documentation
:param args:
:param kwds:
:return:
"""
if mapToolKey == MapTools.SelectFeature:
if self.ui.optionSelectFeaturesRectangle.isChecked():
mapToolKey = MapTools.SelectFeature
elif self.ui.optionSelectFeaturesPolygon.isChecked():
mapToolKey = MapTools.SelectFeatureByPolygon
elif self.ui.optionSelectFeaturesFreehand.isChecked():
mapToolKey = MapTools.SelectFeatureByFreehand
elif self.ui.optionSelectFeaturesRadius.isChecked():
mapToolKey = MapTools.SelectFeatureByRadius

Benjamin Jakimow
committed
self.ui.mMapWidget.setMapTool(mapToolKey, *args)
def setMapsPerMapView(self, n:int):
"""
Sets the number of map canvases that is shown per map view
:param n: int
"""
self.mapWidget().setMapsPerMapView(n)

Benjamin Jakimow
committed
def setMapSize(self, size:QSize):
"""
Sets the MapCanvas size.
:param size: QSize
"""
def setSpatialExtent(self, spatialExtent:SpatialExtent):
Sets the map canvas extent
:param spatialExtent: SpatialExtent
def setSpatialCenter(self, spatialPoint:SpatialPoint):
"""
Sets the center of map canvases
:param spatialPoint: SpatialPoint
"""
def spatialExtent(self)->SpatialExtent:
"""
Returns the map extent
:return: SpatialExtent
"""
return self.mapWidget().spatialExtent()
def spatialCenter(self)->SpatialPoint:
"""
Returns the map center
:return: SpatialPoint
"""
def setCurrentLocation(self, spatialPoint:SpatialPoint, mapCanvas:QgsMapCanvas=None):
"""
Sets the current "last selected" location, for which different properties might get derived,
like cursor location values and SpectraProfiles.
:param spatialPoint: SpatialPoint
:param mapCanvas: QgsMapCanvas (optional), the canvas on which the location got selected
"""
assert isinstance(spatialPoint, SpatialPoint)
bCLV = self.ui.optionIdentifyCursorLocation.isChecked()
bSP = self.ui.optionIdentifySpectralProfile.isChecked()
bTP = self.ui.optionIdentifyTemporalProfile.isChecked()
bCenter = self.ui.optionMoveCenter.isChecked()
self.mCurrentMapLocation = spatialPoint
if isinstance(mapCanvas, QgsMapCanvas):
self.sigCurrentLocationChanged[SpatialPoint, QgsMapCanvas].emit(self.mCurrentMapLocation, mapCanvas)
if bCLV:
self.loadCursorLocationValueInfo(spatialPoint, mapCanvas)
if bCenter:
mapCanvas.setCenter(spatialPoint.toCrs(mapCanvas.mapSettings().destinationCrs()))
if bSP:
self.loadCurrentSpectralProfile(spatialPoint, mapCanvas)
if bTP:
self.loadCurrentTemporalProfile(spatialPoint)
self.sigCurrentLocationChanged[SpatialPoint].emit(self.mCurrentMapLocation)
@pyqtSlot(SpatialPoint, QgsMapCanvas)
def loadCursorLocationValueInfo(self, spatialPoint:SpatialPoint, mapCanvas:QgsMapCanvas):
self.ui.dockCursorLocation.loadCursorLocation(spatialPoint, mapCanvas)
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
@pyqtSlot(SpatialPoint, QgsMapCanvas)
def loadCurrentSpectralProfile(self, spatialPoint: SpatialPoint, mapCanvas: QgsMapCanvas):
"""
Loads SpectralProfiles from a location defined by `spatialPoint`
:param spatialPoint: SpatialPoint
:param mapCanvas: QgsMapCanvas
"""
assert self.mCurrentMapSpectraLoading in ['TOP', 'ALL']
assert isinstance(spatialPoint, SpatialPoint)
from .mapcanvas import MapCanvas
assert isinstance(mapCanvas, MapCanvas)
tsd = mapCanvas.tsd()
sensorLayers = [l for l in mapCanvas.layers() if isinstance(l, SensorProxyLayer)]
currentSpectra = []
sl = self.spectralLibrary()
for lyr in sensorLayers:
assert isinstance(lyr, SensorProxyLayer)
p = SpectralProfile.fromRasterLayer(lyr, spatialPoint)
if isinstance(p, SpectralProfile):
p2 = p.copyFieldSubset(sl.fields())
p2.setName('{} {}'.format(p.name(), tsd.date()))
p2.setAttribute('date', '{}'.format(tsd.date()))
p2.setAttribute('doy', int(tsd.doy()))
p2.setAttribute('sensor', tsd.sensor().name())
currentSpectra.append(p2)
if self.mCurrentMapSpectraLoading == 'TOP':
break
self.ui.dockSpectralLibrary.SLW.setCurrentSpectra(currentSpectra)
@pyqtSlot(SpatialPoint)
def loadCurrentTemporalProfile(self, spatialPoint: SpatialPoint):
self.spectralTemporalVis.loadCoordinate(spatialPoint)
def onShowProfile(self, spatialPoint, mapCanvas, mapToolKey):
assert isinstance(spatialPoint, SpatialPoint)
assert isinstance(mapCanvas, QgsMapCanvas)
from eotimeseriesviewer.mapcanvas import MapTools
assert mapToolKey in MapTools.mapToolValues()
if mapToolKey == MapTools.TemporalProfile:
self.spectralTemporalVis.loadCoordinate(spatialPoint)
elif mapToolKey == MapTools.SpectralProfile:
tsd = None
from .mapcanvas import MapCanvas