Browse Source

update tplot; starting implementation of stvds thanks to matej krejci for the initial patch

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@65640 15284696-431f-4ddb-bdfa-cd5b030d7da7
Luca Delucchi 9 years ago
parent
commit
66446da70f
2 changed files with 522 additions and 151 deletions
  1. 459 127
      gui/wxpython/tplot/frame.py
  2. 63 24
      gui/wxpython/tplot/g.gui.tplot.py

+ 459 - 127
gui/wxpython/tplot/frame.py

@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 """
 """
 @package frame
 @package frame
 
 
@@ -14,11 +16,20 @@ This program is free software under the GNU General Public License
 (>=v2). Read the file COPYING that comes with GRASS for details.
 (>=v2). Read the file COPYING that comes with GRASS for details.
 
 
 @author Luca Delucchi
 @author Luca Delucchi
+@author add stvds support-Matej Krejci
 """
 """
 from itertools import cycle
 from itertools import cycle
 import numpy as np
 import numpy as np
 
 
 import wx
 import wx
+from grass.pygrass.modules import Module
+
+import re
+import wx.lib.flatnotebook as FN
+from mapdisp.main import DMonGrassInterface
+from core.giface import StandaloneGrassInterface
+import grass.script as grass
+from core.utils import _
 
 
 try:
 try:
     import matplotlib
     import matplotlib
@@ -39,11 +50,24 @@ from core.utils import _
 
 
 import grass.temporal as tgis
 import grass.temporal as tgis
 from core.gcmd import GMessage, GError, GException, RunCommand
 from core.gcmd import GMessage, GError, GException, RunCommand
+from gui_core.widgets  import CoordinatesValidator
 from gui_core import gselect
 from gui_core import gselect
 from core import globalvar
 from core import globalvar
 from grass.pygrass.vector.geometry import Point
 from grass.pygrass.vector.geometry import Point
 from grass.pygrass.raster import RasterRow
 from grass.pygrass.raster import RasterRow
 from collections import OrderedDict
 from collections import OrderedDict
+from subprocess import PIPE
+import os
+import multiprocessing as multi
+try:
+    import wx.lib.agw.flatnotebook as FN
+except ImportError:
+    import wx.lib.flatnotebook as FN
+from core import globalvar
+from gui_core.widgets import GNotebook
+
+import ipdb
+
 ALPHA = 0.5
 ALPHA = 0.5
 COLORS = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
 COLORS = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
 
 
@@ -63,23 +87,44 @@ def check_version(*version):
         return True
         return True
 
 
 
 
+def findBetween(s, first, last):
+    try:
+        start = s.rindex(first) + len(first)
+        end = s.rindex(last, start)
+        return s[start:end]
+    except ValueError:
+        return ""
+
+
 class TplotFrame(wx.Frame):
 class TplotFrame(wx.Frame):
     """The main frame of the application"""
     """The main frame of the application"""
-    def __init__(self, parent):
+
+    def __init__(self, parent, giface):
         wx.Frame.__init__(self, parent, id=wx.ID_ANY,
         wx.Frame.__init__(self, parent, id=wx.ID_ANY,
                           title=_("GRASS GIS Temporal Plot Tool"))
                           title=_("GRASS GIS Temporal Plot Tool"))
 
 
         tgis.init(True)
         tgis.init(True)
-        self.datasets = []
-        self.output = None
-        self.timeData = {}
+        self._giface = giface
+        self.datasetsV = None
+        self.datasetsR = None
+        # self.vectorDraw=False
+        # self.rasterDraw=False
+        self.init()
         self._layout()
         self._layout()
-        self.temporalType = None
-        self.unit = None
+
         # We create a database interface here to speedup the GUI
         # We create a database interface here to speedup the GUI
         self.dbif = tgis.SQLDatabaseInterfaceConnection()
         self.dbif = tgis.SQLDatabaseInterfaceConnection()
         self.dbif.connect()
         self.dbif.connect()
 
 
+    def init(self):
+        self.timeDataR = {}
+        self.timeDataV = {}
+        self.temporalType = None
+        self.unit = None
+        self.listWhereConditions = []
+        self.plotNameListR = []
+        self.plotNameListV = []
+
     def __del__(self):
     def __del__(self):
         """Close the database interface and stop the messenger and C-interface
         """Close the database interface and stop the messenger and C-interface
            subprocesses.
            subprocesses.
@@ -94,14 +139,14 @@ class TplotFrame(wx.Frame):
              * mpl navigation toolbar
              * mpl navigation toolbar
              * Control panel for interaction
              * Control panel for interaction
         """
         """
-        self.panel = wx.Panel(self)
-
+        self.mainPanel = wx.Panel(self)
         # Create the mpl Figure and FigCanvas objects.
         # Create the mpl Figure and FigCanvas objects.
         # 5x4 inches, 100 dots-per-inch
         # 5x4 inches, 100 dots-per-inch
         #
         #
         # color =  wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
         # color =  wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
+        # ------------CANVAS AND TOOLBAR------------
         self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1))
         self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1))
