[GRASS-SVN] r73487 - in grass-addons/grass7/vector: . v.what.strds.timestamp

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Oct 4 15:51:23 PDT 2018


Author: sbl
Date: 2018-10-04 15:51:23 -0700 (Thu, 04 Oct 2018)
New Revision: 73487

Added:
   grass-addons/grass7/vector/v.what.strds.timestamp/
   grass-addons/grass7/vector/v.what.strds.timestamp/Makefile
   grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.html
   grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.py
Log:
new, experimental addon v.what.strds.timestamp

Added: grass-addons/grass7/vector/v.what.strds.timestamp/Makefile
===================================================================
--- grass-addons/grass7/vector/v.what.strds.timestamp/Makefile	                        (rev 0)
+++ grass-addons/grass7/vector/v.what.strds.timestamp/Makefile	2018-10-04 22:51:23 UTC (rev 73487)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../..
+
+PGM = v.what.strds.timestamp
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script


Property changes on: grass-addons/grass7/vector/v.what.strds.timestamp/Makefile
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/x-makefile
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.html
===================================================================
--- grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.html	                        (rev 0)
+++ grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.html	2018-10-04 22:51:23 UTC (rev 73487)
@@ -0,0 +1,37 @@
+<h2>DESCRIPTION</h2>
+
+<em>v.what.strds.timestamp</em> matches points with a timestamp in 
+the attribute table (<i>timestamp_column</i>) (e.g. recordings from 
+stationary (temperature logger, wildlife camera traps) or non-stationary 
+sensors (e.g GPS collars)) with Space Time Raster Datasets (STRDS) based 
+on point locaitions in space and time. Raster values at the specific 
+space-time position are written into the user-defined <i>column</i> in 
+the attribute table of the input vector map.
+
+<h2>NOTES</h2>
+
+The SQLite DB backend does not provide specific date/datetime datatypes. 
+However, text columns with ISO formated date strings are supported for 
+the <em>timestamp_column</em> as well.
+
+<p>
+Curretnly, <em>only STRDS with absolute temporal type are supported.</em>
+</p>
+
+<h2>EXAMPLE</h2>
+
+TBD
+
+<h2>SEE ALSO</h2>
+<em>
+<a href="v.what.rast.html">v.what.rast</a>, 
+<a href="v.what.strds.html">v.what.strds</a>, 
+<a href="t.rast.what.html">r.connectivity.corridors</a>
+</em>
+
+<h2>AUTHOR</h2>
+Stefan Blumentrath, Norwegian Institute for Nature Research (NINA)<br>
+Written for the 2018 <a href="irsae.no">IRSAE</a> GRASS GIS course at 
+Studenterhytta, Oslo
+<br>
+<p></p><i>Last changed: $Date$</i>


