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.profilevisualization import SpectralTemporalVisualization
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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.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))
aboutText = readTextFile(PATH_CHANGELOG)
urlPrefix = r'https://bitbucket.org/jakimowb/eo-time-series-viewer/issues/'
aboutText = re.sub(r'(#(\d+))', r'`#\2 <{}\2>`_'.format(urlPrefix), aboutText)
from docutils.core import publish_string
aboutHTML = publish_string(aboutText, writer_name='html')
self.tbChanges.setText(aboutHTML.decode())
self.tbLicense.setText(readTextFile(PATH_LICENSE))
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')):
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)
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):
"""
shortcut to add a created dock and return it
:param dock:
:return:
"""
self.addDockWidget(area, dock)
return dock
area = Qt.LeftDockWidgetArea
# self.dockRendering = addDockWidget(docks.RenderingDockUI(self))
from eotimeseriesviewer.labeling import LabelingDock
self.dockLabeling = addDockWidget(LabelingDock(self))
self.dockLabeling.setHidden(True)
from eotimeseriesviewer.sensorvisualization import SensorDockUI
self.dockSensors = addDockWidget(SensorDockUI(self))
from eotimeseriesviewer.mapvisualization import MapViewDock
self.dockMapViews = addDockWidget(MapViewDock(self))
self.dockCursorLocation = addDockWidget(CursorLocationInfoDock(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(TimeSeriesDockUI(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))
area = Qt.LeftDockWidgetArea
self.dockAdvancedDigitizingDockWidget = addDockWidget(QgsAdvancedDigitizingDockWidget(self.dockLabeling.canvas(), self))
self.dockAdvancedDigitizingDockWidget.setVisible(False)
self.tabifyDockWidget(self.dockSensors, self.dockAdvancedDigitizingDockWidget)
panel = SpectralLibraryPanel(None)
panel.setParent(self)
self.dockSpectralLibrary = addDockWidget(panel)
self.tabifyDockWidget(self.dockTimeSeries, self.dockSpectralLibrary)
#except Exception as ex:
# print('Unable to create SpectralLibrary panel', file=sys.stderr)
# print(ex, file=sys.stderr)
# self.dockSpectralLibrary = None

Benjamin Jakimow
committed
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
from eotimeseriesviewer.systeminfo import SystemInfoDock

benjamin.jakimow@geo.hu-berlin.de
committed
self.dockSystemInfo = addDockWidget(SystemInfoDock(self))
self.dockSystemInfo.setVisible(False)
for dock in self.findChildren(QDockWidget):
if len(dock.actions()) > 0:
s = ""
self.menuPanels.addAction(dock.toggleViewAction())
def registerMapToolAction(self, a: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):
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)
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)
"""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
"""
# assert TimeSeriesViewer.instance() is None
QObject.__init__(self)
QgisInterface.__init__(self)
QApplication.processEvents()

Benjamin Jakimow
committed
self.mMapLayerStore = QgsMapLayerStore()
import eotimeseriesviewer.utils
eotimeseriesviewer.utils.MAP_LAYER_STORES.insert(0, self.mapLayerStore())

Benjamin Jakimow
committed
self.ui = TimeSeriesViewerUI()
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)
# init other GUI components
# self.ICP = D.scrollAreaSubsetContent.layout()
# D.scrollAreaMapViews.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
# self.BVP = self.ui.scrollAreaMapViews.layout()
# D.dockNavigation.connectTimeSeries(self.TS)
self.ui.dockTimeSeries.setTimeSeries(self.mTimeSeries)
self.ui.dockSensors.setTimeSeries(self.mTimeSeries)
self.spectralTemporalVis = SpectralTemporalVisualization(self.mTimeSeries, self.ui.dockProfiles)

benjamin.jakimow@geo.hu-berlin.de
committed
self.spectralTemporalVis.pixelLoader.sigLoadingFinished.connect(
lambda dt: self.ui.dockSystemInfo.addTimeDelta('Pixel Profile', dt))
assert isinstance(self, TimeSeriesViewer)
from eotimeseriesviewer.mapvisualization import SpatialTemporalVisualization
self.spatialTemporalVis = SpatialTemporalVisualization(self)
# self.spatialTemporalVis.sigLoadingStarted.connect(self.ui.dockRendering.addStartedWork)
# self.spatialTemporalVis.sigLoadingFinished.connect(self.ui.dockRendering.addFinishedWork)
# self.spatialTemporalVis.sigShowProfiles.connect(self.spectralTemporalVis.loadCoordinate)

