Skip to content
Snippets Groups Projects
profilevisualization.py 81.1 KiB
Newer Older
# -*- coding: utf-8 -*-
"""
/***************************************************************************
                              -------------------
        begin                : 2017-08-04
        git sha              : $Format:%H$
        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
import os, sys, pickle, datetime
from collections import OrderedDict
from qgis.gui import *
from qgis.core import *
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtXml import *
from qgis.PyQt.QtGui import *

from timeseriesviewer import jp, SETTINGS
from timeseriesviewer.timeseries import *
from timeseriesviewer.utils import SpatialExtent, SpatialPoint, px2geo
from timeseriesviewer.ui.docks import TsvDockWidgetBase, loadUI
from timeseriesviewer.plotstyling import PlotStyle, PlotStyleButton
Benjamin Jakimow's avatar
Benjamin Jakimow committed
from timeseriesviewer.pixelloader import PixelLoader, PixelLoaderTask
from timeseriesviewer.sensorvisualization import SensorListModel
from timeseriesviewer.temporalprofiles2d import *
from timeseriesviewer.temporalprofiles3d import *
from timeseriesviewer.temporalprofiles3d import LABEL_EXPRESSION_3D
Benjamin Jakimow's avatar
Benjamin Jakimow committed
from pyqtgraph import functions as fn
from pyqtgraph import AxisItem


DEBUG = False
OPENGL_AVAILABLE = False
MATPLOTLIB_AVAILABLE = False
try:
    import timeseriesviewer.temporalprofiles3dMPL
    MATPLOTLIB_AVAILABLE = True

except Exception as ex:
    print('unable to import matlotlib based 3d plotting:\n{}'.format(ex))
    OPENGL_AVAILABLE = True
    from timeseriesviewer.temporalprofiles3d import *
    #t = ViewWidget3D()
    #del t
except Exception as ex:
    print('unable to import OpenGL based packages:\n{}'.format(ex))

def getTextColorWithContrast(c):
    assert isinstance(c, QColor)
    if c.lightness() < 0.5:
        return QColor('white')
    else:
        return QColor('black')
def selectedModelIndices(tableView):
    assert isinstance(tableView, QTableView)
    result = {}

    sm = tableView.selectionModel()
    m = tableView.model()
    if isinstance(sm, QItemSelectionModel) and isinstance(m, QAbstractItemModel):
        for idx in sm.selectedIndexes():
            assert isinstance(idx, QModelIndex)
            if idx.row() not in result.keys():
                result[idx.row()] = idx
    return result.values()

Benjamin Jakimow's avatar
Benjamin Jakimow committed

class _SensorPoints(pg.PlotDataItem):
    def __init__(self, *args, **kwds):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        super(_SensorPoints, self).__init__(*args, **kwds)
        # menu creation is deferred because it is expensive and often
        # the user will never see the menu anyway.
        self.menu = None

    def boundingRect(self):
        return super(_SensorPoints,self).boundingRect()
        super(_SensorPoints, self).paint(p, *args)

    # On right-click, raise the context menu
    def mouseClickEvent(self, ev):
        if ev.button() == QtCore.Qt.RightButton:
            if self.raiseContextMenu(ev):
                ev.accept()

    def raiseContextMenu(self, ev):
        menu = self.getContextMenus()

        # Let the scene add on to the end of our context menu
        # (this is optional)
        menu = self.scene().addParentContextMenus(self, menu, ev)

        pos = ev.screenPos()
        menu.popup(QtCore.QPoint(pos.x(), pos.y()))
        return True

    # This method will be called when this item's _children_ want to raise
    # a context menu that includes their parents' menus.
    def getContextMenus(self, event=None):
        if self.menu is None:
            self.menu.setTitle(self.name + " options..")

            green = QAction("Turn green", self.menu)
            green.triggered.connect(self.setGreen)
            self.menu.addAction(green)
            self.menu.green = green

            blue = QAction("Turn blue", self.menu)
            blue.triggered.connect(self.setBlue)
            self.menu.addAction(blue)
            self.menu.green = blue

            alpha = QWidgetAction(self.menu)
            alphaSlider = QSlider()
            alphaSlider.setOrientation(QtCore.Qt.Horizontal)
            alphaSlider.setMaximum(255)
            alphaSlider.setValue(255)
            alphaSlider.valueChanged.connect(self.setAlpha)
            alpha.setDefaultWidget(alphaSlider)
            self.menu.addAction(alpha)
            self.menu.alpha = alpha
            self.menu.alphaSlider = alphaSlider
        return self.menu


Benjamin Jakimow's avatar
Benjamin Jakimow committed

class PlotSettingsModel2DWidgetDelegate(QStyledItemDelegate):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    """
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    """
    def __init__(self, tableView, timeSeries, temporalProfileListModel, parent=None):
        assert isinstance(tableView, QTableView)
        assert isinstance(timeSeries, TimeSeries)
        assert isinstance(temporalProfileListModel, TemporalProfileCollectionListModel)
        super(PlotSettingsModel2DWidgetDelegate, self).__init__(parent=parent)
        self._preferedSize = QgsFieldExpressionWidget().sizeHint()
        self.mTableView = tableView
        self.mTimeSeries = timeSeries
        self.mTemporalProfileListModel = temporalProfileListModel
        self.mSensorLayers = {}
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def setItemDelegates(self, tableView):
        assert isinstance(tableView, QTableView)
        model = tableView.model()

        assert isinstance(model, PlotSettingsModel2D)
        for c in [model.cnSensor, model.cnExpression, model.cnStyle, model.cnTemporalProfile]:
            i = model.columnNames.index(c)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            tableView.setItemDelegateForColumn(i, self)

    def getColumnName(self, index):
        assert index.isValid()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        model = index.model()
        assert isinstance(model, PlotSettingsModel2D)
        return model.columnNames[index.column()]
    """
    def sizeHint(self, options, index):
        s = super(ExpressionDelegate, self).sizeHint(options, index)
        exprString = self.tableView.model().data(index)
        l = QLabel()
        l.setText(exprString)
        x = l.sizeHint().width() + 100
        s = QSize(x, s.height())
        return self._preferedSize
    """
    def exampleLyr(self, sensor):
        assert isinstance(sensor, SensorInstrument)


        if sensor not in self.mSensorLayers.keys():

            crs = QgsCoordinateReferenceSystem('EPSG:4862')
            uri = 'Point?crs={}'.format(crs.authid())
            lyr = QgsVectorLayer(uri, 'LOCATIONS', 'memory')
            f = sensorExampleQgsFeature(sensor)
            assert isinstance(f, QgsFeature)
            assert lyr.startEditing()
            for field in f.fields():
                lyr.addAttribute(field)
            lyr.addFeature(f)
            lyr.commitChanges()
            self.mSensorLayers[sensor] = lyr
        return self.mSensorLayers[sensor]

    def createEditor(self, parent, option, index):
        cname = self.getColumnName(index)
        model = self.mTableView.model()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        w = None
        if index.isValid() and isinstance(model, PlotSettingsModel2D):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            plotStyle = model.idx2plotStyle(index)
            if isinstance(plotStyle, TemporalProfile2DPlotStyle):
                if cname == model.cnExpression and isinstance(plotStyle.sensor(), SensorInstrument):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                    w = QgsFieldExpressionWidget(parent=parent)
                    w.setExpression(plotStyle.expression())
                    w.setLayer(self.exampleLyr(plotStyle.sensor()))
                    plotStyle.sigSensorChanged.connect(lambda s : w.setLayer(self.exampleLyr(s)))
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                    w.setExpressionDialogTitle('Values')
                    w.setToolTip('Set an expression to specify the image band or calculate a spectral index.')
                    w.fieldChanged[str,bool].connect(lambda n, b : self.checkData(index, w, w.expression()))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

                elif cname == model.cnStyle:
                    w = PlotStyleButton(parent=parent)
                    w.setPlotStyle(plotStyle)
                    w.setToolTip('Set style.')
                    w.sigPlotStyleChanged.connect(lambda: self.checkData(index, w, w.plotStyle()))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

                elif cname == model.cnSensor:
                    w = QComboBox(parent=parent)
                    m = SensorListModel(self.mTimeSeries)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                    w.setModel(m)

                elif cname == model.cnTemporalProfile:
                    w = QComboBox(parent=parent)
                    w.setModel(self.mTemporalProfileListModel)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                else:
                    raise NotImplementedError()
    def checkData(self, index, w, value):
        assert isinstance(index, QModelIndex)
        model = self.mTableView.model()
        if index.isValid() and isinstance(model, PlotSettingsModel2D):
            plotStyle = model.idx2plotStyle(index)
            assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
            if isinstance(w, QgsFieldExpressionWidget):
                assert value == w.expression()
                assert w.isExpressionValid(value) == w.isValidExpression()

                if w.isValidExpression():
                    self.commitData.emit(w)
                else:
                    s = ""
                    #print(('Delegate commit failed',w.asExpression()))
            if isinstance(w, PlotStyleButton):
                self.commitData.emit(w)

    def setEditorData(self, editor, index):
        cname = self.getColumnName(index)
        model = self.mTableView.model()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        w = None
        if index.isValid() and isinstance(model, PlotSettingsModel2D):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            cname = self.getColumnName(index)
            if cname == model.cnExpression:
                lastExpr = index.model().data(index, Qt.DisplayRole)
                assert isinstance(editor, QgsFieldExpressionWidget)
                editor.setProperty('lastexpr', lastExpr)
                editor.setField(lastExpr)

            elif cname == model.cnStyle:
                style = index.data()
                assert isinstance(editor, PlotStyleButton)
                editor.setPlotStyle(style)

            elif cname == model.cnSensor:
                assert isinstance(editor, QComboBox)
                m = editor.model()
                assert isinstance(m, SensorListModel)
                sensor = index.data(role=Qt.UserRole)
                if isinstance(sensor, SensorInstrument):
                    idx = m.sensor2idx(sensor)
                    editor.setCurrentIndex(idx.row())
            elif cname == model.cnTemporalProfile:
                assert isinstance(editor, QComboBox)
                m = editor.model()
                assert isinstance(m, TemporalProfileCollectionListModel)
                TP = index.data(role=Qt.UserRole)
                if isinstance(TP, TemporalProfile):
                    idx = m.tp2idx(TP)
                    editor.setCurrentIndex(idx)
            else:
                raise NotImplementedError()

    def setModelData(self, w, model, index):
        cname = self.getColumnName(index)
        model = self.mTableView.model()
        if index.isValid() and isinstance(model, PlotSettingsModel2D):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            if cname == model.cnExpression:
                assert isinstance(w, QgsFieldExpressionWidget)
                expr = w.asExpression()
                exprLast = model.data(index, Qt.DisplayRole)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                if w.isValidExpression() and expr != exprLast:
                    model.setData(index, w.asExpression(), Qt.EditRole)

            elif cname == model.cnStyle:
                assert isinstance(w, PlotStyleButton)
                model.setData(index, w.plotStyle(), Qt.EditRole)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

            elif cname == model.cnSensor:
                assert isinstance(w, QComboBox)
                sensor = w.itemData(w.currentIndex(), role=Qt.UserRole)
                assert isinstance(sensor, SensorInstrument)
                model.setData(index, sensor, Qt.EditRole)

            elif cname == model.cnTemporalProfile:
                assert isinstance(w, QComboBox)
                TP = w.itemData(w.currentIndex(), role=Qt.UserRole)
                #assert isinstance(TP, TemporalProfile)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                model.setData(index, TP, Qt.EditRole)

            else:
                raise NotImplementedError()

class PlotSettingsModel3DWidgetDelegate(QStyledItemDelegate):
    """

    """
    def __init__(self, tableView, timeSeries, temporalProfileListModel, parent=None):
        assert isinstance(tableView, QTableView)
        assert isinstance(timeSeries, TimeSeries)
        assert isinstance(temporalProfileListModel, TemporalProfileCollectionListModel)
        super(PlotSettingsModel3DWidgetDelegate, self).__init__(parent=parent)
        self._preferedSize = QgsFieldExpressionWidget().sizeHint()
        self.mTableView = tableView
        self.mTimeSeries = timeSeries
        self.mTemporalProfileListModel = temporalProfileListModel
        self.mSensorLayers = {}
        self.mTemporalProfileListModel.dataChanged.connect(self.updateComboBoxes)
        self.mTimeSeries.sigSensorRemoved.connect(self.updateComboBoxes)



    def updateComboBoxes(self):

        # assert isinstance(cb, QComboBox)

        s = ""




    def setItemDelegates(self, tableView):
        assert isinstance(tableView, QTableView)
        model = tableView.model()
        assert isinstance(model, PlotSettingsModel3D)
        for c in [model.cnSensor, model.cnExpression, model.cnStyle, model.cnTemporalProfile]:
            i = model.columnNames.index(c)
            tableView.setItemDelegateForColumn(i, self)

    def getColumnName(self, index):
        assert index.isValid()
        model = index.model()
        assert isinstance(model, PlotSettingsModel3D)
        return model.columnNames[index.column()]
    """
    def sizeHint(self, options, index):
        s = super(ExpressionDelegate, self).sizeHint(options, index)
        exprString = self.tableView.model().data(index)
        l = QLabel()
        l.setText(exprString)
        x = l.sizeHint().width() + 100
        s = QSize(x, s.height())
        return self._preferedSize
    """
    def createEditor(self, parent, option, index):
        cname = self.getColumnName(index)
        model = self.mTableView.model()
        w = None
        if index.isValid() and isinstance(model, PlotSettingsModel3D):
            plotStyle = model.idx2plotStyle(index)
            if isinstance(plotStyle, TemporalProfile3DPlotStyle):
                if cname == model.cnExpression:
                    w = QgsFieldExpressionWidget(parent=parent)
                    w.setExpression(plotStyle.expression())
                    w.setLayer(self.exampleLyr(plotStyle.sensor()))
                    def onSensorAdded(s):
                        w.setLayer(self.exampleLyr(s))
                    #plotStyle.sigSensorChanged.connect(lambda s : w.setLayer(self.exampleLyr(s)))
                    plotStyle.sigSensorChanged.connect(onSensorAdded)
                    w.setExpressionDialogTitle('Values')
                    w.setToolTip('Set an expression to specify the image band or calculate a spectral index.')
                    w.fieldChanged[str,bool].connect(lambda n, b : self.checkData(index, w, w.expression()))

                elif cname == model.cnStyle:
                    w = TemporalProfile3DPlotStyleButton(parent=parent)
                    w.setPlotStyle(plotStyle)
                    w.setToolTip('Set plot style')
                    w.sigPlotStyleChanged.connect(lambda: self.checkData(index, w, w.plotStyle()))
                elif cname == model.cnSensor:
                    w = QComboBox(parent=parent)
                    m = SensorListModel(self.mTimeSeries)
                    w.setModel(m)

                elif cname == model.cnTemporalProfile:
                    w = QComboBox(parent=parent)
                    w.setModel(self.mTemporalProfileListModel)
                else:
                    raise NotImplementedError()
    def exampleLyr(self, sensor):

        if sensor not in self.mSensorLayers.keys():
            crs = QgsCoordinateReferenceSystem('EPSG:4862')
            uri = 'Point?crs={}'.format(crs.authid())
            lyr = QgsVectorLayer(uri, 'LOCATIONS', 'memory')
            assert sensor is None or isinstance(sensor, SensorInstrument)

            f = sensorExampleQgsFeature(sensor, singleBandOnly=True)
            assert isinstance(f, QgsFeature)
            assert lyr.startEditing()
            for field in f.fields():
                lyr.addAttribute(field)
            lyr.addFeature(f)
            lyr.commitChanges()
            self.mSensorLayers[sensor] = lyr
        return self.mSensorLayers[sensor]

    def checkData(self, index, w, value):
        assert isinstance(index, QModelIndex)
        model = self.mTableView.model()
        if index.isValid() and isinstance(model, PlotSettingsModel3D):
            plotStyle = model.idx2plotStyle(index)
            assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
Loading
Loading full blame...