-        self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig)
+        self.canvas = FigCanvas(self.mainPanel, wx.ID_ANY, self.fig)
         # axes are initialized later
         # axes are initialized later
         self.axes2d = None
         self.axes2d = None
         self.axes3d = None
         self.axes3d = None
@@ -113,52 +158,126 @@ class TplotFrame(wx.Frame):
         #
         #
         # Layout
         # Layout
         #
         #
-
+        # ------------MAIN VERTICAL SIZER------------
         self.vbox = wx.BoxSizer(wx.VERTICAL)
         self.vbox = wx.BoxSizer(wx.VERTICAL)
         self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
         self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
         self.vbox.Add(self.toolbar, 0, wx.EXPAND)
         self.vbox.Add(self.toolbar, 0, wx.EXPAND)
-        self.vbox.AddSpacer(10)
-
-        gridSizer = wx.GridBagSizer(hgap=5, vgap=5)
-
-        self.datasetSelect = gselect.Select(parent=self.panel, id=wx.ID_ANY,
-                                            size=globalvar.DIALOG_GSELECT_SIZE,
-                                            type='strds', multiple=True)
-        self.drawButton = wx.Button(self.panel, id=wx.ID_ANY, label=_("Draw"))
+        # self.vbox.AddSpacer(10)
+
+        # ------------ADD NOTEBOOK------------
+        self.ntb = GNotebook(parent=self.mainPanel, style=FN.FNB_FANCY_TABS)
+
+        # ------------ITEMS IN NOTEBOOK PAGE (RASTER)------------------------
+
+        self.controlPanelRaster = wx.Panel(parent=self.ntb, id=wx.ID_ANY)
+        self.datasetSelectLabelR = wx.StaticText(parent=self.controlPanelRaster,
+                                                 id=wx.ID_ANY,
+                                                 label=_('Raster temporal '
+                                                         'dataset (strds)'))
+
+        self.datasetSelectR = gselect.Select(parent=self.controlPanelRaster,
+                                             id=wx.ID_ANY,
+                                             size=globalvar.DIALOG_GSELECT_SIZE,
+                                             type='strds', multiple=True)
+        self.coor = wx.StaticText(parent=self.controlPanelRaster, id=wx.ID_ANY,
+                                  label=_('X and Y coordinates separated by '
+                                          'comma:'))
+        try:
+            self._giface.GetMapWindow()
+            self.coorval = gselect.CoordinatesSelect(parent=self.controlPanelRaster,
+                                                     giface=self._giface)
+        except:
+            self.coorval = wx.TextCtrl(parent=self.controlPanelRaster,
+                                       id=wx.ID_ANY,
+                                       size=globalvar.DIALOG_TEXTCTRL_SIZE,
+                                       validator=CoordinatesValidator())
+
+        self.coorval.SetToolTipString(_("Coordinates can be obtained for example"
+                                        " by right-clicking on Map Display."))
+        self.controlPanelSizerRaster = wx.BoxSizer(wx.VERTICAL)
+        # self.controlPanelSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY,
+        # label=_("Select space time raster dataset(s):")),
+        # pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+        self.controlPanelSizerRaster.Add(self.datasetSelectLabelR,
+                                         flag=wx.EXPAND)
+        self.controlPanelSizerRaster.Add(self.datasetSelectR, flag=wx.EXPAND)
+
+        self.controlPanelSizerRaster.Add(self.coor, flag=wx.EXPAND)
+        self.controlPanelSizerRaster.Add(self.coorval, flag=wx.EXPAND)
+
+        self.controlPanelRaster.SetSizer(self.controlPanelSizerRaster)
+        self.controlPanelSizerRaster.Fit(self)
+        self.ntb.AddPage(page=self.controlPanelRaster, text=_('STRDS'),
+                         name='STRDS')
+
+        # ------------ITEMS IN NOTEBOOK PAGE (VECTOR)------------------------
+        self.controlPanelVector = wx.Panel(parent=self.ntb, id=wx.ID_ANY)
+        self.datasetSelectLabelV = wx.StaticText(parent=self.controlPanelVector,
+                                                 id=wx.ID_ANY,
+                                                 label=_('Vector temporal '
+                                                         'dataset (strds)'))
+        self.datasetSelectV = gselect.Select(parent=self.controlPanelVector,
+                                             id=wx.ID_ANY,
+                                             size=globalvar.DIALOG_GSELECT_SIZE,
+                                             type='stvds', multiple=True)
+        self.datasetSelectV.Bind(wx.EVT_COMBOBOX_CLOSEUP,
+                                 self.OnVectorSelected)
+        self.attribute = gselect.ColumnSelect(parent=self.controlPanelVector)
+        self.attributeLabel = wx.StaticText(parent=self.controlPanelVector,
+                                            id=wx.ID_ANY,
+                                            label=_('Select attribute '))
+        # TODO fix the select
+        #self.cats = gselect.VectorCategorySelect(parent=self.controlPanelVector,
+        #                                         giface=self._giface)
+        self.catsLabel = wx.StaticText(parent=self.controlPanelVector,
+                                       id=wx.ID_ANY,
+                                       label=_('Select category of vector(s)'))
+
+        self.controlPanelSizerVector = wx.BoxSizer(wx.VERTICAL)
+        #self.controlPanelSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY,
+        #label=_("Select space time raster dataset(s):")),
+        #pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+        self.controlPanelSizerVector.Add(self.datasetSelectLabelV,
+                                         flag=wx.EXPAND)
+        self.controlPanelSizerVector.Add(self.datasetSelectV, flag=wx.EXPAND)
+
+        self.controlPanelSizerVector.Add(self.attributeLabel, flag=wx.EXPAND)
+        self.controlPanelSizerVector.Add(self.attribute, flag=wx.EXPAND)
+
+        self.controlPanelSizerVector.Add(self.catsLabel, flag=wx.EXPAND)
+        # TODO fix the select
+        #self.controlPanelSizerVector.Add(self.cats, flag=wx.EXPAND)
+
+        self.controlPanelVector.SetSizer(self.controlPanelSizerVector)
+        self.controlPanelSizerVector.Fit(self)
+        self.ntb.AddPage(page=self.controlPanelVector, text=_('STVDS'),
+                         name='STVDS')
+
+
+        # ------------Buttons on the bottom(draw,help)------------
+        self.vButtPanel = wx.Panel(self.mainPanel, id=wx.ID_ANY)
+        self.vButtSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        self.drawButton = wx.Button(self.vButtPanel, id=wx.ID_ANY,
+                                    label=_("Draw"))
         self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw)
         self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw)