Property changes on: grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.html
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/html
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.py
===================================================================
--- grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.py	2018-10-04 22:51:23 UTC (rev 73487)
@@ -0,0 +1,255 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:       v.what.strds.timestamp
+# AUTHOR(S):    Stefan Blumentrath, NINA, based on
+#               v.what.strds by Luca delucchi
+#               Written for the IRSAE GIS course 2018 in Oslo
+#
+# PURPOSE:      Uploads space time raster dataset values at positions of vector points to the table
+# COPYRIGHT:    (C) 2018 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (version 2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+#%module
+#% description: Uploads space time raster dataset values to the attribute table at positions of vector points in space and time.
+#% keyword: vector
+#% keyword: temporal
+#% keyword: sampling
+#% keyword: position
+#% keyword: querying
+#% keyword: attribute table
+#% keyword: timestamp
+#% keyword: time
+#%end
+
+#%option G_OPT_V_INPUT
+#%end
+
+#%option G_OPT_V_FIELD
+#%end
+
+#%option G_OPT_DB_COLUMN
+#%key: timestamp_column
+#%end
+
+#%option G_OPT_DB_COLUMN
+#%key: column
+#%end
+
+#%option G_OPT_DB_WHERE
+#%end
+
+#%option G_OPT_STRDS_INPUTS
+#% key: strds
+#%end
+
+#%option G_OPT_T_WHERE
+#% key: t_where
+#%end
+
+#%flag
+#% key: u
+#% label: Update column of attribute table in input vector map if it already exists
+#% description: Instead of creating a new vector map update the attribute table with value(s)
+#%end
+
+#%flag
+#% key: i
+#% label: Interpolate raster values from the four nearest pixels
+#%end
+
+"""
+To do:
+- implement usage of temporal envelope of vector points
+- implement relative temporal type
+"""
+import os
+try:
+    from subprocess import DEVNULL  # Python 3.
+except ImportError:
+    DEVNULL = open(os.devnull, 'wb')
+import grass.script as grass
+#from grass.exceptions import CalledModuleError
+import grass.temporal as tgis
+#from grass.pygrass.utils import copy as gcopy
+#from grass.pygrass.messages import Messenger
+from grass.pygrass.modules import Module
+
+# i18N
+import gettext
+gettext.install('grassmods', os.path.join(os.getenv("GISBASE"), 'locale'))
+
+def sample_relative(input, layer, timestamp_column, column, t_raster,
+                    where, i_flag):
+    """Point sampling in STRDS with relative temporal type
+    Not implemented yet.
+    """
+    start = t_raster["start_time"]
+    end = t_raster["end_time"]
+    raster_map = '{}@{}'.format(t_raster["name"], t_raster["mapset"])
+    where += """(julianday({0}) > date('{1}') AND \
+                julianday({0}) < date('{2}'))""".format(timestamp_column, start, end)
+
+def sample_absolute(input, layer, timestamp_column, column, t_raster,
+                    where, i_flag):
+    """Point sampling in STRDS with absolute temporal type
+    """
+    start = t_raster["start_time"]
+    end = t_raster["end_time"]
+    raster_map = '{}@{}'.format(t_raster["name"], t_raster["mapset"])
+    where += """({0} > date('{1}') AND \
+                {0} < date('{2}'))""".format(timestamp_column, start, end)
+
+    grass.verbose(_('Sampling points between {} and {}'.format(start, end)))
+
+    # If only one core is used, processing can be faster if computational region is temporarily moved
+    # to where datapoints are (e.g. in case of tracking data)
+    # Move computational region temporarily to where points are in
+    # in space and time
+    treg = grass.parse_command('v.db.select', flags='r',
+                               map=input, where=where, quiet=True) # stderr=subproess.PIPE,
+
+    if len(set(treg.values())) > 1:
+        grass.use_temp_region()
+        grass.run_command("g.region", n=treg['n'], s=treg['s'], e=treg['e'],
+                          w=treg['w'], align=raster_map)
+
+        # Sample spatio-temporally matching points and raster map
+        rast_what = Module('v.what.rast', map=input, layer=layer,
+                           column=column, raster=raster_map,
+                           where=where, stderr_=DEVNULL, quiet=True)
+        rast_what.flags.i = i_flag
+        rast_what.run()
+
+def main():
+    # Get the options
+    input = options["input"]
+    timestamp_column = options["timestamp_column"]
+    columns = options["column"]
+    layer = options["layer"]
+    where = options["where"]
+    strds = options["strds"]
+    tempwhere = options["t_where"]
+    i_flag = flags["i"]
+
+    if where == "" or where == " " or where == "\n":
+        where = None
+
+    # overwrite = grass.overwrite()
+
+    # Set verbosity level
+    # quiet = True
+    # if grass.verbosity() > 2:
+    #     quiet = False
+
+    grass.warning(_('This addon is experimental!'))
+
+    # Check DB connection for input vector map
+    dbcon = grass.vector_layer_db(input, layer)
+    # Check the number of sample strds and the number of columns
+    strds_names = strds.split(",")
+    column_names = columns.split(",")
+    if not len(column_names) == len(strds_names):
+        grass.fatal(_('Number of columns and number of STRDS does not match.'))
+
+    # Check type of timestamp column
+    cols = grass.vector_columns(input, layer=layer)
+    if not timestamp_column in cols.keys():
+        grass.fatal(_('Could not find column {} \
+                    in table connected to vector map {} \
+                    at layer {}'.format(timestamp_column, input, layer)))
+    if cols[timestamp_column]['type'] != 'DATE':
+        if dbcon['driver'] != 'sqlite':
+            # Note that SQLite does not have a DATE datatype and
+            # and an index does not significantly speedup the process
+            # (at least not with a couple of 100 points)
+            grass.warning(_('Timestamp column is of type {}. \
+                            It is recommended to use DATE type with an index. \
+                            '.format(cols[timestamp_column]['type'])))
+
+    # Make sure the temporal database exists
+    tgis.init()
+    # We need a database interface
+    dbif = tgis.SQLDatabaseInterfaceConnection()
+    dbif.connect()
+
+    # Limit temporal extent to extent of points if no tempwhere is given
+    if not tempwhere:
+        extent = []
+        for stat in ('min', 'max'):
+            tsql = "SELECT {}({}) FROM {}".format(stat, timestamp_column,
+                                                  dbcon['table'])
+            extent.append(grass.read_command('db.select', flags='c',
+                                             sql=tsql))
+
+        grass.verbose(_('Temporal extent of vector points map is \
+                      {} to {}'.format(extent[0], extent[1])))
+    else:
+        tempwhere = '({}) AND '.format(tempwhere)
+
+    # Loop over STRDS
+    counter = 0
+    for strds_name in strds_names:
+
+        cur_strds = tgis.open_old_stds(strds_name, "strds", dbif)
+
+        granu = cur_strds.get_granularity()
+        start_time = tgis.datetime_math.check_datetime_string(extent[0])
+        start_gran = tgis.datetime_math.adjust_datetime_to_granularity(start_time, granu).isoformat()
+        tempwhere += "(end_time > '{}' and start_time <= '{}')".format(start_gran, extent[1]) # needs to be set properly
+
+        # Get info on registered maps in STRDS
+        rows = cur_strds.get_registered_maps("name,mapset,start_time,end_time",
+                                             tempwhere, "start_time",
+                                             dbif)
+
+        # Check temporal type and
+        # define sampling function to use
+        # becomes relevant when temporal type relative gets implemented
+        if cur_strds.is_time_relative():
+            grass.fatal(_('Sorry, STRDS of relative temporal type is not (yet) supported'))
+            sample = sample_relative
+        else:
+            sample = sample_absolute
+
+        # Check if there are raster maps to sample from that fullfill
+        # temporal conditions
+        if not rows and not tempwhere:
+            dbif.close()
+            grass.fatal(_("Space time raster dataset <%s> is empty".format(cur_strds.get_id())))
+        elif not rows and tempwhere:
+            dbif.close()
+            grass.fatal(_("No maps selected from Space time raster dataset <%s>, \
+                          or dataset is empty".format(cur_strds.get_id())))
+
+        # Include temporal condition into where clause
+        where_clause = '({}) AND '.format(where) if where else ''
+
+        # Loop over registered maps in STRDS
+        row_number = 0
+        for row in rows:
+            # If r.what had a where option, r.what could be used to
+            # collect raster values (without interpolation)
+            # in a ParallelModuleQueue to collect values using multiple
+            # cores and then upload results in one operation
+
+            sample(input, layer, timestamp_column,
+                   column_names[counter], row, where_clause, i_flag)
+
+            row_number += 1
+            grass.percent(row_number, len(rows), 3)
+        counter = counter + 1
+
+    dbif.close()
+    grass.vector_history(input)
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    main()
+


Property changes on: grass-addons/grass7/vector/v.what.strds.timestamp/v.what.strds.timestamp.py
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/x-python
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property


More information about the grass-commit mailing list