Benjamin Jakimow
committed
self.spatialTemporalVis.sigShowProfiles.connect(self.onShowProfile)

Benjamin Jakimow
committed
self.ui.dockMapViews.sigCrsChanged.connect(self.spatialTemporalVis.setCrs)
self.ui.dockMapViews.sigMapSizeChanged.connect(self.spatialTemporalVis.setMapSize)
self.ui.dockMapViews.sigMapCanvasColorChanged.connect(self.spatialTemporalVis.setMapBackgroundColor)

Benjamin Jakimow
committed
self.spatialTemporalVis.sigCRSChanged.connect(self.ui.dockMapViews.setCrs)
self.spatialTemporalVis.sigMapSizeChanged.connect(self.ui.dockMapViews.setMapSize)
self.spatialTemporalVis.sigVisibleDatesChanged.connect(self.timeSeries().setCurrentDates)
self.spectralTemporalVis.sigMoveToTSD.connect(self.showTimeSeriesDatum)

Benjamin Jakimow
committed
tstv = self.ui.dockTimeSeries.timeSeriesTreeView
assert isinstance(tstv, TimeSeriesTreeView)
tstv.sigMoveToDateRequest.connect(self.showTimeSeriesDatum)
self.mCurrentMapLocation = None
self.mCurrentMapSpectraLoading = 'TOP'
def initMapToolAction(action, key):
assert isinstance(action, QAction)
assert isinstance(key, str)
assert key in MapTools.mapToolKeys()
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.toolBarEditing
assert isinstance(tb, QToolBar)
tb.addAction(self.ui.dockLabeling.actionToggleEditing())
tb.addAction(self.ui.dockLabeling.actionSaveEdits())
tb.addAction(self.ui.dockLabeling.actionAddFeature())
self.ui.dockLabeling.sigMapExtentRequested.connect(self.setSpatialExtent)
self.ui.dockLabeling.sigMapCenterRequested.connect(self.setSpatialCenter)
initMapToolAction(self.ui.dockLabeling.actionAddFeature(), MapTools.AddFeature)
self.ui.dockLabeling.sigVectorLayerChanged.connect(lambda : self.spatialTemporalVis.setCurrentLayer(self.ui.dockLabeling.currentVectorSource()))
#initMapToolAction(self.ui.dockLabeling., 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(self.spatialTemporalVis.MVC.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(self.ui.dockTimeSeries.selectedTimeSeriesDates()))
self.ui.actionRefresh.triggered.connect(self.spatialTemporalVis.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(self.loadExampleTimeSeries)
self.ui.actionLoadTimeSeriesStack.triggered.connect(self.loadTimeSeriesStack)
self.ui.actionShowCrosshair.toggled.connect(self.spatialTemporalVis.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)

Benjamin Jakimow
committed
#SLW.sigLoadFromMapRequest.connect(self.ui.actionIdentifySpectralProfile.trigger)
SLW.setMapInteraction(True)
SLW.setCurrentProfilesMode(SpectralLibraryWidget.CurrentProfilesMode.automatically)
SLW.sigMapExtentRequested.connect(self.setSpatialExtent)
SLW.sigMapCenterRequested.connect(self.setSpatialCenter)
# add the cadDock
# 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)
self.spatialTemporalVis.sigMapViewAdded.connect(self.onMapViewAdded)
#QgsProject.instance().addMapLayer(temporalProfileLayer)
eotimeseriesviewer.labeling.MAP_LAYER_STORES.append(self.mMapLayerStore)
eotimeseriesviewer.labeling.registerLabelShortcutEditorWidget()
self.initQGISConnection()
for toolBar in self.ui.findChildren(QToolBar):
for toolButton in toolBar.findChildren(QToolButton):
assert isinstance(toolButton, QToolButton)
if isinstance(toolButton.defaultAction(), QAction) and isinstance(toolButton.defaultAction().menu(), QMenu):
toolButton.setPopupMode(QToolButton.MenuButtonPopup)
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 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'
"""
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
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 = QProgressDialog()
progressDialog.setWindowTitle('Save Map Images...')
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.addLayer(self.spectralTemporalVis.temporalProfileLayer())
mapView.addLayer(self.spectralLibrary())
def temporalProfileLayer(self)->QgsVectorLayer:
"""
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 showTimeSeriesDatum(self, tsd:TimeSeriesDatum):
"""
Moves the viewport of the scroll window to a specific TimeSeriesDatum
:param tsd: TimeSeriesDatum
"""
assert isinstance(tsd, TimeSeriesDatum)
self.spatialTemporalVis.navigateToTSD(tsd)

Benjamin Jakimow
committed
def mapCanvases(self)->list:
"""
Returns all MapCanvases of the spatial visualization
:return: [list-of-MapCanvases]
"""
return self.spatialTemporalVis.mapCanvases()
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)
self.spatialTemporalVis.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 ca in m.actions():
assert isinstance(ca, QAction)
if ca == a:
self.ui.actionSelectFeatures.setIcon(a.icon())
self.ui.actionSelectFeatures.setToolTip(a.toolTip())
ca.setChecked(ca == a)
self.setMapTool(MapTools.SelectFeature)