-        self.helpButton = wx.Button(self.panel, id=wx.ID_ANY, label=_("Help"))
+        self.helpButton = wx.Button(self.vButtPanel, id=wx.ID_ANY,
+                                    label=_("Help"))
         self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp)
         self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp)
+        self.vButtSizer.Add(self.drawButton)
+        self.vButtSizer.Add(self.helpButton)
+        self.vButtPanel.SetSizer(self.vButtSizer)
 
 
-        self.coor = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
-                                  label=_('X and Y coordinates separated by comma:'))
-
-        self.coorval = wx.TextCtrl(parent=self.panel, id=wx.ID_ANY)
-        self.coorval.SetToolTipString(_("Coordinates can be obtained for example "
-                                        "by right-clicking on Map Display."))
-
-        gridSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY,
-                                    label=_("Select space time raster dataset(s):")),
-                      pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(self.datasetSelect, pos=(1, 0), flag=wx.EXPAND)
-
-        gridSizer.Add(self.coor, pos=(2, 0), flag=wx.EXPAND)
-
-        gridSizer.Add(self.coorval, pos=(3, 0), flag=wx.EXPAND)
-        gridSizer.Add(self.drawButton, pos=(3, 1), flag=wx.EXPAND)
-        gridSizer.Add(self.helpButton, pos=(3, 2), flag=wx.EXPAND)
-
-        self.vbox.Add(gridSizer, proportion=0, flag=wx.EXPAND | wx.ALL,
-                      border=10)
-
-        self.panel.SetSizer(self.vbox)
+        self.mainPanel.SetSizer(self.vbox)
+        self.vbox.Add(self.ntb, flag=wx.EXPAND)
+        self.vbox.Add(self.vButtPanel, flag=wx.EXPAND)
         self.vbox.Fit(self)
         self.vbox.Fit(self)
 
 
-    def _getData(self, timeseries):
+    def _getSTRDdata(self, timeseries):
         """Load data and read properties
         """Load data and read properties
-
         :param list timeseries: a list of timeseries
         :param list timeseries: a list of timeseries
         """
         """
-        self.timeData = OrderedDict()
+        self.timeDataR = OrderedDict()
         mode = None
         mode = None
         unit = None
         unit = None
         columns = ','.join(['name', 'start_time', 'end_time'])
         columns = ','.join(['name', 'start_time', 'end_time'])
@@ -169,18 +288,20 @@ class TplotFrame(wx.Frame):
             sp = tgis.dataset_factory(etype, fullname)
             sp = tgis.dataset_factory(etype, fullname)
             sp.select(dbif=self.dbif)
             sp.select(dbif=self.dbif)
 
 
-            self.timeData[name] = OrderedDict()
+            self.plotNameListR.append(series)
+            self.timeDataR[name] = OrderedDict()
             if not sp.is_in_db(dbif=self.dbif):
             if not sp.is_in_db(dbif=self.dbif):
                 GError(self, message=_("Dataset <%s> not found in temporal "
                 GError(self, message=_("Dataset <%s> not found in temporal "
                                        "database") % (fullname))
                                        "database") % (fullname))
                 return
                 return
 
 
-            self.timeData[name]['temporalDataType'] = etype
-            self.timeData[name]['temporalType'] = sp.get_temporal_type()
-            self.timeData[name]['granularity'] = sp.get_granularity()
+            self.timeDataR[name]['temporalDataType'] = etype
+            self.timeDataR[name]['temporalType'] = sp.get_temporal_type()
+            self.timeDataR[name]['granularity'] = sp.get_granularity()
+
             if mode is None:
             if mode is None:
-                mode = self.timeData[name]['temporalType']
-            elif self.timeData[name]['temporalType'] != mode:
+                mode = self.timeDataR[name]['temporalType']
+            elif self.timeDataR[name]['temporalType'] != mode:
                 GError(parent=self, message=_("Datasets have different temporal"
                 GError(parent=self, message=_("Datasets have different temporal"
                                               " type (absolute x relative), "
                                               " type (absolute x relative), "
                                               "which is not allowed."))
                                               "which is not allowed."))
@@ -188,14 +309,14 @@ class TplotFrame(wx.Frame):
 
 
             # check topology
             # check topology
             maps = sp.get_registered_maps_as_objects(dbif=self.dbif)
             maps = sp.get_registered_maps_as_objects(dbif=self.dbif)
-            self.timeData[name]['validTopology'] = sp.check_temporal_topology(maps=maps, dbif=self.dbif)
+            self.timeDataR[name]['validTopology'] = sp.check_temporal_topology(maps=maps, dbif=self.dbif)
 
 
-            self.timeData[name]['unit'] = None  # only with relative
-            if self.timeData[name]['temporalType'] == 'relative':
-                start, end, self.timeData[name]['unit'] = sp.get_relative_time()
+            self.timeDataR[name]['unit'] = None  # only with relative
+            if self.timeDataR[name]['temporalType'] == 'relative':
+                start, end, self.timeDataR[name]['unit'] = sp.get_relative_time()
                 if unit is None:
                 if unit is None:
-                    unit = self.timeData[name]['unit']
-                elif self.timeData[name]['unit'] != unit:
+                    unit = self.timeDataR[name]['unit']
+                elif self.timeDataR[name]['unit'] != unit:
                     GError(self, _("Datasets have different time unit which "
                     GError(self, _("Datasets have different time unit which "
                                    "is not allowed."))
                                    "is not allowed."))
                     return
                     return
@@ -203,14 +324,141 @@ class TplotFrame(wx.Frame):
             rows = sp.get_registered_maps(columns=columns, where=None,
             rows = sp.get_registered_maps(columns=columns, where=None,
                                           order='start_time', dbif=self.dbif)
                                           order='start_time', dbif=self.dbif)
             for row in rows:
             for row in rows:
-                self.timeData[name][row[0]] = {}
-                self.timeData[name][row[0]]['start_datetime'] = row[1]
-                self.timeData[name][row[0]]['end_datetime'] = row[2]
+                self.timeDataR[name][row[0]] = {}
+                self.timeDataR[name][row[0]]['start_datetime'] = row[1]
+                self.timeDataR[name][row[0]]['end_datetime'] = row[2]
                 r = RasterRow(row[0])
                 r = RasterRow(row[0])
                 r.open()
                 r.open()
                 val = r.get_value(self.poi)
                 val = r.get_value(self.poi)
                 r.close()
                 r.close()
-                self.timeData[name][row[0]]['value'] = val
+                self.timeDataR[name][row[0]]['value'] = val
+        self.unit = unit
+        self.temporalType = mode
+        return
+
+    def parseVDbConn(self, map, layerInp):
+        '''find attribute key according to layer of input map'''
+        vdb = Module('v.db.connect', map=map, flags='g', stdout_=PIPE)
+
+        vdb = vdb.outputs.stdout
+        for line in vdb.splitlines():
+            lsplit = line.split('|')
+            layer = lsplit[0].split('/')[0]
+            if layer == layerInp:
+                return lsplit[2]
+        return None
+
+    def _getSTVDData(self, timeseries):
+        """Load data and read properties
+        :param list timeseries: a list of timeseries
+        """
+        try:
+            len(self.timeDataV)
+        except:
+            self.timeDataV = OrderedDict()
+
+        # TODO parse categories to where condition
+        # cats = self.cats.GetValue()
+        cats = [str(i) for i in range(1,137)]
+        cats = ','.join(cats)
+
+        # idKye = 'linkid'  #TODO
+
+        mode = None
+        unit = None
+        attributes = self.attribute.GetValue()
+        columns = ','.join(['name', 'start_time', 'end_time', 'id', 'layer'])
+        for series in timeseries:
+            name = series[0]
+            fullname = name + '@' + series[1]
+            etype = series[2]
+            sp = tgis.dataset_factory(etype, fullname)
+            sp.select(dbif=self.dbif)
+            rows = sp.get_registered_maps(dbif=self.dbif, order="start_time",
+                                          columns=columns, where=None)
+            for attr in attributes.split(','):
+                for x, cat in enumerate(cats.split(',')):
+                    # TODO chck
+                    idKye = self.parseVDbConn(rows[x]['name'],
+                                              rows[x]['layer'])
+                    conditionWhere = idKye + '=' + cat
+                    self.listWhereConditions.append(conditionWhere)
+
+                    name = str(series) + str(conditionWhere)
+                    self.plotNameListV.append(name)
+
+                    self.timeDataV[name] = OrderedDict()
+                    if not sp.is_in_db(dbif=self.dbif):
+                        GError(self, message=_("Dataset <%s> not found in "
+                                               "temporal database") % (fullname))
+                        return
+
+                    self.timeDataV[name]['temporalDataType'] = etype
+                    self.timeDataV[name]['temporalType'] = sp.get_temporal_type()
+                    self.timeDataV[name]['granularity'] = sp.get_granularity()
+
+                    if mode is None:
+                        mode = self.timeDataV[name]['temporalType']
+                    elif self.timeDataV[name]['temporalType'] != mode:
+                        GError(parent=self, message=_("Datasets have different temporal"
+                                                      " type (absolute x relative), "
+                                                      "which is not allowed."))
+                        return
+
+                    # check topology
+                    maps = sp.get_registered_maps_as_objects(dbif=self.dbif)
+
+                    self.timeDataV[name]['validTopology'] = sp.check_temporal_topology(maps=maps, dbif=self.dbif)
+
+                    self.timeDataV[name]['unit'] = None  # only with relative
+                    if self.timeDataV[name]['temporalType'] == 'relative':
+                        start, end, self.timeDataV[name]['unit'] = sp.get_relative_time()
+                        if unit is None:
+                            unit = self.timeDataV[name]['unit']
+                        elif self.timeDataV[name]['unit'] != unit:
+                            GError(self, _("Datasets have different time unit"
+                                           " which is not allowed."))
+                            return
+
+                    workers = multi.cpu_count()
+                    # Check if workers are already being used
+                    # run all bands in parallel
+                    if "WORKERS" in os.environ:
+                        workers = int(os.environ["WORKERS"])
+                    else:
+                        workers = len(rows)
+                    # Initialize process dictionary
+                    proc = {}
+                    pout = {}
+
+                    for j, row in enumerate(rows):
+                        self.timeDataV[name][row[3]] = {}
+                        self.timeDataV[name][row[3]]['start_datetime'] = row[1]
+                        self.timeDataV[name][row[3]]['end_datetime'] = row[2]
+                        if self.timeDataV[name][row[3]]['end_datetime'] is None:
+                            self.timeDataV[name][row[3]]['end_datetime'] = row[1]
+                        proc[j] = grass.pipe_command('v.db.select',
+                                                     map=row['name'],
+                                                     layer=row['layer'],
+                                                     where=conditionWhere,
+                                                     columns=attr,
+                                                     flags='c')
+                        if j % workers is 0:
+                            # wait for the ones launched so far to finish
+                            for jj in range(j):
+                                if not proc[jj].stdout.closed:
+                                    pout[jj] = proc[jj].communicate()[0]
+                                proc[jj].wait()
+
+                    for row in range(len(proc)):
+                        if not proc[row].stdout.closed:
+                            pout[row] = proc[row].communicate()[0]
+                        proc[row].wait()
+
+                    for i, row in enumerate(rows):
+                        self.timeDataV[name][row[3]]['value'] = pout[i]
+
+                    ipdb.set_trace()
         self.unit = unit
         self.unit = unit
         self.temporalType = mode
         self.temporalType = mode
         return
         return
@@ -228,72 +476,141 @@ class TplotFrame(wx.Frame):
             self.convert = lambda x: x
             self.convert = lambda x: x
             self.invconvert = self.convert
             self.invconvert = self.convert
 
 
-        colors = cycle(COLORS)
+        self.colors = cycle(COLORS)
+
+        self.yticksNames = []
+        self.yticksPos = []
+        self.plots = []
+
+        if self.datasetsR:
+            self.lookUp = LookUp(self.timeDataR, self.invconvert)
+        else:
+            self.lookUp = LookUp(self.timeDataV, self.invconvert)
+
+        if self.datasetsR:
+            self.drawR()
+        if self.datasetsV:
+            self.drawV()
+
+        self.canvas.draw()
+        DataCursor(self.plots, self.lookUp, InfoFormat, self.convert)
 
 
-        yticksNames = []
-        yticksPos = []
-        plots = []
-        lookUp = LookUp(self.timeData, self.invconvert)
-        for i, name in enumerate(self.datasets):
+    def drawR(self):
+        for i, name in enumerate(self.datasetsR):
             name = name[0]
             name = name[0]
-            yticksNames.append(name)  # just name; with mapset it would be long
-            yticksPos.append(i)
+             # just name; with mapset it would be long
+            self.yticksNames.append(name)
+            self.yticksPos.append(1)  # TODO
             xdata = []
             xdata = []
             ydata = []
             ydata = []
-            for keys, values in self.timeData[name].iteritems():
+            for keys, values in self.timeDataR[name].iteritems():
                 if keys in ['temporalType', 'granularity', 'validTopology',
                 if keys in ['temporalType', 'granularity', 'validTopology',
                             'unit', 'temporalDataType']:
                             'unit', 'temporalDataType']:
                     continue
                     continue
                 xdata.append(self.convert(values['start_datetime']))
                 xdata.append(self.convert(values['start_datetime']))
                 ydata.append(values['value'])
                 ydata.append(values['value'])
 
 
-            lookUp.AddDataset(yranges=ydata, xranges=xdata, datasetName=name)
-            color = colors.next()
-            plots.append(self.axes2d.plot(xdata, ydata, marker='o',
-                                          color=color, label=name)[0])
+            self.lookUp.AddDataset(yranges=ydata, xranges=xdata,
+                                   datasetName=name)
+            color = self.colors.next()
+            self.plots.append(self.axes2d.plot(xdata, ydata, marker='o',
+                                               color=color,
+                                               label=self.plotNameListR[i])[0])
 
 
         if self.temporalType == 'absolute':
         if self.temporalType == 'absolute':
-            self.axes2d.set_xlabel(_("Temporal resolution: %s" % self.timeData[name]['granularity']))
+            self.axes2d.set_xlabel(_("Temporal resolution: %s" % self.timeDataR[name]['granularity']))
         else:
         else:
             self.axes2d.set_xlabel(_("Time [%s]") % self.unit)
             self.axes2d.set_xlabel(_("Time [%s]") % self.unit)
-        self.axes2d.set_ylabel(', '.join(yticksNames))
+        self.axes2d.set_ylabel(', '.join(self.yticksNames))
 
 
-        #legend
+        # legend
         handles, labels = self.axes2d.get_legend_handles_labels()
         handles, labels = self.axes2d.get_legend_handles_labels()
         self.axes2d.legend(loc=0)
         self.axes2d.legend(loc=0)
-        if self.output:
-            self.canvas.print_figure(filename=self.output, dpi=self.dpi)
+
+    def drawV(self):
+        for i, name in enumerate(self.plotNameListV):
+             # just name; with mapset it would be long
+            self.yticksNames.append(self.attribute.GetValue())
+            self.yticksPos.append(0)  # TODO
+            xdata = []
+            ydata = []
+            for keys, values in self.timeDataV[name].iteritems():
+                if keys in ['temporalType', 'granularity', 'validTopology',
+                            'unit', 'temporalDataType']:
+                    continue
+                xdata.append(self.convert(values['start_datetime']))
+                ydata.append(values['value'])
+
+            self.lookUp.AddDataset(yranges=ydata, xranges=xdata,
+                                   datasetName=name)
+            color = self.colors.next()
+            #print xdata
+            #print ydata
+
+            self.plots.append(self.axes2d.plot(xdata, ydata, marker='o',
+                                               color=color, label=name)[0])
+        # ============================
+        if self.temporalType == 'absolute':
+            self.axes2d.set_xlabel(_("Temporal resolution: %s" % self.timeDataV[name]['granularity']))
         else:
         else:
-            self.canvas.draw()
-            DataCursor(plots, lookUp, InfoFormat, self.convert)
+            self.axes2d.set_xlabel(_("Time [%s]") % self.unit)
+        self.axes2d.set_ylabel(', '.join(self.yticksNames))
+
+        # legend
+        handles, labels = self.axes2d.get_legend_handles_labels()
+        self.axes2d.legend(loc=0)
+        self.listWhereConditions = []
 
 
-    def OnRedraw(self, event):
+    def OnRedraw(self, event=None):
         """Required redrawing."""
         """Required redrawing."""
-        datasets = self.datasetSelect.GetValue().strip()
-        if not datasets:
+        self.init()
+        datasetsR = self.datasetSelectR.GetValue().strip()
+        datasetsV = self.datasetSelectV.GetValue().strip()
+
+        if not datasetsR and not datasetsV:
             return
             return
-        datasets = datasets.split(',')
-        try:
-            datasets = self._checkDatasets(datasets)
-            if not datasets:
+        # check raster dataset
+        if datasetsR:
+            datasetsR = datasetsR.split(',')
+            try:
+                datasetsR = self._checkDatasets(datasetsR)
+                if not datasetsR:
+                    return
+            except GException:
+                GError(parent=self, message=_("Invalid input raster dataset"))
                 return
                 return
-        except GException:
-            GError(parent=self, message=_("Invalid input data"))
-            return
 
 
-        self.datasets = datasets
-        try:
-            coordx, coordy = self.coorval.GetValue().split(',')
-            coordx, coordy = float(coordx), float(coordy)
-        except ValueError:
-            GMessage(_("Incorrect format of coordinates, should be: x,y"))
-        coors = [coordx, coordy]
-        if coors:
             try:
             try:
-                self.poi = Point(float(coors[0]), float(coors[1]))
+                coordx, coordy = self.coorval.coordsField.GetValue().split(',')
+                coordx, coordy = float(coordx), float(coordy)
+            except ValueError:
+                try:
+                    coordx, coordy = self.coorval.GetValue().split(',')
+                    coordx, coordy = float(coordx), float(coordy)
+                except ValueError:
+                    GMessage(_("Incorrect format of coordinates, should be: x,y"))
+            coors = [coordx, coordy]
+
+            if coors:
+                try:
+                    self.poi = Point(float(coors[0]), float(coors[1]))
+                except GException:
+                    GError(parent=self, message=_("Invalid input coordinates"))
+                    return
+            self.datasetsR = datasetsR
+
+        # check vector dataset
+        if datasetsV:
+            datasetsV = datasetsV.split(',')
+            try:
+                datasetsV = self._checkDatasets(datasetsV)
+                if not datasetsV:
+                    return
             except GException:
             except GException:
-                GError(parent=self, message=_("Invalid input coordinates"))
+                GError(parent=self, message=_("Invalid input vector dataset"))
                 return
                 return
+            self.datasetsV = datasetsV
+
         self._redraw()
         self._redraw()
 
 
     def _redraw(self):
     def _redraw(self):
@@ -301,7 +618,12 @@ class TplotFrame(wx.Frame):
 
 
         Decides if to draw also 3D and adjusts layout if needed.
         Decides if to draw also 3D and adjusts layout if needed.
         """
         """
-        self._getData(self.datasets)
+        if self.datasetsR:
+            self._getSTRDdata(self.datasetsR)
+
+        if self.datasetsV:
+            self._getSTVDData(self.datasetsV)
+
         # axes3d are physically removed
         # axes3d are physically removed
         if not self.axes2d:
         if not self.axes2d:
             self.axes2d = self.fig.add_subplot(1, 1, 1)
             self.axes2d = self.fig.add_subplot(1, 1, 1)
@@ -367,19 +689,23 @@ class TplotFrame(wx.Frame):
         """Function to show help"""
         """Function to show help"""
         RunCommand('g.manual', quiet=True, entry='g.gui.tplot')
         RunCommand('g.manual', quiet=True, entry='g.gui.tplot')
 
 
-    def SetDatasets(self, datasets, coors, output, dpi):
+    def SetDatasets(self, rasters, vectors, coors, cats, attr):
         """Set the data
         """Set the data
-
-        :param list datasets: a list of temporal dataset's name
+        #TODO
+        :param list rasters: a list of temporal raster dataset's name
+        :param list vectors: a list of temporal vector dataset's name
         :param list coors: a list with x/y coordinates
         :param list coors: a list with x/y coordinates
-        :param str output: the name of output png file
-        :param int dpi: the dpi value for png file
+        :param list cats: a list with incld. categories of vector
+        :param str attr:  name of atribute of vectror data
         """
         """
-        if not datasets or not coors:
+        if not (rasters or vectors) or not coors:
             return
             return
         try:
         try:
-            datasets = self._checkDatasets(datasets)
-            if not datasets:
+            if rasters:
+                self.datasetsR = self._checkDatasets(rasters)
+            if vectors:
+                self.datasetsV = self._checkDatasets(vectors)
+            if not (self.datasetsR or self.datasetsV):
                 return
                 return
         except GException:
         except GException:
             GError(parent=self, message=_("Invalid input temporal dataset"))
             GError(parent=self, message=_("Invalid input temporal dataset"))
@@ -389,17 +715,32 @@ class TplotFrame(wx.Frame):
         except GException:
         except GException:
             GError(parent=self, message=_("Invalid input coordinates"))
             GError(parent=self, message=_("Invalid input coordinates"))
             return
             return
-        self.datasets = datasets
-        self.output = output
-        self.dpi = dpi
-        self.datasetSelect.SetValue(','.join(map(lambda x: x[0] + '@' + x[1],
-                                                 datasets)))
-        self.coorval.SetValue(','.join(coors))
+        if self.datasetsV:
+            self.datasetSelectV.SetValue(','.join(map(lambda x: x[0] + '@' + x[1],
+                                                      self.datasetsV)))
+            self.attribute.SetValue(attr)
+        if self.datasetsR:
+            self.datasetSelectR.SetValue(','.join(map(lambda x: x[0] + '@' + x[1],
+                                                      self.datasetsR)))
+        try:
+            self.coorval.coordsField.SetValue(','.join(coors))
+        except:
+            self.coorval.SetValue(','.join(coors))
         self._redraw()
         self._redraw()
 
 
+    def OnVectorSelected(self, event):
+        """Update the controlbox related to stvds"""
+        dataset = self.datasetSelectV.GetValue().strip()
+        vect_list = grass.read_command('t.vect.list', flags='s', input=dataset,
+                                       col='name')
+        vect_list = list(set(sorted(vect_list.split())))
+        for vec in vect_list:
+            self.attribute.InsertColumns(vec, 1)
+
 
 
 class LookUp:
 class LookUp:
     """Helper class for searching info by coordinates"""
     """Helper class for searching info by coordinates"""
+
     def __init__(self, timeData, convert):
     def __init__(self, timeData, convert):
         self.data = {}
         self.data = {}
         self.timeData = timeData
         self.timeData = timeData
@@ -437,7 +778,8 @@ def InfoFormat(timeData, values):
         elif etype == 'str3ds':
         elif etype == 'str3ds':
             text.append(_("Space time 3D raster dataset: %s") % key)
             text.append(_("Space time 3D raster dataset: %s") % key)
 
 
-        text.append(_("Value for {date} is {val}".format(date=val[0], val=val[1])))
+        text.append(_("Value for {date} is {val}".format(date=val[0],
+                      val=val[1])))
         text.append('\n')
         text.append('\n')
     text.append(_("Press Del to dismiss."))
     text.append(_("Press Del to dismiss."))
 
 
@@ -452,6 +794,7 @@ class DataCursor(object):
     Source: http://stackoverflow.com/questions/4652439/
     Source: http://stackoverflow.com/questions/4652439/
             is-there-a-matplotlib-equivalent-of-matlabs-datacursormode/4674445
             is-there-a-matplotlib-equivalent-of-matlabs-datacursormode/4674445
     """
     """
+
     def __init__(self, artists, lookUp, formatFunction, convert,
     def __init__(self, artists, lookUp, formatFunction, convert,
                  tolerance=5, offsets=(-30, 20), display_all=False):
                  tolerance=5, offsets=(-30, 20), display_all=False):
         """Create the data cursor and connect it to the relevant figure.
         """Create the data cursor and connect it to the relevant figure.
@@ -538,14 +881,3 @@ class DataCursor(object):
             annotation.set_text(text)
             annotation.set_text(text)
             annotation.set_visible(True)
             annotation.set_visible(True)
             event.canvas.draw()
             event.canvas.draw()
-
-
-def run(parent=None, datasets=None):
-    frame = TplotFrame(parent)
-    if datasets:
-        frame.SetDatasets(datasets)
-    frame.Show()
-
-
-if __name__ == '__main__':
-    run()

+ 63 - 24
gui/wxpython/tplot/g.gui.tplot.py

@@ -21,31 +21,58 @@
 ############################################################################
 ############################################################################
 
 
 #%module
 #%module
-#% description: Allows the user to see in a plot the values of one or more temporal datasets for a queried point defined by a coordinate pair.
-#% keyword: general
-#% keyword: GUI
-#% keyword: temporal
+#% description: Allows the user to see in a plot the values of one or more temporal raser datasets for a queried point defined by a coordinate pair. Also allows to plot data of vector dataset for a defined categories and attribut.
+#% keywords: general
+#% keywords: GUI
+#% keywords: temporal
 #%end
 #%end
-#%option G_OPT_STDS_INPUTS
+
+#%option G_OPT_STVDS_INPUTS
+#% key: stvds
 #% required: no
 #% required: no
 #%end
 #%end
+
+#%option G_OPT_STRDS_INPUTS
+#% key: strds
+#% required: no
+#%end
+
 #%option G_OPT_M_COORDS
 #%option G_OPT_M_COORDS
 #% required: no
 #% required: no
 #%end
 #%end
+
+#TODO use option G_OPT_V_CATS
+#%option
+#% key: cats
+#% label: Categories of vectores features
+#% description: To use only with stvds
+#% required: no
+#%end
+
+
+#%option
+#% key: attr
+#% label: Name of attribute
+#% description: Name of attribute which represent data for plotting
+#% required: no
+#%end
+
 #%option G_OPT_F_OUTPUT
 #%option G_OPT_F_OUTPUT
 #% required: no
 #% required: no
 #% label: Name for output file
 #% label: Name for output file
 #% description: Add extension to specify format (.png, .pdf, .svg)
 #% description: Add extension to specify format (.png, .pdf, .svg)
 #%end
 #%end
+
 #%option
 #%option
-#% key: dpi
-#% type: integer
-#% label: The DPI for output image
-#% description: To use only with output parameter
+#% key: size
+#% type: string
+#% label: The size for output image
+#% description: It works only with output parameter
 #% required: no
 #% required: no
 #%end
 #%end
 
 
 import grass.script as gscript
 import grass.script as gscript
+from core.giface import StandaloneGrassInterface
 
 
 
 
 def main():
 def main():
@@ -57,26 +84,38 @@ def main():
         from tplot.frame import TplotFrame
         from tplot.frame import TplotFrame
     except ImportError as e:
     except ImportError as e:
         gscript.fatal(e.message)
         gscript.fatal(e.message)
-
-    datasets = options['inputs'].strip().split(',')
-    datasets = [data for data in datasets if data]
+    rasters = None
+    if options['strds']:
+        rasters = options['strds'].strip().split(',')
+    vectors = None
+    attr = None
+    if options['stvds']:
+        vectors = options['stvds'].strip().split(',')
+        if not options['attr']:
+            gscript.fatal(_("With stvds you have to use also 'attr' option"))
+        else:
+            attr = options['attr']
     coords = options['coordinates'].strip().split(',')
     coords = options['coordinates'].strip().split(',')
     output = options['output']
     output = options['output']
-    dpi = options['dpi']
-    dpi = int(dpi) if dpi else None
-    if dpi and not output:
-        gscript.warning(
-            _("No output filename set, so DPI option will not used"))
 
 
     app = wx.App()
     app = wx.App()
-    frame = TplotFrame(None)
-    frame.SetDatasets(datasets, coords, output, dpi)
+    frame = TplotFrame(parent=None, giface=StandaloneGrassInterface())
+    frame.SetDatasets(rasters, vectors, coords, None, attr)
     if output:
     if output:
-        return
-
-    frame.Show()
-    app.MainLoop()
-
+        frame.OnRedraw()
+        if options['size']:
+            sizes = options['size'].strip().split(',')
+            sizes = [int(s) for s in sizes]
+            frame.canvas.SetSize(sizes)
+        if output.split('.')[-1].lower() == 'png':
+            frame.canvas.print_png(output)
+        if output.split('.')[-1].lower() in ['jpg', 'jpeg']:
+            frame.canvas.print_jpg(output)
+        if output.split('.')[-1].lower() in ['tif', 'tiff']:
+            frame.canvas.print_tif(output)
+    else:
+        frame.Show()
+        app.MainLoop()
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
     main()
     main()