Source code for temporal.temporal_topology_dataset_connector
"""
Temporal topology dataset connector class
Usage:
.. code-block:: python
>>> import grass.temporal as tgis
>>> tmr = tgis.TemporalTopologyDatasetConnector()
(C) 2012-2013 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.
:authors: Soeren Gebbert
"""
import copy
[docs]class TemporalTopologyDatasetConnector:
"""This class implements a temporal topology access structure to connect
temporal related datasets
This object will be set up by temporal topology creation method provided
by the SpatioTemporalTopologyBuilder.
If correctly initialize the calls next() and prev()
let the user walk temporally forward and backward in time.
The following temporal relations with access methods are supported:
- equal
- follows
- precedes
- overlaps
- overlapped
- during (including starts, finishes)
- contains (including started, finished)
- starts
- started
- finishes
- finished
.. code-block:: python
# We have build the temporal topology and we know the first map
start = first
while start:
# Print all maps this map temporally contains
dlist = start.get_contains()
for map in dlist:
map.print_info()
start = start.next()
.. code-block:: python
>>> import grass.temporal as tgis
>>> tgis.init()
>>> map = tgis.RasterDataset("a@P")
>>> tmr = tgis.TemporalTopologyDatasetConnector()
>>> tmr.set_next(map)
>>> tmr.set_prev(map)
>>> tmr.append_equal(map)
>>> tmr.append_follows(map)
>>> tmr.append_precedes(map)
>>> tmr.append_overlapped(map)
>>> tmr.append_overlaps(map)
>>> tmr.append_during(map)
>>> tmr.append_contains(map)
>>> tmr.append_starts(map)
>>> tmr.append_started(map)
>>> tmr.append_finishes(map)
>>> tmr.append_finished(map)
>>> tmr.print_temporal_topology_info()
+-------------------- Temporal Topology -------------------------------------+
| Next: ...................... a@P
| Previous: .................. a@P
| Equal:...................... a@P
| Follows: ................... a@P
| Precedes: .................. a@P
| Overlaps: .................. a@P
| Overlapped: ................ a@P
| During: .................... a@P
| Contains: .................. a@P
| Starts:.. .................. a@P
| Started:. .................. a@P
| Finishes:................... a@P
| Finished:................... a@P
>>> tmr.print_temporal_topology_shell_info()
next=a@P
prev=a@P
equal=a@P
follows=a@P
precedes=a@P
overlaps=a@P
overlapped=a@P
during=a@P
contains=a@P
starts=a@P
started=a@P
finishes=a@P
finished=a@P
>>> rlist = tmr.get_temporal_relations()
>>> if "FINISHED" in rlist.keys():
... print(rlist["FINISHED"][0].get_id())
...
a@P
"""
def __init__(self) -> None:
self.reset_temporal_topology()
[docs] def reset_temporal_topology(self) -> None:
"""Reset any information about temporal topology"""
self._temporal_topology = {}
self._has_temporal_topology = False
[docs] def get_temporal_relations(self):
"""Return the dictionary of temporal relationships
Keys are the temporal relationships in upper case,
values are abstract map objects.
:return: The temporal relations dictionary
"""
return copy.copy(self._temporal_topology)
[docs] def get_number_of_temporal_relations(self):
"""Return a dictionary in which the keys are the relation names and
the value are the number of relations.
The following relations are available:
- equal
- follows
- precedes
- overlaps
- overlapped
- during (including starts, finishes)
- contains (including started, finished)
- starts
- started
- finishes
- finished
To access topological information the temporal topology must be build
first using the SpatioTemporalTopologyBuilder.
:return: the dictionary with relations as keys and number as values
or None in case the topology wasn't build
"""
if self._has_temporal_topology is False:
return None
relations = {}
try:
relations["equal"] = len(self._temporal_topology["EQUAL"])
except KeyError:
relations["equal"] = 0
try:
relations["follows"] = len(self._temporal_topology["FOLLOWS"])
except KeyError:
relations["follows"] = 0
try:
relations["precedes"] = len(self._temporal_topology["PRECEDES"])
except KeyError:
relations["precedes"] = 0
try:
relations["overlaps"] = len(self._temporal_topology["OVERLAPS"])
except KeyError:
relations["overlaps"] = 0
try:
relations["overlapped"] = len(self._temporal_topology["OVERLAPPED"])
except KeyError:
relations["overlapped"] = 0
try:
relations["during"] = len(self._temporal_topology["DURING"])
except KeyError:
relations["during"] = 0
try:
relations["contains"] = len(self._temporal_topology["CONTAINS"])
except KeyError:
relations["contains"] = 0
try:
relations["starts"] = len(self._temporal_topology["STARTS"])
except KeyError:
relations["starts"] = 0
try:
relations["started"] = len(self._temporal_topology["STARTED"])
except KeyError:
relations["started"] = 0
try:
relations["finishes"] = len(self._temporal_topology["FINISHES"])
except KeyError:
relations["finishes"] = 0
try:
relations["finished"] = len(self._temporal_topology["FINISHED"])
except KeyError:
relations["finished"] = 0
return relations
[docs] def set_temporal_topology_build_true(self) -> None:
"""Same as name"""
self._has_temporal_topology = True
[docs] def set_temporal_topology_build_false(self) -> None:
"""Same as name"""
self._has_temporal_topology = False
[docs] def is_temporal_topology_build(self):
"""Check if the temporal topology was build"""
return self._has_temporal_topology
[docs] def set_next(self, map) -> None:
"""Set the map that is temporally as closest located after this map.
Temporally located means that the start time of the "next" map is
temporally located AFTER the start time of this map, but temporally
near than other maps of the same dataset.
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
self._temporal_topology["NEXT"] = map
[docs] def set_prev(self, map) -> None:
"""Set the map that is temporally as closest located before this map.
Temporally located means that the start time of the "previous" map
is temporally located BEFORE the start time of this map, but
temporally near than other maps of the same dataset.
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
self._temporal_topology["PREV"] = map
[docs] def next(self):
"""Return the map with a start time temporally located after
the start time of this map, but temporal closer than other maps
:return: A map object or None
"""
if "NEXT" not in self._temporal_topology:
return None
return self._temporal_topology["NEXT"]
[docs] def prev(self):
"""Return the map with a start time temporally located before
the start time of this map, but temporal closer than other maps
:return: A map object or None
"""
if "PREV" not in self._temporal_topology:
return None
return self._temporal_topology["PREV"]
[docs] def append_equal(self, map) -> None:
"""Append a map with equivalent temporal extent as this map
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "EQUAL" not in self._temporal_topology:
self._temporal_topology["EQUAL"] = []
self._temporal_topology["EQUAL"].append(map)
[docs] def get_equal(self):
"""Return a list of map objects with equivalent temporal extent as
this map
:return: A list of map objects or None
"""
if "EQUAL" not in self._temporal_topology:
return None
return self._temporal_topology["EQUAL"]
[docs] def append_starts(self, map) -> None:
"""Append a map that this map temporally starts with
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "STARTS" not in self._temporal_topology:
self._temporal_topology["STARTS"] = []
self._temporal_topology["STARTS"].append(map)
[docs] def get_starts(self):
"""Return a list of map objects that this map temporally starts with
:return: A list of map objects or None
"""
if "STARTS" not in self._temporal_topology:
return None
return self._temporal_topology["STARTS"]
[docs] def append_started(self, map) -> None:
"""Append a map that this map temporally started with
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "STARTED" not in self._temporal_topology:
self._temporal_topology["STARTED"] = []
self._temporal_topology["STARTED"].append(map)
[docs] def get_started(self):
"""Return a list of map objects that this map temporally started with
:return: A list of map objects or None
"""
if "STARTED" not in self._temporal_topology:
return None
return self._temporal_topology["STARTED"]
[docs] def append_finishes(self, map) -> None:
"""Append a map that this map temporally finishes with
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "FINISHES" not in self._temporal_topology:
self._temporal_topology["FINISHES"] = []
self._temporal_topology["FINISHES"].append(map)
[docs] def get_finishes(self):
"""Return a list of map objects that this map temporally finishes with
:return: A list of map objects or None
"""
if "FINISHES" not in self._temporal_topology:
return None
return self._temporal_topology["FINISHES"]
[docs] def append_finished(self, map) -> None:
"""Append a map that this map temporally finished with
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "FINISHED" not in self._temporal_topology:
self._temporal_topology["FINISHED"] = []
self._temporal_topology["FINISHED"].append(map)
[docs] def get_finished(self):
"""Return a list of map objects that this map temporally finished with
:return: A list of map objects or None
"""
if "FINISHED" not in self._temporal_topology:
return None
return self._temporal_topology["FINISHED"]
[docs] def append_overlaps(self, map) -> None:
"""Append a map that this map temporally overlaps
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "OVERLAPS" not in self._temporal_topology:
self._temporal_topology["OVERLAPS"] = []
self._temporal_topology["OVERLAPS"].append(map)
[docs] def get_overlaps(self):
"""Return a list of map objects that this map temporally overlaps
:return: A list of map objects or None
"""
if "OVERLAPS" not in self._temporal_topology:
return None
return self._temporal_topology["OVERLAPS"]
[docs] def append_overlapped(self, map) -> None:
"""Append a map that this map temporally overlapped
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "OVERLAPPED" not in self._temporal_topology:
self._temporal_topology["OVERLAPPED"] = []
self._temporal_topology["OVERLAPPED"].append(map)
[docs] def get_overlapped(self):
"""Return a list of map objects that this map temporally overlapped
:return: A list of map objects or None
"""
if "OVERLAPPED" not in self._temporal_topology:
return None
return self._temporal_topology["OVERLAPPED"]
[docs] def append_follows(self, map) -> None:
"""Append a map that this map temporally follows
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "FOLLOWS" not in self._temporal_topology:
self._temporal_topology["FOLLOWS"] = []
self._temporal_topology["FOLLOWS"].append(map)
[docs] def get_follows(self):
"""Return a list of map objects that this map temporally follows
:return: A list of map objects or None
"""
if "FOLLOWS" not in self._temporal_topology:
return None
return self._temporal_topology["FOLLOWS"]
[docs] def append_precedes(self, map) -> None:
"""Append a map that this map temporally precedes
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "PRECEDES" not in self._temporal_topology:
self._temporal_topology["PRECEDES"] = []
self._temporal_topology["PRECEDES"].append(map)
[docs] def get_precedes(self):
"""Return a list of map objects that this map temporally precedes
:return: A list of map objects or None
"""
if "PRECEDES" not in self._temporal_topology:
return None
return self._temporal_topology["PRECEDES"]
[docs] def append_during(self, map) -> None:
"""Append a map that this map is temporally located during
This includes temporal relationships starts and finishes
:param map: This object should be of type
AbstractMapDataset or derived classes
"""
if "DURING" not in self._temporal_topology:
self._temporal_topology["DURING"] = []
self._temporal_topology["DURING"].append(map)
[docs] def get_during(self):
"""Return a list of map objects that this map is temporally located during
This includes temporally relationships starts and finishes
:return: A list of map objects or None
"""
if "DURING" not in self._temporal_topology:
return None
return self._temporal_topology["DURING"]
[docs] def append_contains(self, map) -> None:
"""Append a map that this map temporally contains
This includes temporal relationships started and finished
:param map: This object should be of type AbstractMapDataset
or derived classes
"""
if "CONTAINS" not in self._temporal_topology:
self._temporal_topology["CONTAINS"] = []
self._temporal_topology["CONTAINS"].append(map)
[docs] def get_contains(self):
"""Return a list of map objects that this map temporally contains
This includes temporal relationships started and finished
:return: A list of map objects or None
"""
if "CONTAINS" not in self._temporal_topology:
return None
return self._temporal_topology["CONTAINS"]
def _generate_map_list_string(self, map_list, line_wrap: bool = True):
count = 0
string = ""
for map_ in map_list:
if line_wrap and count > 0 and count % 3 == 0:
string += "\n | ............................ "
count = 0
if count == 0:
string += map_.get_id()
else:
string += ",%s" % map_.get_id()
count += 1
return string
# Set the properties
equal = property(fget=get_equal, fset=append_equal)
follows = property(fget=get_follows, fset=append_follows)
precedes = property(fget=get_precedes, fset=append_precedes)
overlaps = property(fget=get_overlaps, fset=append_overlaps)
overlapped = property(fget=get_overlapped, fset=append_overlapped)
during = property(fget=get_during, fset=append_during)
contains = property(fget=get_contains, fset=append_contains)
starts = property(fget=get_starts, fset=append_starts)
started = property(fget=get_started, fset=append_started)
finishes = property(fget=get_finishes, fset=append_finishes)
finished = property(fget=get_finished, fset=append_finished)
[docs] def print_temporal_topology_info(self) -> None:
"""Print information about this class in human readable style"""
print(
" +-------------------- Temporal Topology -------------------------------------+" # noqa: E501
)
# 0123456789012345678901234567890
if self.next() is not None:
print(" | Next: ...................... " + str(self.next().get_id()))
if self.prev() is not None:
print(" | Previous: .................. " + str(self.prev().get_id()))
if self.equal is not None:
print(
" | Equal:...................... "
+ self._generate_map_list_string(self.equal)
)
if self.follows is not None:
print(
" | Follows: ................... "
+ self._generate_map_list_string(self.follows)
)
if self.precedes is not None:
print(
" | Precedes: .................. "
+ self._generate_map_list_string(self.precedes)
)
if self.overlaps is not None:
print(
" | Overlaps: .................. "
+ self._generate_map_list_string(self.overlaps)
)
if self.overlapped is not None:
print(
" | Overlapped: ................ "
+ self._generate_map_list_string(self.overlapped)
)
if self.during is not None:
print(
" | During: .................... "
+ self._generate_map_list_string(self.during)
)
if self.contains is not None:
print(
" | Contains: .................. "
+ self._generate_map_list_string(self.contains)
)
if self.starts is not None:
print(
" | Starts:.. .................. "
+ self._generate_map_list_string(self.starts)
)
if self.started is not None:
print(
" | Started:. .................. "
+ self._generate_map_list_string(self.started)
)
if self.finishes is not None:
print(
" | Finishes:................... "
+ self._generate_map_list_string(self.finishes)
)
if self.finished is not None:
print(
" | Finished:................... "
+ self._generate_map_list_string(self.finished)
)
[docs] def print_temporal_topology_shell_info(self) -> None:
"""Print information about this class in shell style"""
if self.next() is not None:
print("next=" + self.next().get_id())
if self.prev() is not None:
print("prev=" + self.prev().get_id())
if self.equal is not None:
print("equal=" + self._generate_map_list_string(self.equal, False))
if self.follows is not None:
print("follows=" + self._generate_map_list_string(self.follows, False))
if self.precedes is not None:
print("precedes=" + self._generate_map_list_string(self.precedes, False))
if self.overlaps is not None:
print("overlaps=" + self._generate_map_list_string(self.overlaps, False))
if self.overlapped is not None:
print(
"overlapped=" + self._generate_map_list_string(self.overlapped, False)
)
if self.during is not None:
print("during=" + self._generate_map_list_string(self.during, False))
if self.contains is not None:
print("contains=" + self._generate_map_list_string(self.contains, False))
if self.starts is not None:
print("starts=" + self._generate_map_list_string(self.starts))
if self.started is not None:
print("started=" + self._generate_map_list_string(self.started))
if self.finishes is not None:
print("finishes=" + self._generate_map_list_string(self.finishes))
if self.finished is not None:
print("finished=" + self._generate_map_list_string(self.finished))
###############################################################################
if __name__ == "__main__":
import doctest
doctest.testmod()