Benjamin Jakimow
committed
def onCrosshairPositionChanged(self, spatialPoint:SpatialPoint):
"""
Synchronizes all crosshair positions. Takes care of CRS differences.
:param spatialPoint: SpatialPoint of the new Crosshair position
"""
sender = self.sender()
from .mapcanvas import MapCanvas
for mapCanvas in self.mapCanvases():
if isinstance(mapCanvas, MapCanvas) and mapCanvas != sender:
mapCanvas.setCrosshairPosition(spatialPoint, emitSignal=False)
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.spatialTemporalVis.setSpatialExtent(SpatialExtent.fromMapCanvas(iface.mapCanvas())))
self.ui.actionExportExtent.triggered.connect(lambda: iface.mapCanvas().setExtent(self.spatialTemporalVis.spatialExtent().toCrs(iface.mapCanvas().mapSettings().destinationCrs())))
self.ui.actionExportCenter.triggered.connect(lambda: iface.mapCanvas().setCenter(self.spatialTemporalVis.spatialExtent().spatialCenter()))
self.ui.actionImportCenter.triggered.connect(lambda: self.spatialTemporalVis.setSpatialCenter(SpatialPoint.fromMapCanvasCenter(iface.mapCanvas())))
self.spatialTemporalVis.sigSpatialExtentChanged.connect(lambda: self.spatialTemporalVis.syncQGISCanvasCenter(False))
iface.mapCanvas().extentsChanged.connect(lambda: self.spatialTemporalVis.syncQGISCanvasCenter(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):
"""
Reads the QSettings object and applies its value 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])
self.mTimeSeries.setDateTimePrecision(value(Keys.DateTimePrecision))
self.spatialTemporalVis.mMapRefreshTimer.start(value(Keys.MapUpdateInterval))
self.spatialTemporalVis.setMapBackgroundColor(value(Keys.MapBackgroundColor))
self.spatialTemporalVis.setMapSize(value(Keys.MapSize))
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:
"""
self.spatialTemporalVis.setMapTool(mapToolKey)
def setSpatialExtent(self, spatialExtent:SpatialExtent):
Sets the map canvas extent
:param spatialExtent: SpatialExtent
self.spatialTemporalVis.setSpatialExtent(spatialExtent)
def setSpatialCenter(self, spatialPoint:SpatialPoint):
"""
Sets the center of map canvases
:param spatialPoint: SpatialPoint
"""
self.spatialTemporalVis.setSpatialCenter(spatialPoint)
def spatialCenter(self)->SpatialPoint:
return self.spatialTemporalVis.spatialCenter()
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)
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
@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):
# self.spatialTemporalVis.sigShowProfiles.connect(self.spectralTemporalVis.loadCoordinate)
assert isinstance(spatialPoint, SpatialPoint)
assert isinstance(mapCanvas, QgsMapCanvas)
from eotimeseriesviewer.mapcanvas import MapTools
assert mapToolKey in MapTools.mapToolKeys()
if mapToolKey == MapTools.TemporalProfile:
self.spectralTemporalVis.loadCoordinate(spatialPoint)
elif mapToolKey == MapTools.SpectralProfile:
tsd = None
from .mapcanvas import MapCanvas
if isinstance(mapCanvas, MapCanvas):
tsd = mapCanvas.tsd()
if not hasattr(self, 'cntSpectralProfile'):
self.cntSpectralProfile = 0
profiles = SpectralProfile.fromMapCanvas(mapCanvas, spatialPoint)
if isinstance(tsd, TimeSeriesDatum):
profiles2 = []
sl = self.spectralLibrary()
if isinstance(sl, SpectralLibrary):
for p in profiles:
self.cntSpectralProfile += 1
assert isinstance(p, SpectralProfile)
p2 = p.copyFieldSubset(fields=sl.fields())
p2.setName('Profile {} {}'.format(self.cntSpectralProfile, tsd.mDate))
p2.setAttribute('date', '{}'.format(tsd.mDate))
p2.setAttribute('doy', int(tsd.mDOY))
p2.setAttribute('sensor', tsd.mSensor.name())
profiles2.append(p2)
self.ui.dockSpectralLibrary.SLW.setCurrentSpectra(profiles2)
elif mapToolKey == MapTools.CursorLocation:
self.ui.dockCursorLocation.loadCursorLocation(spatialPoint, mapCanvas)
else:
s = ""
pass
def messageBar(self)->QgsMessageBar:
"""
Returns the QgsMessageBar that is used to show messages in the TimeSeriesViewer UI.
:return: QgsMessageBar
"""
return self.ui.messageBar
def loadImageFiles(self, files:list):
"""
Loads image files to the time series.
:param files: [list-of-file-paths]
"""
assert isinstance(files, list)
progressDialog = QProgressDialog(parent=self.ui)
progressDialog.setWindowTitle('Load data')
progressDialog.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
progressDialog.show()
QApplication.processEvents()
self.mTimeSeries.addSources(files, progressDialog=progressDialog)
progressDialog.hide()
progressDialog.setParent(None)
def loadTimeSeriesDefinition(self, path:str=None, n_max:int=None):
"""
Loads a time series definition file
:param path:
:param n_max:
:return:
"""
if not (isinstance(path, str) and os.path.isfile(path)):
defFile = s.value('file_ts_definition')
defDir = None
if defFile is not None:
defDir = os.path.dirname(defFile)
filters = "CSV (*.csv *.txt);;" + \
"All files (*.*)"
path, filter = QFileDialog.getOpenFileName(caption='Load Time Series definition', directory=defDir, filter=filters)
if path is not None and os.path.exists(path):
progressDialog = QProgressDialog(parent=self.ui)
progressDialog.setWindowTitle('Load data')
progressDialog.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
progressDialog.show()
self.clearTimeSeries()
self.mTimeSeries.loadFromFile(path, n_max=n_max, progressDialog=progressDialog)
progressDialog.hide()
progressDialog.setParent(None)
"""
Create a new MapView
"""
def mapViews(self)->list:
"""
Returns all MapViews
:return: [list-of-MapViews]
"""
return self.spatialTemporalVis.MVC[:]
def zoomTo(self, key):
ext = self.mTimeSeries.maxSpatialExtent(self.ui.dockRendering.crs())
elif key == 'zoomPixelScale':
extent = self.spatialTemporalVis.spatialExtent()

benjamin.jakimow@geo.hu-berlin.de
committed
#calculate in web-mercator for metric distances
crs = self.spatialTemporalVis.crs()
crsWMC = QgsCoordinateReferenceSystem('EPSG:3857')
extentWMC = extent.toCrs(crsWMC)
pxSize = max(self.mTimeSeries.pixelSizes(), key= lambda s :s.width())
canvasSize = self.spatialTemporalVis.mapSize()
f = 0.05
width = f * canvasSize.width() * pxSize.width() # width in map units
height = f * canvasSize.height() * pxSize.height()

benjamin.jakimow@geo.hu-berlin.de
committed
ext = SpatialExtent(crsWMC, 0, 0, width, height)
ext.setCenter(extentWMC.center())
#return to original CRS
ext = ext.toCrs(crs)
else:
raise NotImplementedError(key)
self.spatialTemporalVis.setSpatialExtent(ext)
def icon(self)->QIcon:
"""
Returns the EO Time Series Viewer icon
:return: QIcon
"""
import eotimeseriesviewer
return eotimeseriesviewer.icon()
def logMessage(self, message, tag, level):
m = message.split('\n')
if '' in message.split('\n'):
m = m[0:m.index('')]
m = '\n'.join(m)

benjamin.jakimow@geo.hu-berlin.de
committed
if DEBUG: print(message)

benjamin.jakimow@geo.hu-berlin.de
committed
if not re.search('timeseriesviewer', m):
if level in [Qgis.Critical, Qgis.Warning]:
self.ui.messageBar.pushMessage(tag, message, level=level)
print(r'{}({}): {}'.format(tag, level, message))

benjamin.jakimow@geo.hu-berlin.de
committed
def onTimeSeriesChanged(self, *args):

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

benjamin.jakimow@geo.hu-berlin.de
committed
if not self.mSpatialMapExtentInitialized:
if len(self.mTimeSeries) > 0: