[GRASS-SVN] r74143 - in grass-addons/grass7/raster/r.estimap.recreation: . estimap_recreation images r.estimap.recreation
svn_grass at osgeo.org
svn_grass at osgeo.org
Fri Mar 1 03:47:49 PST 2019
Author: nikosa
Date: 2019-03-01 03:47:49 -0800 (Fri, 01 Mar 2019)
New Revision: 74143
Added:
grass-addons/grass7/raster/r.estimap.recreation/corine_accounting_to_maes_land_classes.rules
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/Makefile
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/__init__.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/accessibility.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/colors.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/components.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/constants.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/distance.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/grassy_utilities.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/labels.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/main.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/mobility.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/normalisation.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/panos.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/spectrum.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/supply_and_use.py
grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/utilities.py
grass-addons/grass7/raster/r.estimap.recreation/images/
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_area_of_interest.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_bathing_water_quality.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006_suitability.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_legend.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_demand.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_distance_to_infrastructure.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_land_suitability.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_local_administrative_units.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_mobility.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_opportunity.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_population_2015.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_1.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_2.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_3.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_4.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_based_on_corine_land_cover_2006.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_corine.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_masked.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_protected_areas.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum_high_provision_near.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_unmet_demand.png
grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_water_resources.png
grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/
grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/Makefile
grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.html
grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.py
grass-addons/grass7/raster/r.estimap.recreation/requirements-dev.txt
grass-addons/grass7/raster/r.estimap.recreation/setup.py
grass-addons/grass7/raster/r.estimap.recreation/test_integration.sh
Removed:
grass-addons/grass7/raster/r.estimap.recreation/area_of_interest.png
grass-addons/grass7/raster/r.estimap.recreation/bathing_water_quality.png
grass-addons/grass7/raster/r.estimap.recreation/corine_land_cover_2006.png
grass-addons/grass7/raster/r.estimap.recreation/corine_land_cover_2006_suitability.png
grass-addons/grass7/raster/r.estimap.recreation/corine_land_cover_legend.png
grass-addons/grass7/raster/r.estimap.recreation/demand.png
grass-addons/grass7/raster/r.estimap.recreation/distance_to_infrastructure.png
grass-addons/grass7/raster/r.estimap.recreation/land_suitability.png
grass-addons/grass7/raster/r.estimap.recreation/local_administrative_units.png
grass-addons/grass7/raster/r.estimap.recreation/mobility.png
grass-addons/grass7/raster/r.estimap.recreation/opportunity.png
grass-addons/grass7/raster/r.estimap.recreation/population_2015.png
grass-addons/grass7/raster/r.estimap.recreation/potential.png
grass-addons/grass7/raster/r.estimap.recreation/potential_1.png
grass-addons/grass7/raster/r.estimap.recreation/potential_2.png
grass-addons/grass7/raster/r.estimap.recreation/potential_3.png
grass-addons/grass7/raster/r.estimap.recreation/potential_4.png
grass-addons/grass7/raster/r.estimap.recreation/potential_based_on_corine_land_cover_2006.png
grass-addons/grass7/raster/r.estimap.recreation/potential_corine.png
grass-addons/grass7/raster/r.estimap.recreation/potential_masked.png
grass-addons/grass7/raster/r.estimap.recreation/protected_areas.png
grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.py
grass-addons/grass7/raster/r.estimap.recreation/spectrum.png
grass-addons/grass7/raster/r.estimap.recreation/spectrum_high_provision_near.png
grass-addons/grass7/raster/r.estimap.recreation/test.r.estimap.recreation.py
grass-addons/grass7/raster/r.estimap.recreation/unmet_demand.png
grass-addons/grass7/raster/r.estimap.recreation/water_resources.png
Modified:
grass-addons/grass7/raster/r.estimap.recreation/Makefile
grass-addons/grass7/raster/r.estimap.recreation/README.md
grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.html
Log:
r.estimap.recreation: Major refactoring, see also https://gitlab.com/natcapes/r.estimap.recreation/tags/v3.0
Modified: grass-addons/grass7/raster/r.estimap.recreation/Makefile
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/Makefile 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/Makefile 2019-03-01 11:47:49 UTC (rev 74143)
@@ -2,7 +2,12 @@
PGM = r.estimap.recreation
-include $(MODULE_TOPDIR)/include/Make/Script.make
-include $(MODULE_TOPDIR)/include/Make/Python.make
+SUBDIRS = estimap_recreation \
+ r.estimap.recreation
-default: script
+include $(MODULE_TOPDIR)/include/Make/Dir.make
+
+default: parsubdirs htmldir
+
+install: installsubdirs
+ $(INSTALL_DATA) $(PGM).html $(INST_DIR)/docs/html/
Modified: grass-addons/grass7/raster/r.estimap.recreation/README.md
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/README.md 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/README.md 2019-03-01 11:47:49 UTC (rev 74143)
@@ -1,7 +1,7 @@
Description
-----------
-*r.estimap* is an implementation of the ESTIMAP recreation algorithm to
+*r.estimap.recreation* is an implementation of the ESTIMAP recreation algorithm to
support mapping and modelling of ecosystem services (Zulian, 2014).
Examples
@@ -19,10 +19,10 @@
<div>
-![Example of a land suitability input map](area_of_interest.png)
-![Example of a land suitability input map](land_suitability.png)
-![Example of a water resources input map](water_resources.png) ![Example
-of a protected areas input map](protected_areas.png)
+![Example of a land suitability input map](images/r_estimap_recreation_area_of_interest.png)
+![Example of a land suitability input map](images/r_estimap_recreation_land_suitability.png)
+![Example of a water resources input map](images/r_estimap_recreation_water_resources.png) ![Example
+of a protected areas input map](images/r_estimap_recreation_protected_areas.png)
</div>
@@ -51,11 +51,11 @@
<div class="code">
- r.estimap land=land_suitability potential=potential
+ r.estimap.recreation land=land_suitability potential=potential
</div>
-![Example of a recreation potential output map](potential.png)
+![Example of a recreation potential output map](images/r_estimap_recreation_potential.png)
Note, this will process the input map `land_suitability` over the extent
defined previously via `g.region`, which is the standard behaviour in
@@ -66,12 +66,12 @@
<div class="code">
- r.estimap land=land_suitability mask=area_of_interest potential=potential_1
+ r.estimap.recreation land=land_suitability mask=area_of_interest potential=potential_1
</div>
![Example of a recreation potential output map while using a
-MASK](potential_1.png)
+MASK](images/r_estimap_recreation_potential_1.png)
The use of a mask (in GRASS GIS' terminology known as **MASK**) will
ignore areas of **No Data** (pixels in the `area_of_interest` map
@@ -93,12 +93,12 @@
<div class="code">
- r.estimap land=land_suitability water=water_resources potential=potential_2
+ r.estimap.recreation land=land_suitability water=water_resources potential=potential_2
</div>
![Example of a recreation potential output map while using a MASK, a
-land suitability map and a water resources map](potential_2.png)
+land suitability map and a water resources map](images/r_estimap_recreation_potential_2.png)
At this point it becomes clear that all `NULL` cells present in the
"water" map, are proagated in the output map `potential_2`.
@@ -109,13 +109,13 @@
<div class="code">
- r.estimap land=land_suitability water=water_resources natural=protected_areas potential=potential_3
+ r.estimap.recreation land=land_suitability water=water_resources natural=protected_areas potential=potential_3
</div>
![Example of a recreation potential output map while using a MASK, a
land suitability map, a water resources map and a natural resources
-map](potential_3.png)
+map](images/r_estimap_recreation_potential_3.png)
While the `land` option accepts only one map as an input, both the
`water` and the `natural` options accept multiple maps as inputs. In
@@ -124,7 +124,7 @@
<div class="code">
- r.estimap land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas potential=potential_4
+ r.estimap.recreation land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas potential=potential_4
</div>
@@ -133,7 +133,7 @@
![Example of a recreation potential output map while using a MASK, a
land suitability map, two water resources maps and a natural resources
-map](potential_4.png)
+map](images/r_estimap_recreation_potential_4.png)
This example, features also a title and a legend, so as to make sense of
the map.
@@ -164,13 +164,13 @@
`distance_to_infrastructure` is defined as an input:
![Example of an input map showing distances to
-infrastructure](distance_to_infrastructure.png)
+infrastructure](images/r_estimap_recreation_distance_to_infrastructure.png)
Naturally, we need to define the output map option `spectrum` too:
<div class="code">
- r.estimap \
+ r.estimap.recreation \
land=land_suitability \
water=water_resources,bathing_water_quality \
natural=protected_areas \
@@ -183,13 +183,13 @@
<div class="code">
- r.estimap land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure spectrum=spectrum
+ r.estimap.recreation land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure spectrum=spectrum
</div>
![Example of a recreation spectrum output map while using a MASK, a land
suitability map, a water resources map and a natural resources
-map](spectrum.png)
+map](images/r_estimap_recreation_spectrum.png)
Missing to define the `infrastructure` map, the command will abort and
inform about.
@@ -215,7 +215,7 @@
<div class="code">
- r.estimap \
+ r.estimap.recreation \
mask=area_of_interest \
land=land_suitability \
water=water_resources,bathing_water_quality \
@@ -230,13 +230,13 @@
<div class="code">
- r.estimap mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas spectrum=spectrum infrastructure=distance_to_infrastructure opportunity=opportunity
+ r.estimap.recreation mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas spectrum=spectrum infrastructure=distance_to_infrastructure opportunity=opportunity
</div>
![Example of a recreation spectrum output map while using a MASK, a land
suitability map, a water resources map and a natural resources
-map](opportunity.png)
+map](images/r_estimap_recreation_opportunity.png)
#### More input maps
@@ -252,7 +252,7 @@
Population
-![Fragment of a population map (GHSL, 2015)](population_2015.png)
+![Fragment of a population map (GHSL, 2015)](images/r_estimap_recreation_population_2015.png)
In this example, the population map named `population_2015` is of
1000m\^2.
@@ -260,7 +260,7 @@
Local administrative units
![Fragment of a local administrative units input
-map](local_administrative_units.png)
+map](images/r_estimap_recreation_local_administrative_units.png)
The map named `local_administrative_units` serves in the following
example as the base map for the zonal statistics to obtain the demand
@@ -270,7 +270,7 @@
<div class="code">
- r.estimap --o \
+ r.estimap.recreation --o \
mask=area_of_interest \
land=land_suitability \
water=water_resources,bathing_water_quality \
@@ -284,13 +284,13 @@
![Example of a demand distribution output map while using a MASK and
inputs for land suitability, water resources, natural resources,
-infrastructure, population and base](demand.png)
+infrastructure, population and base](images/r_estimap_recreation_demand.png)
#### Unmet Demand
<div class="code">
- r.estimap --o \
+ r.estimap.recreation --o \
mask=area_of_interest \
land=land_suitability \
water=water_resources,bathing_water_quality \
@@ -305,7 +305,7 @@
![Example of an 'unmet demand' output map while using a MASK and inputs
for land suitability, water resources, natural resources,
-infrastructure, population and base](unmet_demand.png)
+infrastructure, population and base](images/r_estimap_recreation_unmet_demand.png)
#### Mobility
@@ -336,7 +336,7 @@
<div class="code">
- r.estimap --o \
+ r.estimap.recreation --o \
mask=area_of_interest \
land=land_suitability \
water=water_resources,bathing_water_quality \
@@ -350,7 +350,7 @@
![Example of a mobility output map while using a MASK and inputs for
land suitability, water resources, natural resources, infrastructure,
-population and base](mobility.png)
+population and base](images/r_estimap_recreation_mobility.png)
#### All in one call
@@ -358,7 +358,7 @@
<div class="code">
- r.estimap --o \
+ r.estimap.recreation --o \
mask=area_of_interest \
land=land_suitability \
water=water_resources,bathing_water_quality \
@@ -441,8 +441,8 @@
<div>
-![Fragment from the CORINE land data base ](corine_land_cover_2006.png)
-![Legend for the CORINE land data base](corine_land_cover_legend.png)
+![Fragment from the CORINE land data base ](images/r_estimap_recreation_corine_land_cover_2006.png)
+![Legend for the CORINE land data base](images/r_estimap_recreation_corine_land_cover_legend.png)
</div>
@@ -487,18 +487,18 @@
<div class="code">
- r.estimap landuse=corine_land_cover_2006 suitability_scores=corine_suitability.scores potential=potential_corine --o
+ r.estimap.recreation landuse=corine_land_cover_2006 suitability_scores=corine_suitability.scores potential=potential_corine --o
</div>
![Example of a recreation spectrum output map while using a MASK, based
-on a fragment from the CORINE land data base](potential_corine.png)
+on a fragment from the CORINE land data base](images/r_estimap_recreation_potential_corine.png)
The same can be achieved with a long one-line string too:
<div class="code">
- r.estimap \
+ r.estimap.recreation \
landuse=corine_land_cover_2006 \
suitability_scores="1:1:0:0,2:2:0.1:0.1,3:9:0:0,10:10:1:1,11:11:0.1:0.1,12:13:0.3:0.3,14:14:0.4:0.4,15:17:0.5:0.5,18:18:0.6:0.6,19:20:0.3:0.3,21:22:0.6:0.6,23:23:1:1,24:24:0.8:0.8,25:25:1:1,26:29:0.8:0.8,30:30:1:1,31:31:0.8:0.8,32:32:0.7:0.7,33:33:0:0,34:34:0.8:0.8,35:35:1:1,36:36:0.8:0.8,37:37:1:1,38:38:0.8:0.8,39:39:1:1,40:42:1:1,43:43:0.8:0.8,44:44:1:1,45:45:0.3:0.3" potential=potential_1 --o
@@ -510,7 +510,7 @@
<div class="code">
- r.estimap landuse=corine_land_cover_2006 suitability_scores=corine_suitability.scores potential=potential_1 --o
+ r.estimap.recreation landuse=corine_land_cover_2006 suitability_scores=corine_suitability.scores potential=potential_1 --o
</div>
Deleted: grass-addons/grass7/raster/r.estimap.recreation/area_of_interest.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/bathing_water_quality.png
===================================================================
(Binary files differ)
Added: grass-addons/grass7/raster/r.estimap.recreation/corine_accounting_to_maes_land_classes.rules
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/corine_accounting_to_maes_land_classes.rules (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/corine_accounting_to_maes_land_classes.rules 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,40 @@
+1 = 1 Urban
+2 = 1 Urban
+3 = 1 Urban
+4 = 1 Urban
+5 = 1 Urban
+6 = 1 Urban
+7 = 1 Urban
+8 = 1 Urban
+9 = 1 Urban
+10 = 1 Urban
+11 = 1 Urban
+12 = 2 Cropland
+13 = 2 Cropland
+14 = 2 Cropland
+15 = 2 Cropland
+16 = 2 Cropland
+17 = 2 Cropland
+18 = 4 Grassland
+19 = 2 Cropland
+20 = 2 Cropland
+21 = 2 Cropland
+22 = 2 Cropland
+23 = 3 Woodland and forest
+24 = 3 Woodland and forest
+25 = 3 Woodland and forest
+26 = 4 Grassland
+27 = 5 Heathland and shrub
+28 = 5 Heathland and shrub
+29 = 3 Woodland and forest
+30 = 6 Sparsely vegetated land
+31 = 6 Sparsely vegetated land
+32 = 6 Sparsely vegetated land
+33 = 6 Sparsely vegetated land
+34 = 6 Sparsely vegetated land
+35 = 7 Wetland
+36 = 7 Wetland
+37 = 8 Marine
+38 = 8 Marine
+39 = 8 Marine
+
Deleted: grass-addons/grass7/raster/r.estimap.recreation/corine_land_cover_2006.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/corine_land_cover_2006_suitability.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/corine_land_cover_legend.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/demand.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/distance_to_infrastructure.png
===================================================================
(Binary files differ)
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/Makefile
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/Makefile (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/Makefile 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,25 @@
+MODULE_TOPDIR = ../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+
+MODULES = __init__ accessibility colors components constants distance grassy_utilities labels main mobility normalisation panos spectrum supply_and_use utilities
+
+PGM = r.estimap.recreation
+LIBDIR = estimap_recreation
+ETCDIR = $(ETC)/$(PGM)/$(LIBDIR)
+
+PYFILES := $(patsubst %,$(ETCDIR)/%.py,$(MODULES))
+PYCFILES := $(patsubst %,$(ETCDIR)/%.pyc,$(MODULES))
+
+default: $(PYFILES) $(PYCFILES)
+
+$(ETCDIR):
+ $(MKDIR) $@
+
+$(ETCDIR)/%: % | $(ETCDIR)
+ $(INSTALL_DATA) $< $@
+
+install:
+ $(MKDIR) $(INST_DIR)/etc/$(PGM)
+ cp -r $(ETCDIR) $(INST_DIR)/etc/$(PGM)/$(LIBDIR)
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/__init__.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/__init__.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/__init__.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+# __all__ = ['colors', 'constants', 'labels', 'utilities']
+
+version = "0.3"
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/accessibility.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/accessibility.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/accessibility.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+from grass.exceptions import CalledModuleError
+from grass.pygrass.modules.shortcuts import general as g
+from grass.pygrass.modules.shortcuts import raster as r
+from grass.pygrass.modules.shortcuts import vector as v
+
+
+def artificial_accessibility_expression(artificial_proximity, roads_proximity):
+ """
+ Build an r.mapcalc compatible expression to compute accessibility to
+ artificial surfaces based on the following accessibility classification
+ rules for artificial surfaces:
+
+|-------------------+-------+------------+-------------+--------------+---------|
+| Anthropic \ Roads | < 500 | 500 - 1000 | 1000 - 5000 | 5000 - 10000 | > 10000 |
+|-------------------+-------+------------+-------------+--------------+---------|
+| < 500 | 1 | 1 | 2 | 3 | 4 |
+|-------------------+-------+------------+-------------+--------------+---------|
+| 500 - 1000 | 1 | 1 | 2 | 3 | 4 |
+|-------------------+-------+------------+-------------+--------------+---------|
+| 1000 - 5000 | 2 | 2 | 2 | 4 | 5 |
+|-------------------+-------+------------+-------------+--------------+---------|
+| 5000 - 10000 | 3 | 3 | 4 | 5 | 5 |
+|-------------------+-------+------------+-------------+--------------+---------|
+| > 10000 | 3 | 4 | 4 | 5 | 5 |
+|-------------------+-------+------------+-------------+--------------+---------|
+
+ Parameters
+ ----------
+ artificial :
+ Proximity to artificial surfaces
+
+ roads :
+ Proximity to roads
+
+ Returns
+ -------
+ expression
+ Valid r.mapcalc expression
+
+
+ Examples
+ --------
+ ...
+ """
+ expression = (
+ "if( {artificial} <= 2 && {roads} <= 2, 1,"
+ " \ \n if( {artificial} == 1 && {roads} == 3, 2,"
+ " \ \n if( {artificial} == 2 && {roads} == 3, 2,"
+ " \ \n if( {artificial} == 3 && {roads} <= 3, 2,"
+ " \ \n if( {artificial} <= 2 && {roads} == 4, 3,"
+ " \ \n if( {artificial} == 4 && {roads} == 2, 3,"
+ " \ \n if( {artificial} >= 4 && {roads} == 1, 3,"
+ " \ \n if( {artificial} <= 2 && {roads} == 5, 4,"
+ " \ \n if( {artificial} == 3 && {roads} == 4, 4,"
+ " \ \n if( {artificial} >= 4 && {roads} == 3, 4,"
+ " \ \n if( {artificial} == 5 && {roads} == 2, 4,"
+ " \ \n if( {artificial} >= 3 && {roads} == 5, 5,"
+ " \ \n if( {artificial} >= 4 && {roads} == 4, 5)))))))))))))"
+ )
+
+ expression = expression.format(
+ artificial=artificial_proximity, roads=roads_proximity
+ )
+ return expression
+
+
+def compute_artificial_accessibility(
+ artificial_proximity, roads_proximity, output_name=None
+):
+ """Compute artificial proximity
+
+ Parameters
+ ----------
+ artificial_proximity :
+ Artificial surfaces...
+
+ roads_proximity :
+ Road infrastructure
+
+ output_name :
+ Name to pass to temporary_filename() to create a temporary map name
+
+ Returns
+ -------
+ output :
+ ...
+
+ Examples
+ --------
+ ...
+ """
+ artificial = grass.find_file(name=artificial_proximity, element="cell")
+ if not artificial["file"]:
+ grass.fatal("Raster map {name} not found".format(name=artificial_proximity))
+
+ roads = grass.find_file(name=roads_proximity, element="cell")
+ if not roads["file"]:
+ grass.fatal("Raster map {name} not found".format(name=roads_proximity))
+
+ accessibility_expression = artificial_accessibility_expression(
+ artificial_proximity, roads_proximity
+ )
+ # temporary maps will be removed!
+ if output_name:
+ tmp_output = temporary_filename(filename=output_name)
+ else:
+ basename = "artificial_accessibility"
+ tmp_output = temporary_filename(filename=basename)
+
+ accessibility_equation = EQUATION.format(
+ result=tmp_output, expression=accessibility_expression
+ )
+
+ msg = "Equation for proximity to artificial areas: \n"
+ msg += accessibility_equation
+ grass.verbose(msg)
+
+ grass.verbose(_("Computing accessibility to artificial surfaces"))
+ grass.mapcalc(accessibility_equation, overwrite=True)
+
+ return tmp_output
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/colors.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/colors.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/colors.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+MOBILITY_COLORS = "wave"
+LANDCOVER_FRACTIONS_COLOR = "wave"
+
+SCORE_COLORS = """
+# http://colorbrewer2.org/?type=diverging&scheme=RdYlGn&n=11
+0.0% 165:0:38
+10.0% 215:48:39
+20.0% 244:109:67
+30.0% 253:174:97
+40.0% 254:224:139
+50.0% 255:255:191
+60.0% 217:239:139
+70.0% 166:217:106
+80.0% 102:189:99
+90.0% 26:152:80
+100.0% 0:104:55
+""".strip()
+
+POTENTIAL_COLORS = """
+# Cubehelix color table generated using:
+# r.colors.cubehelix -dn ncolors=3 map=recreation_potential nrotations=0.33 gamma=1.5 hue=0.9 dark=0.3 output=recreation_potential.colors
+0.000% 55:29:66
+33.333% 55:29:66
+33.333% 157:85:132
+66.667% 157:85:132
+66.667% 235:184:193
+100.000% 235:184:193
+""".strip()
+
+OPPORTUNITY_COLORS = """
+# Cubehelix color table generated using:
+# r.colors.cubehelix -dn ncolors=3 map=recreation_potential nrotations=0.33 gamma=1.5 hue=0.9 dark=0.3 output=recreation_potential.colors
+0.000% 55:29:66
+33.333% 55:29:66
+33.333% 157:85:132
+66.667% 157:85:132
+66.667% 235:184:193
+100.000% 235:184:193
+""".strip()
+
+SPECTRUM_COLORS = """
+# Cubehelix color table generated using:
+# r.colors.cubehelix -dn ncolors=9 map=recreation_spectrum nrotations=0.33 gamma=1.5 hue=0.9 dark=0.3 output=recreation_spectrum.colors
+0.000% 55:29:66
+11.111% 55:29:66
+11.111% 79:40:85
+22.222% 79:40:85
+22.222% 104:52:102
+33.333% 104:52:102
+33.333% 131:67:118
+44.444% 131:67:118
+44.444% 157:85:132
+55.556% 157:85:132
+55.556% 180:104:145
+66.667% 180:104:145
+66.667% 202:128:159
+77.778% 202:128:159
+77.778% 221:156:175
+88.889% 221:156:175
+88.889% 235:184:193
+100.000% 235:184:193
+""".strip()
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/components.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/components.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/components.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+import grass.script as grass
+from grass.pygrass.modules.shortcuts import raster as r
+
+
+def append_map_to_component(raster, component_name, component_list):
+ """Appends raster map to given list of components
+
+ Parameters
+ ----------
+ raster :
+ Input raster map name
+
+ component_name :
+ Name of the component to add the raster map to
+
+ component_list :
+ List of raster maps to add the input 'raster' map
+
+ Returns
+ -------
+
+ Examples
+ --------
+ ...
+ """
+ component_list.append(raster)
+ msg = "Map {name} included in the '{component}' component"
+ msg = msg.format(name=raster, component=component_name)
+ grass.verbose(_(msg))
+
+
+def smooth_component(component, method, size):
+ """
+ component:
+
+ method:
+
+ size:
+ """
+ try:
+ if len(component) > 1:
+ for item in component:
+ smooth_map(item, method=method, size=size)
+ else:
+ smooth_map(component[0], method=method, size=size)
+
+ except IndexError:
+ grass.verbose(_("Index Error")) # FIXME: some useful message... ?
+
+
+def classify_recreation_component(component, rules, output_name):
+ """
+ Recode an input recreation component based on given rules
+
+ To Do:
+
+ - Potentially, test range of input recreation component, i.e. ranging in
+ [0,1]
+
+ Parameters
+ ----------
+ component :
+ Name of input raster map
+
+ rules :
+ Rules for r.recode
+
+ output_name :
+ Name for output raster map
+
+ Returns
+ -------
+ Does not return any value
+
+ Examples
+ --------
+ ...
+
+ """
+ r.recode(input=component, rules="-", stdin=rules, output=output_name)
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/constants.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/constants.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/constants.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+CITATION_RECREATION_POTENTIAL = "Zulian (2014)"
+SPACY_PLUS = " + "
+EQUATION = "{result} = {expression}" # basic equation for mapcalc
+
+THRESHHOLD_ZERO = 0
+THRESHHOLD_0001 = 0.0001
+
+CSV_EXTENSION = ".csv"
+COMMA = "comma"
+METHODS = "sum"
+EUCLIDEAN = "euclidean"
+# units='k'
+NEIGHBORHOOD_SIZE = 11 # this and below, required for neighborhood_function
+NEIGHBORHOOD_METHOD = "mode"
+
+WATER_PROXIMITY_CONSTANT = 1
+WATER_PROXIMITY_KAPPA = 30
+WATER_PROXIMITY_ALPHA = 0.008
+WATER_PROXIMITY_SCORE = 1
+BATHING_WATER_PROXIMITY_CONSTANT = 1
+BATHING_WATER_PROXIMITY_KAPPA = 5
+BATHING_WATER_PROXIMITY_ALPHA = 0.1101
+
+SUITABILITY_SCORES = """
+1:1:0:0
+2:2:0.1:0.1
+3:9:0:0
+10:10:1:1
+11:11:0.1:0.1
+12:13:0.3:0.3
+14:14:0.4:0.4
+15:17:0.5:0.5
+18:18:0.6:0.6
+19:20:0.3:0.3
+21:22:0.6:0.6
+23:23:1:1
+24:24:0.8:0.8
+25:25:1:1
+26:29:0.8:0.8
+30:30:1:1
+31:31:0.8:0.8
+32:32:0.7:0.7
+33:33:0:0
+34:34:0.8:0.8
+35:35:1:1
+36:36:0.8:0.8
+37:37:1:1
+38:38:0.8:0.8
+39:39:1:1
+40:42:1:1
+43:43:0.8:0.8
+44:44:1:1
+45:45:0.3:0.3
+""".strip()
+
+SUITABILITY_SCORES_LABELS = """
+1 thru 1 = 1 0
+2 thru 2 = 2 0.1
+3 thru 9 = 9 0
+10 thru 10 = 10 1
+11 thru 11 = 11 0.1
+12 thru 13 = 13 0.3
+14 thru 14 = 14 0.4
+15 thru 17 = 17 0.5
+18 thru 18 = 18 0.6
+19 thru 20 = 20 0.3
+21 thru 22 = 22 0.6
+23 thru 23 = 23 1
+24 thru 24 = 24 0.8
+25 thru 25 = 25 1
+26 thru 29 = 29 0.8
+30 thru 30 = 30 1
+31 thru 31 = 31 0.8
+32 thru 32 = 32 0.7
+33 thru 33 = 33 0
+34 thru 34 = 34 0.8
+35 thru 35 = 35 1
+36 thru 36 = 36 0.8
+37 thru 37 = 37 1
+38 thru 38 = 38 0.8
+39 thru 39 = 39 1
+40 thru 42 = 42 1
+43 thru 43 = 43 0.8
+44 thru 44 = 44 1
+45 thru 45 = 45 0.3
+""".strip()
+
+URBAN_ATLAS_CATEGORIES = """
+11100
+11200
+12100
+12200
+12300
+12400
+13100
+13200
+13300
+14100
+14200
+21100
+21200
+21300
+22100
+22200
+22300
+23100
+24100
+24200
+24300
+24400
+31100
+31200
+31300
+32100
+32200
+32300
+32400
+33100
+33200
+33300
+33400
+33500
+41100
+41200
+42100
+42200
+42300
+""".strip()
+
+URBAN_ATLAS_TO_MAES_NOMENCLATURE = """
+11100 = 1 Urban
+11210 = 1 Urban
+11220 = 1 Urban
+11230 = 1 Urban
+11240 = 1 Urban
+11300 = 1 Urban
+12100 = 1 Urban
+12210 = 1 Urban
+12220 = 1 Urban
+12230 = 1 Urban
+12300 = 1 Urban
+12400 = 1 Urban
+13100 = 1 Urban
+13300 = 1 Urban
+13400 = 1 Urban
+14100 = 1 Urban
+14200 = 1 Urban
+21000 = 2 Cropland
+22000 = 2 Cropland
+23000 = 2 Cropland
+25400 = 2 Cropland
+31000 = 3 Woodland and forest
+32000 = 3 Woodland and forest
+33000 = 3 Woodland and forest
+40000 = 4 Grassland
+50000 = 5 Heathland and shrub
+""".strip()
+
+# Recreation
+
+RECREATION_POTENTIAL_CATEGORIES = """
+0.0:0.2:1
+0.2:0.4:2
+0.4:*:3
+""".strip()
+# artificial_distance_categories=
+#'0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5'
+RECREATION_OPPORTUNITY_CATEGORIES = RECREATION_POTENTIAL_CATEGORIES
+HIGHEST_RECREATION_CATEGORY = 9
+
+# Mobility
+
+MOBILITY_CONSTANT = 1
+MOBILITY_COEFFICIENTS = {
+ 0: (0.02350, 0.00102),
+ 1: (0.02651, 0.00109),
+ 2: (0.05120, 0.00098),
+ 3: (0.10700, 0.00067),
+ 4: (0.06930, 0.00057),
+}
+MOBILITY_SCORE = 52
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/distance.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/distance.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/distance.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,324 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import grass.script as grass
+from grass.exceptions import CalledModuleError
+from grass.pygrass.modules.shortcuts import general as g
+from grass.pygrass.modules.shortcuts import raster as r
+from grass.pygrass.modules.shortcuts import vector as v
+
+
+def build_distance_function(
+ constant, kappa, alpha, variable, score=None, suitability=None
+):
+ """
+ Build a valid `r.mapcalc` expression based on the following "space-time"
+ function:
+
+ ( {constant} + {kappa} ) / ( {kappa} + exp({alpha} * {variable}) )
+
+ Parameters
+ ----------
+ constant :
+ 1
+
+ kappa :
+ A constant named 'K'
+
+ alpha :
+ A constant named 'a'
+
+ variable :
+ The main input variable: for 'attractiveness' it is 'distance', for
+ 'flow' it is 'population'
+
+ score :
+ If 'score' is given, it is used as a multiplication factor to the base
+ equation.
+
+ suitability :
+ [ NOTE: this argument is yet unused! It is meant to be used only after
+ successful integration of land suitability scores in
+ build_distance_function(). ]
+ If 'suitability' is given, it is used as a multiplication
+ factor to the base equation.
+
+ Returns
+ -------
+ function:
+ A valid `r.mapcalc` expression
+
+ Examples
+ --------
+ ..
+ """
+ numerator = "{constant} + {kappa}"
+ numerator = numerator.format(constant=constant, kappa=kappa)
+
+ denominator = "{kappa} + exp({alpha} * {variable})"
+ denominator = denominator.format(
+ kappa=kappa, alpha=alpha, variable=variable
+ ) # variable "formatted" by a caller function
+
+ function = " ( {numerator} ) / ( {denominator} )"
+ function = function.format(numerator=numerator, denominator=denominator)
+ grass.debug("Function without score: {f}".format(f=function))
+
+ if score:
+ function += " * {score}" # need for float()?
+ function = function.format(score=score)
+ grass.debug(_("Function after adding 'score': {f}".format(f=function)))
+
+ # -------------------------------------------------------------------------
+ # if suitability:
+ # function += " * {suitability}" # FIXME : Confirm Correctness
+ # function = function.format(suitability=suitability)
+ # msg = "Function after adding 'suitability': {f}".format(f=function)
+ # grass.debug(_(msg))
+ # -------------------------------------------------------------------------
+
+ return function
+
+
+def compute_attractiveness(
+ raster, metric, constant, kappa, alpha, mask=None, output_name=None
+):
+ """
+ Compute a raster map whose values follow an (euclidean) distance function
+ ( {constant} + {kappa} ) / ( {kappa} + exp({alpha} * {distance}) ), where:
+
+ Source: http://publications.jrc.ec.europa.eu/repository/bitstream/JRC87585/lb-na-26474-en-n.pd
+
+ Parameters
+ ----------
+ constant : 1
+
+ kappa :
+ A constant named 'K'
+
+ alpha :
+ A constant named 'a'
+
+ distance :
+ A distance map based on the input raster
+
+ score :
+ A score term to multiply the distance function
+
+ mask :
+ Optional raster MASK which is inverted to selectively exclude non-NULL
+ cells from distance related computations.
+
+ output_name :
+ Name to pass to temporary_filename() to create a temporary map name
+
+ Returns
+ -------
+ tmp_output :
+ A temporary proximity to features raster map.
+
+ Examples
+ --------
+ ...
+
+ """
+ distance_terms = [
+ str(raster),
+ str(metric),
+ "distance",
+ str(constant),
+ str(kappa),
+ str(alpha),
+ ]
+
+ if score:
+ grass.debug(_("Score for attractiveness equation: {s}".format(s=score)))
+ distance_terms += str(score)
+
+ # tmp_distance = temporary_filename('_'.join(distance_terms))
+ tmp_distance = temporary_filename(filename="_".join([raster, metric]))
+ r.grow_distance(
+ input=raster, distance=tmp_distance, metric=metric, quiet=True, overwrite=True
+ )
+
+ if mask:
+ msg = "Inverted masking to exclude non-NULL cells "
+ msg += "from distance related computations based on '{mask}'"
+ msg = msg.format(mask=mask)
+ grass.verbose(_(msg))
+ r.mask(raster=mask, flags="i", overwrite=True, quiet=True)
+
+ # FIXME: use a parameters dictionary, avoid conditionals
+ if score:
+ distance_function = build_distance_function(
+ constant=constant,
+ kappa=kappa,
+ alpha=alpha,
+ variable=tmp_distance,
+ score=score,
+ )
+
+ # FIXME: use a parameters dictionary, avoid conditionals
+ if not score:
+ distance_function = build_distance_function(
+ constant=constant, kappa=kappa, alpha=alpha, variable=tmp_distance
+ )
+
+ # temporary maps will be removed
+ if output_name:
+ tmp_distance_map = temporary_filename(filename=output_name)
+ else:
+ basename = "_".join([raster, "attractiveness"])
+ tmp_distance_map = temporary_filename(filename=basename)
+
+ distance_function = EQUATION.format(
+ result=tmp_distance_map, expression=distance_function
+ )
+ msg = "Distance function: {f}".format(f=distance_function)
+ grass.verbose(_(msg))
+ grass.mapcalc(distance_function, overwrite=True)
+
+ r.null(map=tmp_distance_map, null=0) # Set NULLs to 0
+
+ compress_status = grass.read_command("r.compress", flags="g", map=tmp_distance_map)
+ grass.verbose(_("Compress status: {s}".format(s=compress_status))) # REMOVEME
+
+ return tmp_distance_map
+
+
+def neighborhood_function(raster, method, size, distance_map):
+ """
+ Parameters
+ ----------
+ raster :
+ Name of input raster map for which to apply r.neighbors
+
+ method :
+ Method for r.neighbors
+
+ size :
+ Size for r.neighbors
+
+ distance :
+ A distance map
+
+ Returns
+ -------
+ filtered_output :
+ A neighborhood filtered raster map
+
+ Examples
+ --------
+ ...
+ """
+ r.null(map=raster, null=0) # Set NULLs to 0
+
+ neighborhood_output = distance_map + "_" + method
+ msg = "Neighborhood operator '{method}' and size '{size}' for map '{name}'"
+ msg = msg.format(method=method, size=size, name=neighborhood_output)
+ grass.verbose(_(msg))
+
+ r.neighbors(
+ input=raster,
+ output=neighborhood_output,
+ method=method,
+ size=size,
+ overwrite=True,
+ )
+
+ scoring_function = "{neighborhood} * {distance}"
+ scoring_function = scoring_function.format(
+ neighborhood=neighborhood_output, distance=distance_map
+ )
+
+ filtered_output = distance_map
+ filtered_output += "_" + method + "_" + str(size)
+
+ neighborhood_function = EQUATION.format(
+ result=filtered_output, expression=scoring_function
+ )
+ # ---------------------------------------------------------------
+ grass.debug(_("Expression: {e}".format(e=neighborhood_function)))
+ # ---------------------------------------------------------------
+ grass.mapcalc(neighborhood_function, overwrite=True)
+
+ # tmp_distance_map = filtered_output
+
+ # r.compress(distance_map, flags='g')
+
+ return filtered_output
+
+
+def compute_artificial_proximity(raster, distance_categories, output_name=None):
+ """
+ Compute proximity to artificial surfaces
+
+ 1. Distance to features
+ 2. Classify distances
+
+ Parameters
+ ----------
+ raster :
+ Name of input raster map
+
+ distance_categories :
+ Category rules to recode the input distance map
+
+ output_name :
+ Name to pass to temporary_filename() to create a temporary map name
+
+ Returns
+ -------
+ tmp_output :
+ Name of the temporary output map for internal, in-script, re-use
+
+ Examples
+ --------
+ ...
+ """
+ artificial_distances = temporary_filename(filename=raster)
+
+ grass.run_command(
+ "r.grow.distance",
+ input=raster,
+ distance=artificial_distances,
+ metric=EUCLIDEAN,
+ quiet=True,
+ overwrite=True,
+ )
+
+ # temporary maps will be removed
+ if output_name:
+ tmp_output = temporary_filename(filename=output_name)
+ grass.debug(_("Pre-defined output map name {name}".format(name=tmp_output)))
+
+ else:
+ tmp_output = temporary_filename(filename="artificial_proximity")
+ grass.debug(_("Hardcoded temporary map name {name}".format(name=tmp_output)))
+
+ msg = "Computing proximity to '{mapname}'"
+ msg = msg.format(mapname=raster)
+ grass.verbose(_(msg))
+ grass.run_command(
+ "r.recode",
+ input=artificial_distances,
+ output=tmp_output,
+ rules=distance_categories,
+ overwrite=True,
+ )
+
+ output = grass.find_file(name=tmp_output, element="cell")
+ if not output["file"]:
+ grass.fatal("Proximity map {name} not created!".format(name=raster))
+ # else:
+ # g.message(_("Output map {name}:".format(name=tmp_output)))
+
+ return tmp_output
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/grassy_utilities.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/grassy_utilities.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/grassy_utilities.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,532 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import atexit
+import os
+
+import grass.script as grass
+from grass.exceptions import CalledModuleError
+from grass.pygrass.modules.shortcuts import general as g
+from grass.pygrass.modules.shortcuts import raster as r
+from grass.pygrass.modules.shortcuts import vector as v
+
+from .colors import SCORE_COLORS
+from .constants import CITATION_RECREATION_POTENTIAL
+
+
+def run(cmd, **kwargs):
+ """Pass required arguments to grass commands (?)"""
+ grass.run_command(cmd, quiet=True, **kwargs)
+
+
+def remove_map(map_name):
+ """ Remove the provided map """
+ grass.verbose("Removing %s" % map_name)
+ g.remove(flags="f", type=("raster", "vector"), name=map_name, quiet=True)
+
+
+def remove_map_at_exit(map_name):
+ """ Remove the provided map when the program exits """
+ atexit.register(lambda: remove_map(map_name))
+
+
+def remove_files_at_exit(filename):
+ """ Remove the specified file when the program exits """
+ atexit.register(lambda: os.unlink(filename))
+
+
+def temporary_filename(filename=None):
+ """Returns a temporary filename using grass.script.tempfile() and
+ grass.script.basename()
+
+ Parameters
+ ----------
+ filename :
+ Name for a file
+
+ Returns
+ -------
+ temporary_filename :
+ A temporary file name
+
+ Examples
+ --------
+ >>> temporary_filename(potential)
+ tmp.SomeTemporaryString.potential
+ """
+ temporary_absolute_filename = grass.tempfile()
+ temporary_filename = "tmp." + grass.basename(temporary_absolute_filename)
+ if filename:
+ temporary_filename = temporary_filename + "." + str(filename)
+ return temporary_filename
+
+
+def remove_temporary_maps():
+ """Clean up temporary maps"""
+
+ # get list of temporary maps
+ # temporary_raster_maps = grass.list_strings(
+ # type="raster", pattern="tmp.{pid}*".format(pid=os.getpid())
+ # )
+
+ # # remove temporary maps
+ # if temporary_raster_maps:
+ g.message("Removing temporary maps")
+ g.remove(
+ flags="f",
+ type="raster",
+ pattern="tmp.{pid}*".format(pid=os.getpid()),
+ quiet=True,
+ )
+
+ # # remove MASK ? FIXME
+ # if grass.find_file(name='MASK', element='cell')['file']:
+ # r.mask(flags='r', verbose=True)
+
+
+def string_to_file(string, filename=None):
+ """Split series of strings separated by comma in lines and write as an
+ ASCII file
+
+ Parameters
+ ----------
+ string :
+ A string where commas will be replaced by a newline
+
+ name :
+ A string for temporary_filename() to create a temporary file name 'filename'
+
+ Returns
+ -------
+ filename :
+ Name of the ASCII file into where the transformed string is written
+
+ Examples
+ --------
+
+ """
+ string = string.split(",")
+ string = "\n".join(string)
+ # string = string.splitlines()
+ msg = "String split in lines: {s}".format(s=string)
+ grass.debug(_(msg))
+
+ # # Use a file-like object instead?
+ # import tempfile
+ # ascii_file = tempfile.TemporaryFile()
+
+ try:
+ ascii_file = open(filename, "w")
+ ascii_file.writelines(string)
+ # ascii_file.seek(0) # in case of a file-like object
+
+ # if DEBUG, then do:
+ # for line in ascii_file:
+ # grass.debug(_(line.rstrip()))
+
+ except IOError as error:
+ print("IOError :", error)
+ return
+
+ finally:
+ ascii_file.close()
+ return filename # how would that work with a file-like object?
+ # Will be removed right after `.close()` -- How to possibly re-use it
+ # outside the function?
+ # Wrap complete main() in a `try` statement?
+
+
+def get_univariate_statistics(raster):
+ """
+ Return and print basic univariate statistics of the input raster map
+
+ Parameters
+ ----------
+ raster :
+ Name of input raster map
+
+ Returns
+ -------
+ univariate :
+ Univariate statistics min, mean, max and variance of the input raster
+ map
+
+ Example
+ -------
+ ...
+ """
+ univariate = grass.parse_command("r.univar", flags="g", map=raster)
+ minimum = univariate["min"]
+ mean = univariate["mean"]
+ maximum = univariate["max"]
+ variance = univariate["variance"]
+ msg = "min {mn} | mean {avg} | max {mx} | variance {v}"
+ msg = msg.format(mn=minimum, avg=mean, mx=maximum, v=variance)
+ grass.verbose(_(msg))
+ return univariate
+
+
+def recode_map(raster, rules, colors, output):
+ """Scores a raster map based on a set of category recoding rules.
+
+ This is a wrapper around r.recode
+
+ Parameters
+ ----------
+ raster :
+ Name of input raster map
+
+ rules :
+ Rules for r.recode
+
+ colors :
+ Color rules for r.colors
+
+ output :
+ Name of output raster map
+
+ Returns
+ -------
+ Does not return any value
+
+ Examples
+ --------
+ ...
+ """
+ msg = "Setting NULL cells in {name} map to 0"
+ msg = msg.format(name=raster)
+ grass.debug(_(msg))
+
+ # ------------------------------------------
+ r.null(map=raster, null=0) # Set NULLs to 0
+ msg = "To Do: confirm if setting the '{raster}' map's NULL cells to 0 is right"
+ msg = msg.format(raster=raster)
+ grass.debug(_(msg))
+ # Is this right?
+ # ------------------------------------------
+
+ r.recode(input=raster, rules=rules, output=output)
+
+ r.colors(map=output, rules="-", stdin=SCORE_COLORS, quiet=True)
+
+ grass.verbose(_("Scored map {name}:".format(name=raster)))
+
+
+def float_to_integer(double):
+ """Converts an FCELL or DCELL raster map into a CELL raster map
+
+ Parameters
+ ----------
+ double :
+ An 'FCELL' or 'DCELL' type raster map
+
+ Returns
+ -------
+ This function does not return any value
+
+ Examples
+ --------
+ ..
+ """
+ expression = "int({double})"
+ expression = expression.format(double=double)
+ equation = EQUATION.format(result=double, expression=expression)
+ r.mapcalc(equation)
+
+
+def update_meta(raster, title, timestamp=None):
+ """
+ Update metadata of given raster map
+
+ Parameters
+ ----------
+ raster :
+ ...
+
+ title :
+ ...
+
+ Returns
+ -------
+ Does not return any value
+
+ Examples
+ --------
+ ...
+ """
+ history = "\n" + CITATION_RECREATION_POTENTIAL
+ description_string = "Recreation {raster} map"
+ description = description_string.format(raster=raster)
+
+ title = "{title}".format(title=title)
+ units = "Meters"
+
+ source1 = "Source 1"
+ source2 = "Source 2"
+
+ r.support(
+ map=raster,
+ title=title,
+ description=description,
+ units=units,
+ source1=source1,
+ source2=source2,
+ history=history,
+ )
+
+ if timestamp:
+ r.timestamp(map=raster, date=timestamp)
+
+
+def export_map(input_name, title, categories, colors, output_name, timestamp):
+ """
+ Export a raster map by renaming the (temporary) raster map name
+ 'input_name' to the requested output raster map name 'output_name'.
+ This function is (mainly) used to export either of the intermediate
+ recreation 'potential' or 'opportunity' maps.
+
+ Parameters
+ ----------
+ raster :
+ Input raster map name
+
+ title :
+ Title for the output raster map
+
+ categories :
+ Categories and labels for the output raster map
+
+ colors :
+ Colors for the output raster map
+
+ output_name :
+ Output raster map name
+
+ Returns
+ -------
+ output_name :
+ This function will return the requested 'output_name'
+
+ Examples
+ --------
+ ..
+ """
+ finding = grass.find_file(name=input_name, element="cell")
+ if not finding["file"]:
+ grass.fatal("Raster map {name} not found".format(name=input_name))
+
+ # inform
+ msg = "\nOutputting '{raster}' map\n"
+ msg = msg.format(raster=input_name)
+ grass.verbose(_(msg))
+
+ # get categories and labels
+ temporary_raster_categories_map = temporary_filename("categories_of_" + input_name)
+ raster_category_labels = string_to_file(
+ string=categories, filename=temporary_raster_categories_map
+ )
+
+ # add ascii file to removal list
+ remove_files_at_exit(raster_category_labels)
+
+ # apply categories and description
+ r.category(map=input_name, rules=raster_category_labels, separator=":")
+
+ # update meta and colors
+ update_meta(input_name, title, timestamp)
+ r.colors(map=input_name, rules="-", stdin=colors, quiet=True)
+ # rename to requested output name
+ g.rename(raster=(input_name, output_name), quiet=True)
+
+ return output_name
+
+
+def get_raster_statistics(map_one, map_two, separator, flags):
+ """
+ Parameters
+ ----------
+ map_one :
+ First map as input to `r.stats`
+
+ map_two :
+ Second map as input to `r.stats`
+
+ separator :
+ Character to use as separator in `r.stats`
+
+ flags :
+ Flags for `r.stats`
+
+ Returns
+ -------
+ dictionary :
+ A nested dictionary that holds categorical statistics for both maps
+ 'map_one' and 'map_two'.
+
+ - The 'outer_key' is the raster category _and_ label of 'map_one'.
+ - The 'inner_key' is the raster map category of 'map_two'.
+ - The 'inner_value' is the list of statistics for map two, as returned
+ for `r.stats`.
+
+ Example of a nested dictionary:
+
+ {(u'3',
+ u'Region 3'):
+ {u'1': [
+ u'355.747658',
+ u'6000000.000000',
+ u'6',
+ u'6.38%'],
+ u'3': [
+ u'216304.146140',
+ u'46000000.000000',
+ u'46',
+ u'48.94%'],
+ u'2': [
+ u'26627.415787',
+ u'46000000.000000',
+ u'46',
+ u'48.94%']}}
+ """
+
+ statistics = grass.read_command(
+ "r.stats",
+ input=(map_one, map_two),
+ output="-",
+ flags=flags,
+ separator=separator,
+ quiet=True,
+ )
+ statistics = statistics.split("\n")[:-1]
+
+ dictionary = dict()
+
+ # build a nested dictionary where:
+ for row in statistics:
+ row = row.split("|")
+ outer_key = (row[0], row[1])
+ inner_key = row[2]
+ inner_value = row[3:]
+ inner_dictionary = {inner_key: inner_value}
+ try:
+ dictionary[outer_key][inner_key] = inner_value
+ except KeyError:
+ dictionary[outer_key] = {inner_key: inner_value}
+
+ return dictionary
+
+
+def smooth_map(raster, method, size):
+ """
+ Parameters
+ ----------
+ raster :
+
+ method :
+
+ size :
+
+ Returns
+ -------
+
+ Examples
+ --------
+ """
+ r.neighbors(
+ input=raster,
+ output=raster,
+ method=method,
+ size=size,
+ overwrite=True,
+ quiet=True,
+ )
+
+
+# This function is not used. Review and Fix or Remove!
+def update_vector(vector, raster, methods, column_prefix):
+ """
+
+ Parameters
+ ----------
+ vector :
+ Vector map whose attribute table to update with results of the
+ v.rast.stats call
+
+ raster :
+ Source raster map for statistics
+
+ methods :
+ Descriptive statistics for the `v.rast.stats` call
+
+ column_prefix :
+ Prefix for the names of the columns created by the `v.rast.stats` call
+
+ Returns
+ -------
+ This helper function executes `v.rast.stats`. It does not return any
+ value.
+
+ Examples
+ --------
+ ..
+ """
+ run(
+ "v.rast.stats",
+ map=vector,
+ flags="c",
+ raster=raster,
+ method=methods,
+ column_prefix=column_prefix,
+ overwrite=True,
+ )
+ # grass.verbose(_("Updating vector map '{v}'".format(v=vector)))
+
+
+def raster_to_vector(raster, vector, type):
+ """Converts a raster to a vector map
+
+ Parameters
+ ----------
+
+ raster :
+ Name of the input raster map
+
+ vector :
+ Name for the output vector map
+
+ type :
+ Type for the output vector map
+
+ Returns
+ -------
+
+ Examples
+ --------
+ ..
+ """
+ r.to_vect(input=flow_in_category, output=flow_in_category, type="area", quiet=True)
+
+ # Value is the ecosystem type
+ v.db_renamecolumn(map=flow_in_category, column=("value", "ecosystem"))
+
+ # New column for flow values
+ addcolumn_string = flow_column_name + " double"
+ v.db_addcolumn(map=flow_in_category, columns=addcolumn_string)
+
+ # The raster category 'label' is the 'flow'
+ v.db_update(map=flow_in_category, column="flow", query_column="label")
+ v.db_dropcolumn(map=flow_in_category, columns="label")
+
+ # Update the aggregation raster categories
+ v.db_addcolumn(map=flow_in_category, columns="aggregation_id int")
+ v.db_update(map=flow_in_category, column="aggregation_id", value=category)
+
+ v.colors(map=flow_in_category, raster=flow_in_category, quiet=True)
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/labels.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/labels.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/labels.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+#
+## FIXME -- No hardcodings please.
+#
+
+POTENTIAL_CATEGORY_LABELS = """
+1:Low
+2:Moderate
+3:High
+""".strip()
+
+OPPORTUNITY_CATEGORY_LABELS = """
+1:Far
+2:Midrange
+3:Near
+""".strip()
+
+SPECTRUM_CATEGORY_LABELS = """
+1:Low provision (far)
+2:Low provision (midrange)
+3:Low provision (near)
+4:Moderate provision (far)
+5:Moderate provision (midrange)
+6:Moderate provision (near)
+7:High provision (far)
+8:High provision (midrange)
+9:High provision (near)
+""".strip()
+
+SPECTRUM_DISTANCE_CATEGORY_LABELS = """
+1:0 to 1 km
+2:1 to 2 km
+3:2 to 3 km
+4:3 to 4 km
+5:>4 km
+""".strip()
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/main.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/main.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/main.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,976 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+import atexit
+
+# constants
+
+from estimap_recreation.labels import POTENTIAL_CATEGORY_LABELS
+from estimap_recreation.labels import OPPORTUNITY_CATEGORY_LABELS
+from estimap_recreation.labels import SPECTRUM_CATEGORY_LABELS
+from estimap_recreation.labels import SPECTRUM_DISTANCE_CATEGORY_LABELS
+from estimap_recreation.colors import POTENTIAL_COLORS
+from estimap_recreation.colors import OPPORTUNITY_COLORS
+from estimap_recreation.colors import SPECTRUM_COLORS
+
+# utilities
+
+from estimap_recreation.grassy_utilities import *
+from estimap_recreation.utilities import *
+
+# algorithms
+
+from estimap_recreation.distance import *
+from estimap_recreation.normalisation import *
+from estimap_recreation.accessibility import *
+from estimap_recreation.spectrum import *
+from estimap_recreation.components import *
+from estimap_recreation.mobility import *
+from estimap_recreation.supply_and_use import *
+
+def main():
+ """
+ Main program
+ """
+ atexit.register(remove_temporary_maps)
+
+ """Flags and Options"""
+ options, flags = grass.parser()
+
+ # Flags that are not being used
+ info = flags["i"]
+ save_temporary_maps = flags["s"]
+
+ # Flags that are being used
+ average_filter = flags["f"]
+ landuse_extent = flags["e"]
+ print_only = flags["p"]
+
+ timestamp = options["timestamp"]
+
+ metric = options["metric"]
+ units = options["units"]
+ if len(units) > 1:
+ units = units.split(",")
+
+ """names for input, output, output suffix, options"""
+
+ mask = options["mask"]
+
+ """
+ following some hard-coded names -- review and remove!
+ """
+
+ land = options["land"]
+ land_component_map_name = temporary_filename(filename="land_component")
+
+ water = options["water"]
+ water_component_map_name = temporary_filename(filename="water_component")
+
+ natural = options["natural"]
+ natural_component_map_name = temporary_filename(filename="natural_component")
+
+ urban = options["urban"]
+ urban_component_map = "urban_component"
+
+ infrastructure = options["infrastructure"]
+ infrastructure_component_map_name = temporary_filename(filename="infrastructure_component")
+
+ recreation = options["recreation"]
+ recreation_component_map_name = temporary_filename(filename="recreation_component")
+
+ """Land components"""
+
+ landuse = options["landuse"]
+ if landuse:
+ # Check datatype: a land use map should be categorical, i.e. of type CELL
+ landuse_datatype = grass.raster.raster_info(landuse)["datatype"]
+ if landuse_datatype != "CELL":
+ msg = (
+ "The '{landuse}' input map "
+ "should be a categorical one "
+ "and of type 'CELL'. "
+ "Perhaps you meant to use the 'land' input option instead?"
+ )
+ grass.fatal(_(msg.format(landuse=landuse)))
+
+ suitability_map_name = temporary_filename(filename="suitability")
+ suitability_scores = options["suitability_scores"]
+
+ if landuse and suitability_scores and ":" not in suitability_scores:
+ msg = "Suitability scores from file: {scores}."
+ msg = msg.format(scores=suitability_scores)
+ grass.verbose(_(msg))
+
+ if landuse and not suitability_scores:
+ msg = "Using internal rules to score land use classes in '{map}'"
+ msg = msg.format(map=landuse)
+ grass.warning(_(msg))
+
+ temporary_suitability_map_name = temporary_filename(filename=suitability_map_name)
+ suitability_scores = string_to_file(
+ SUITABILITY_SCORES, filename=temporary_suitability_map_name
+ )
+ remove_files_at_exit(suitability_scores)
+
+ if landuse and suitability_scores and ":" in suitability_scores:
+ msg = "Using provided string of rules to score land use classes in {map}"
+ msg = msg.format(map=landuse)
+ grass.verbose(_(msg))
+ temporary_suitability_map_name = temporary_filename(filename=suitability_map_name)
+ suitability_scores = string_to_file(
+ suitability_scores, filename=temporary_suitability_map_name
+ )
+ remove_files_at_exit(suitability_scores)
+
+ # FIXME -----------------------------------------------------------------
+
+ # Use one landcover input if supply is requested
+ # Use one set of land cover reclassification rules
+
+ landcover = options["landcover"]
+
+ if not landcover:
+ landcover = landuse
+ msg = "Land cover map 'landcover' not given. "
+ msg += "Attempt to use the '{landuse}' map to derive areal statistics"
+ msg = msg.format(landuse=landuse)
+ grass.verbose(_(msg))
+
+ maes_ecosystem_types = "maes_ecosystem_types"
+ maes_ecosystem_types_scores = "maes_ecosystem_types_scores"
+ landcover_reclassification_rules = options["land_classes"]
+
+ # if 'land_classes' is a file
+ if (
+ landcover
+ and landcover_reclassification_rules
+ and ":" not in landcover_reclassification_rules
+ ):
+ msg = "Land cover reclassification rules from file: {rules}."
+ msg = msg.format(rules=landcover_reclassification_rules)
+ grass.verbose(_(msg))
+
+ # if 'land_classes' not given
+ if landcover and not landcover_reclassification_rules:
+
+ # if 'landcover' is not the MAES land cover,
+ # then use internal reclassification rules
+ # how to test:
+ # 1. landcover is not a "MAES" land cover
+ # 2. landcover is an Urban Atlas one?
+
+ msg = "Using internal rules to reclassify the '{map}' map"
+ msg = msg.format(map=landcover)
+ grass.verbose(_(msg))
+
+ temporary_maes_ecosystem_types = temporary_filename(filename=maes_ecosystem_types)
+ landcover_reclassification_rules = string_to_file(
+ URBAN_ATLAS_TO_MAES_NOMENCLATURE, filename=maes_ecosystem_types
+ )
+ remove_files_at_exit(landcover_reclassification_rules)
+
+ # if landcover is a "MAES" land cover, no need to reclassify!
+
+ if (
+ landuse
+ and landcover_reclassification_rules
+ and ":" in landcover_reclassification_rules
+ ):
+ msg = "Using provided string of rules to reclassify the '{map}' map"
+ msg = msg.format(map=landcover)
+ grass.verbose(_(msg))
+ temporary_maes_land_classes = temporary_filename(filename=maes_land_classes)
+ landcover_reclassification_rules = string_to_file(
+ landcover_reclassification_rules, filename=maes_land_classes
+ )
+ remove_files_at_exit(landcover_reclassification_rules)
+
+ # FIXME -----------------------------------------------------------------
+
+ """Water components"""
+
+ lakes = options["lakes"]
+ lakes_coefficients = options["lakes_coefficients"]
+ lakes_proximity_map_name = "lakes_proximity"
+ coastline = options["coastline"]
+ coast_proximity_map_name = "coast_proximity"
+ coast_geomorphology = options["coast_geomorphology"]
+ # coast_geomorphology_coefficients = options['geomorphology_coefficients']
+ coast_geomorphology_map_name = "coast_geomorphology"
+ bathing_water = options["bathing_water"]
+ bathing_water_coefficients = options["bathing_coefficients"]
+ bathing_water_proximity_map_name = "bathing_water_proximity"
+
+ """Natural components"""
+
+ protected = options["protected"]
+ protected_scores = options["protected_scores"]
+ protected_areas_map_name = "protected_areas"
+
+ """Artificial areas"""
+
+ artificial = options["artificial"]
+ artificial_proximity_map_name = "artificial_proximity"
+ artificial_distance_categories = options["artificial_distances"]
+
+ roads = options["roads"]
+ roads_proximity_map_name = "roads_proximity"
+ roads_distance_categories = options["roads_distances"]
+
+ artificial_accessibility_map_name = "artificial_accessibility"
+
+ """Devaluation"""
+
+ devaluation = options["devaluation"]
+
+ """Aggregational boundaries"""
+
+ base = options["base"]
+ base_vector = options["base_vector"]
+ aggregation = options["aggregation"]
+
+ """Population"""
+
+ population = options["population"]
+ if population:
+ population_ns_resolution = grass.raster_info(population)["nsres"]
+ population_ew_resolution = grass.raster_info(population)["ewres"]
+
+ """Outputs"""
+
+ potential_title = "Recreation potential"
+ recreation_potential = options["potential"] # intermediate / output
+ recreation_potential_map_name = temporary_filename(filename="recreation_potential")
+
+ opportunity_title = "Recreation opportunity"
+ recreation_opportunity = options["opportunity"]
+ recreation_opportunity_map_name = "recreation_opportunity"
+
+ spectrum_title = "Recreation spectrum"
+ # if options['spectrum']:
+ recreation_spectrum = options["spectrum"] # output
+ # else:
+ # recreation_spectrum = 'recreation_spectrum'
+ # recreation_spectrum_component_map_name =
+ # temporary_filename(filename='recreation_spectrum_component_map')
+
+ spectrum_distance_categories = options["spectrum_distances"]
+ if ":" in spectrum_distance_categories:
+ temporary_recreation_spectrum = temporary_filename(filename=recreation_spectrum)
+ spectrum_distance_categories = string_to_file(
+ spectrum_distance_categories,
+ filename=temporary_recreation_spectrum
+ )
+ remove_files_at_exit(spectrum_distance_categories)
+
+ highest_spectrum = "highest_recreation_spectrum"
+ crossmap = "crossmap" # REMOVEME
+
+ demand = options["demand"]
+ unmet_demand = options["unmet"]
+
+ flow = options["flow"]
+ flow_map_name = "flow"
+
+ supply = options["supply"] # use as CSV filename prefix
+ use = options["use"] # use as CSV filename prefix
+
+ """ First, care about the computational region"""
+
+ if mask:
+ msg = "Masking NULL cells based on '{mask}'".format(mask=mask)
+ grass.verbose(_(msg))
+ r.mask(raster=mask, overwrite=True, quiet=True)
+
+ if landuse_extent:
+ grass.use_temp_region() # to safely modify the region
+ g.region(flags="p", raster=landuse) # Set region to 'mask'
+ msg = "|! Computational resolution matched to {raster}"
+ msg = msg.format(raster=landuse)
+ g.message(_(msg))
+
+ """Land Component
+ or Suitability of Land to Support Recreation Activities (SLSRA)"""
+
+ land_component = [] # a list, use .extend() wherever required
+
+ if land:
+
+ land_component = land.split(",")
+
+ if landuse and suitability_scores:
+
+ msg = "Deriving land suitability from '{landuse}' "
+ msg += "based on rules described in file '{rules}'"
+ grass.verbose(msg.format(landuse=landuse, rules=suitability_scores))
+
+ # suitability is the 'suitability_map_name'
+ recode_map(
+ raster=landuse,
+ rules=suitability_scores,
+ colors=SCORE_COLORS,
+ output=suitability_map_name,
+ )
+
+ append_map_to_component(
+ raster=suitability_map_name,
+ component_name="land",
+ component_list=land_component,
+ )
+
+ """Water Component"""
+
+ water_component = []
+ water_components = []
+
+ if water:
+
+ water_component = water.split(",")
+ msg = "Water component includes currently: {component}"
+ msg = msg.format(component=water_component)
+ grass.debug(_(msg))
+ # grass.verbose(_(msg))
+
+ if lakes:
+
+ if lakes_coefficients:
+ metric, constant, kappa, alpha, score = get_coefficients(lakes_coefficients)
+
+ lakes_proximity = compute_attractiveness(
+ raster=lakes,
+ metric=EUCLIDEAN,
+ constant=constant,
+ kappa=kappa,
+ alpha=alpha,
+ score=score,
+ mask=lakes,
+ )
+
+ append_map_to_component(
+ raster=lakes_proximity,
+ component_name="water",
+ component_list=water_components,
+ )
+
+ if coastline:
+
+ coast_proximity = compute_attractiveness(
+ raster=coastline,
+ metric=EUCLIDEAN,
+ constant=WATER_PROXIMITY_CONSTANT,
+ alpha=WATER_PROXIMITY_ALPHA,
+ kappa=WATER_PROXIMITY_KAPPA,
+ score=WATER_PROXIMITY_SCORE,
+ )
+
+ append_map_to_component(
+ raster=coast_proximity,
+ component_name="water",
+ component_list=water_components,
+ )
+
+ if coast_geomorphology:
+
+ try:
+
+ if not coastline:
+ msg = "The coastline map is required in order to "
+ msg += "compute attractiveness based on the "
+ msg += "coast geomorphology raster map"
+ msg = msg.format(c=water_component)
+ grass.fatal(_(msg))
+
+ except NameError:
+ grass.fatal(_("No coast proximity"))
+
+ coast_attractiveness = neighborhood_function(
+ raster=coast_geomorphology,
+ method=NEIGHBORHOOD_METHOD,
+ size=NEIGHBORHOOD_SIZE,
+ distance_map=coast_proximity,
+ )
+
+ append_map_to_component(
+ raster=coast_attractiveness,
+ component_name="water",
+ component_list=water_components,
+ )
+
+ if bathing_water:
+
+ if bathing_water_coefficients:
+ metric, constant, kappa, alpha = get_coefficients(
+ bathing_water_coefficients
+ )
+
+ bathing_water_proximity = compute_attractiveness(
+ raster=bathing_water,
+ metric=EUCLIDEAN,
+ constant=constant,
+ kappa=kappa,
+ alpha=alpha,
+ )
+
+ append_map_to_component(
+ raster=bathing_water_proximity,
+ component_name="water",
+ component_list=water_components,
+ )
+
+ # merge water component related maps in one list
+ water_component += water_components
+
+ """Natural Component"""
+
+ natural_component = []
+ natural_components = []
+
+ if natural:
+
+ natural_component = natural.split(",")
+
+ if protected:
+ msg = "Scoring protected areas '{protected}' based on '{rules}'"
+ grass.verbose(_(msg.format(protected=protected, rules=protected_scores)))
+
+ protected_areas = protected_areas_map_name
+
+ recode_map(
+ raster=protected,
+ rules=protected_scores,
+ colors=SCORE_COLORS,
+ output=protected_areas,
+ )
+
+ append_map_to_component(
+ raster=protected_areas,
+ component_name="natural",
+ component_list=natural_components,
+ )
+
+ # merge natural resources component related maps in one list
+ natural_component += natural_components
+
+ """ Normalize land, water, natural inputs
+ and add them to the recreation potential component"""
+
+ recreation_potential_component = []
+
+ if land_component:
+
+ for dummy_index in land_component:
+
+ # remove 'land_map' from 'land_component'
+ # process and add it back afterwards
+ land_map = land_component.pop(0)
+
+ """
+ This section sets NULL cells to 0.
+ Because `r.null` operates on the complete input raster map,
+ manually subsetting the input map is required.
+ """
+ suitability_map = temporary_filename(filename=land_map)
+ subset_land = EQUATION.format(result=suitability_map, expression=land_map)
+ r.mapcalc(subset_land)
+
+ grass.debug(_("Setting NULL cells to 0")) # REMOVEME ?
+ r.null(map=suitability_map, null=0) # Set NULLs to 0
+
+ msg = "\nAdding land suitability map '{suitability}' "
+ msg += "to 'Recreation Potential' component\n"
+ msg = msg.format(suitability=suitability_map)
+ grass.verbose(_(msg))
+
+ # add 'suitability_map' to 'land_component'
+ land_component.append(suitability_map)
+
+ if len(land_component) > 1:
+ grass.verbose(_("\nNormalize 'Land' component\n"))
+ zerofy_and_normalise_component(
+ land_component, THRESHHOLD_ZERO, land_component_map_name
+ )
+ recreation_potential_component.extend(land_component)
+ else:
+ recreation_potential_component.extend(land_component)
+
+ if land_component and average_filter:
+ smooth_component(land_component, method="average", size=7)
+
+ remove_map_at_exit(land_component)
+
+ if len(water_component) > 1:
+ grass.verbose(_("\nNormalize 'Water' component\n"))
+ zerofy_and_normalise_component(
+ water_component, THRESHHOLD_ZERO, water_component_map_name
+ )
+ recreation_potential_component.append(water_component_map_name)
+ else:
+ recreation_potential_component.extend(water_component)
+
+ remove_map_at_exit(water_component_map_name)
+
+ if len(natural_component) > 1:
+ grass.verbose(_("\nNormalize 'Natural' component\n"))
+ zerofy_and_normalise_component(
+ components=natural_component,
+ threshhold=THRESHHOLD_ZERO,
+ output_name=natural_component_map_name,
+ )
+ recreation_potential_component.append(natural_component_map_name)
+ else:
+ recreation_potential_component.extend(natural_component)
+
+ if natural_component and average_filter:
+ smooth_component(natural_component, method="average", size=7)
+
+ remove_map_at_exit(natural_component_map_name)
+
+ """ Recreation Potential [Output] """
+
+ tmp_recreation_potential = temporary_filename(filename=recreation_potential_map_name)
+
+ msg = "Computing intermediate 'Recreation Potential' map: '{potential}'"
+ grass.verbose(_(msg.format(potential=tmp_recreation_potential)))
+ grass.debug(_("Maps: {maps}".format(maps=recreation_potential_component)))
+
+ zerofy_and_normalise_component(
+ components=recreation_potential_component,
+ threshhold=THRESHHOLD_ZERO,
+ output_name=tmp_recreation_potential,
+ )
+
+ # recode recreation_potential
+ tmp_recreation_potential_categories = temporary_filename(filename=recreation_potential)
+
+ msg = "\nClassifying '{potential}' map"
+ msg = msg.format(potential=tmp_recreation_potential)
+ grass.verbose(_(msg))
+
+ classify_recreation_component(
+ component=tmp_recreation_potential,
+ rules=RECREATION_POTENTIAL_CATEGORIES,
+ output_name=tmp_recreation_potential_categories,
+ )
+
+ if recreation_potential:
+
+ # export 'recreation_potential' map and
+ # use 'output_name' for the temporary 'potential' map for spectrum
+ tmp_recreation_potential_categories = export_map(
+ input_name=tmp_recreation_potential_categories,
+ title=potential_title,
+ categories=POTENTIAL_CATEGORY_LABELS,
+ colors=POTENTIAL_COLORS,
+ output_name=recreation_potential,
+ timestamp=timestamp,
+ )
+
+ # Infrastructure to access recreational facilities, amenities, services
+ # Required for recreation opportunity and successively recreation spectrum
+
+ if infrastructure and not any(
+ [recreation_opportunity, recreation_spectrum, demand, flow, supply]
+ ):
+ msg = (
+ "Infrastructure is not required "
+ "to derive the 'potential' recreation map."
+ )
+ grass.warning(_(msg))
+
+ if any([recreation_opportunity, recreation_spectrum, demand, flow, supply]):
+
+ infrastructure_component = []
+ infrastructure_components = []
+
+ if infrastructure:
+ infrastructure_component.append(infrastructure)
+
+ """Artificial surfaces (includung Roads)"""
+
+ if artificial and roads:
+
+ msg = "Roads distance categories: {c}"
+ msg = msg.format(c=roads_distance_categories)
+ grass.debug(_(msg))
+ roads_proximity = compute_artificial_proximity(
+ raster=roads,
+ distance_categories=roads_distance_categories,
+ output_name=roads_proximity_map_name,
+ )
+
+ msg = "Artificial distance categories: {c}"
+ msg = msg.format(c=artificial_distance_categories)
+ grass.debug(_(msg))
+ artificial_proximity = compute_artificial_proximity(
+ raster=artificial,
+ distance_categories=artificial_distance_categories,
+ output_name=artificial_proximity_map_name,
+ )
+
+ artificial_accessibility = compute_artificial_accessibility(
+ artificial_proximity,
+ roads_proximity,
+ output_name=artificial_accessibility_map_name,
+ )
+
+ infrastructure_components.append(artificial_accessibility)
+
+ # merge infrastructure component related maps in one list
+ infrastructure_component += infrastructure_components
+
+ # # Recreational facilities, amenities, services
+
+ # recreation_component = []
+ # recreation_components = []
+
+ # if recreation:
+ # recreation_component.append(recreation)
+
+ # # merge recreation component related maps in one list
+ # recreation_component += recreation_components
+
+ """ Recreation Spectrum """
+
+ if any([recreation_spectrum, demand, flow, supply]):
+
+ recreation_opportunity_component = []
+
+ # input
+ zerofy_and_normalise_component(
+ components=infrastructure_component,
+ threshhold=THRESHHOLD_ZERO,
+ output_name=infrastructure_component_map_name,
+ )
+
+ recreation_opportunity_component.append(infrastructure_component_map_name)
+
+ # # input
+ # zerofy_and_normalise_component(recreation_component,
+ # THRESHHOLD_0001, recreation_component_map_name)
+ # recreation_opportunity_component.append(recreation_component_map_name)
+ # remove_map_at_exit(recreation_component_map_name)
+
+ # intermediate
+
+ # REVIEW --------------------------------------------------------------
+ tmp_recreation_opportunity = temporary_filename(filename=recreation_opportunity_map_name)
+ msg = "Computing intermediate opportunity map '{opportunity}'"
+ grass.debug(_(msg.format(opportunity=tmp_recreation_opportunity)))
+
+ grass.verbose(_("\nNormalize 'Recreation Opportunity' component\n"))
+ grass.debug(_("Maps: {maps}".format(maps=recreation_opportunity_component)))
+
+ zerofy_and_normalise_component(
+ components=recreation_opportunity_component,
+ threshhold=THRESHHOLD_0001,
+ output_name=tmp_recreation_opportunity,
+ )
+
+ # Why threshhold 0.0003? How and why it differs from 0.0001?
+ # -------------------------------------------------------------- REVIEW
+
+ msg = "Classifying '{opportunity}' map"
+ grass.verbose(msg.format(opportunity=tmp_recreation_opportunity))
+
+ # recode opportunity_component
+ tmp_recreation_opportunity_categories = temporary_filename(filename=recreation_opportunity)
+ classify_recreation_component(
+ component=tmp_recreation_opportunity,
+ rules=RECREATION_OPPORTUNITY_CATEGORIES,
+ output_name=tmp_recreation_opportunity_categories,
+ )
+
+ """ Recreation Opportunity [Output]"""
+
+ if recreation_opportunity:
+
+ # export 'recreation_opportunity' map and
+ # use 'output_name' for the temporary 'potential' map for spectrum
+ tmp_recreation_opportunity_categories = export_map(
+ input_name=tmp_recreation_opportunity_categories,
+ title=opportunity_title,
+ categories=OPPORTUNITY_CATEGORY_LABELS,
+ colors=OPPORTUNITY_COLORS,
+ output_name=recreation_opportunity,
+ timestamp=timestamp,
+ )
+
+ # Recreation Spectrum: Potential + Opportunity [Output]
+
+ if not recreation_spectrum and any([demand, flow, supply]):
+ recreation_spectrum = temporary_filename(filename="recreation_spectrum")
+ remove_map_at_exit(recreation_spectrum)
+
+ recreation_spectrum = compute_recreation_spectrum(
+ potential=tmp_recreation_potential_categories,
+ opportunity=tmp_recreation_opportunity_categories,
+ spectrum=recreation_spectrum,
+ )
+
+ msg = "Writing '{spectrum}' map"
+ msg = msg.format(spectrum=recreation_spectrum)
+ grass.verbose(_(msg))
+ get_univariate_statistics(recreation_spectrum)
+
+ # get category labels
+ temporary_spectrum_categories = temporary_filename(filename="categories_of_" + recreation_spectrum)
+ spectrum_category_labels = string_to_file(
+ SPECTRUM_CATEGORY_LABELS, filename=temporary_spectrum_categories
+ )
+
+ # add to list for removal
+ remove_files_at_exit(spectrum_category_labels)
+
+ # update category labels, meta and colors
+ spectrum_categories = "categories_of_"
+
+ r.category(
+ map=recreation_spectrum, rules=spectrum_category_labels, separator=":"
+ )
+
+ update_meta(recreation_spectrum, spectrum_title)
+
+ r.colors(map=recreation_spectrum, rules="-", stdin=SPECTRUM_COLORS, quiet=True)
+
+ if base_vector:
+ update_vector(
+ vector=base_vector,
+ raster=recreation_spectrum,
+ methods=METHODS,
+ column_prefix="spectrum",
+ )
+
+ """Valuation Tables"""
+
+ if any([demand, flow, supply, aggregation]):
+
+ """Highest Recreation Spectrum == 9"""
+
+ expression = (
+ "if({spectrum} == {highest_recreation_category}, {spectrum}, null())"
+ )
+ highest_spectrum_expression = expression.format(
+ spectrum=recreation_spectrum,
+ highest_recreation_category=HIGHEST_RECREATION_CATEGORY,
+ )
+ highest_spectrum_equation = EQUATION.format(
+ result=highest_spectrum, expression=highest_spectrum_expression
+ )
+ r.mapcalc(highest_spectrum_equation, overwrite=True)
+
+ """Distance map"""
+
+ distance_to_highest_spectrum = temporary_filename(filename=highest_spectrum)
+ r.grow_distance(
+ input=highest_spectrum,
+ distance=distance_to_highest_spectrum,
+ metric=metric,
+ quiet=True,
+ overwrite=True,
+ )
+
+ """Distance categories"""
+
+ distance_categories_to_highest_spectrum = "categories_of_"
+ distance_categories_to_highest_spectrum += distance_to_highest_spectrum
+ remove_map_at_exit(distance_categories_to_highest_spectrum) # FIXME
+
+ recode_map(
+ raster=distance_to_highest_spectrum,
+ rules=spectrum_distance_categories,
+ colors=SCORE_COLORS,
+ output=distance_categories_to_highest_spectrum,
+ )
+
+ temporary_distance_categories_to_highest_spectrum = temporary_filename(filename=distance_categories_to_highest_spectrum)
+ spectrum_distance_category_labels = string_to_file(
+ SPECTRUM_DISTANCE_CATEGORY_LABELS,
+ filename=temporary_distance_categories_to_highest_spectrum,
+ )
+ remove_files_at_exit(spectrum_distance_category_labels)
+
+ r.category(
+ map=distance_categories_to_highest_spectrum,
+ rules=spectrum_distance_category_labels,
+ separator=":",
+ )
+
+ """Combine Base map and Distance Categories"""
+
+ tmp_crossmap = temporary_filename(filename=crossmap)
+ r.cross(
+ input=(distance_categories_to_highest_spectrum, base),
+ flags="z",
+ output=tmp_crossmap,
+ quiet=True,
+ )
+
+ grass.use_temp_region() # to safely modify the region
+ g.region(
+ nsres=population_ns_resolution, ewres=population_ew_resolution, flags="a"
+ ) # Resolution should match 'population' FIXME
+ msg = "|! Computational extent & resolution matched to {raster}"
+ msg = msg.format(raster=landuse)
+ grass.verbose(_(msg))
+
+ population_statistics = get_univariate_statistics(population)
+ population_total = population_statistics['sum']
+ msg = "|i Population statistics: {s}".format(s=population_total)
+ grass.verbose(_(msg))
+
+ """Demand Distribution"""
+
+ if any([flow, supply, aggregation]) and not demand:
+ demand = temporary_filename(filename="demand")
+
+ r.stats_zonal(
+ base=tmp_crossmap,
+ flags="r",
+ cover=population,
+ method="sum",
+ output=demand,
+ overwrite=True,
+ quiet=True,
+ )
+
+ # copy 'reclassed' as 'normal' map (r.mapcalc)
+ # so as to enable removal of it and its 'base' map
+ demand_copy = demand + "_copy"
+ copy_expression = "{input_raster}"
+ copy_expression = copy_expression.format(input_raster=demand)
+ copy_equation = EQUATION.format(result=demand_copy, expression=copy_expression)
+ r.mapcalc(copy_equation, overwrite=True)
+
+ # remove the reclassed map 'demand'
+ g.remove(flags="f", type="raster", name=demand, quiet=True)
+
+ # rename back to 'demand'
+ g.rename(raster=(demand_copy, demand), quiet=True)
+
+ if demand and base_vector:
+ update_vector(
+ vector=base_vector,
+ raster=demand,
+ methods=METHODS,
+ column_prefix="demand",
+ )
+
+ """Unmet Demand"""
+
+ if unmet_demand:
+
+ # compute unmet demand
+
+ unmet_demand_expression = compute_unmet_demand(
+ distance=distance_categories_to_highest_spectrum,
+ constant=MOBILITY_CONSTANT,
+ coefficients=MOBILITY_COEFFICIENTS[4],
+ population=demand,
+ score=MOBILITY_SCORE,
+ )
+ # suitability=suitability) # Not used.
+ # Maybe it can, though, after successfully testing its
+ # integration to build_distance_function().
+
+ grass.debug(
+ _("Unmet demand function: {f}".format(f=unmet_demand_expression))
+ )
+
+ unmet_demand_equation = EQUATION.format(
+ result=unmet_demand, expression=unmet_demand_expression
+ )
+ r.mapcalc(unmet_demand_equation, overwrite=True)
+
+ if base_vector:
+ update_vector(
+ vector=base_vector,
+ raster=unmet_demand,
+ methods=METHODS,
+ column_prefix="unmet",
+ )
+
+ """Mobility function"""
+
+ if not flow and any([supply, aggregation]):
+
+ flow = flow_map_name
+ remove_map_at_exit(flow)
+
+ if flow or any([supply, aggregation]):
+
+ mobility_expression = mobility_function(
+ distance=distance_categories_to_highest_spectrum,
+ constant=MOBILITY_CONSTANT,
+ coefficients=MOBILITY_COEFFICIENTS,
+ population=demand,
+ score=MOBILITY_SCORE,
+ )
+ # suitability=suitability) # Not used.
+ # Maybe it can, though, after successfully testing its
+ # integration to build_distance_function().
+
+ msg = "Mobility function: {f}"
+ grass.debug(_(msg.format(f=mobility_expression)))
+
+ """Flow map"""
+
+ mobility_equation = EQUATION.format(
+ result=flow, expression=mobility_expression
+ )
+ r.mapcalc(mobility_equation, overwrite=True)
+
+ if base_vector:
+ update_vector(
+ vector=base_vector,
+ raster=flow_map_name,
+ methods=METHODS,
+ column_prefix="flow",
+ )
+
+ """Supply Table"""
+
+ if aggregation:
+
+ supply_parameters = {}
+
+ if supply:
+ supply_parameters.update({"supply_filename": supply})
+
+ if use:
+ supply_parameters.update({"use_filename": use})
+
+ if base_vector:
+ supply_parameters.update({"vector": base_vector})
+
+ compute_supply(
+ base=landcover,
+ recreation_spectrum=recreation_spectrum,
+ highest_spectrum=highest_spectrum,
+ base_reclassification_rules=landcover_reclassification_rules,
+ reclassified_base=maes_ecosystem_types,
+ reclassified_base_title="MAES ecosystem types",
+ flow=flow,
+ flow_map_name=flow_map_name,
+ aggregation=aggregation,
+ ns_resolution=population_ns_resolution,
+ ew_resolution=population_ew_resolution,
+ print_only=print_only,
+ **supply_parameters
+ )
+
+ # restore region
+ if landuse_extent:
+ grass.del_temp_region() # restoring previous region settings
+ grass.verbose("Original Region restored")
+
+ # print citation
+ citation = "Citation: " + CITATION_RECREATION_POTENTIAL
+ grass.verbose(citation)
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/mobility.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/mobility.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/mobility.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import grass.script as grass
+from .distance import build_distance_function
+
+
+def mobility_function(
+ distance, constant, coefficients, population, score, suitability=None
+):
+ """
+ The following 'mobility' function, is identical to the one used in
+ `compute_attractiveness()`, excluding, however, the 'score' term:
+
+ if(L10<>0,(1+$D$3)/($D$3+exp(-$E$3*L10))*52,0)
+
+ Source: Excel file provided by the MAES Team, Land Resources, D3
+
+ ------------------------------------------------------------------
+ if L<>0; then
+ # (1 + D) / (D + exp(-E * L)) * 52)
+
+ # D: Kappa
+ # -E: Alpha -- Note the '-' sign in front of E
+ # L: Population (within boundary, within distance buffer)
+ ------------------------------------------------------------------
+
+ Parameters
+ ----------
+
+ distance :
+ Map of distance categories
+
+ constant :
+ Constant for the mobility function
+
+ coefficients :
+ A dictionary with a set for coefficients for each distance category, as
+ (the example) presented in the following table:
+
+ |----------+---------+---------|
+ | Distance | Kappa | Alpha |
+ |----------+---------+---------|
+ | 0 to 1 | 0.02350 | 0.00102 |
+ |----------+---------+---------|
+ | 1 to 2 | 0.02651 | 0.00109 |
+ |----------+---------+---------|
+ | 2 to 3 | 0.05120 | 0.00098 |
+ |----------+---------+---------|
+ | 3 to 4 | 0.10700 | 0.00067 |
+ |----------+---------+---------|
+ | >4 | 0.06930 | 0.00057 |
+ |----------+---------+---------|
+
+ Note, the last distance category is not considered in deriving the
+ final "map of visits".
+
+ Note, the Alpha coefficient, is signed with a '-' in the mobility
+ function.
+
+ population :
+ A map with the distribution of the demand per distance category and
+ predefined geometric boundaries (see `r.stats.zonal` deriving the
+ 'demand' map ).
+
+ score :
+ A score value for the mobility function
+
+ suitability :
+ [ NOTE: this argument is yet unused! It is meant to be used only after
+ successful integration of land suitability scores in
+ build_distance_function(). ]
+ If 'suitability' is given, it is used as a multiplication
+ factor to the base equation.
+
+
+ Returns
+ -------
+
+ mobility_expression :
+ A valid mapcalc expression to compute the flow based on the
+ predefined function `build_distance_function`.
+
+ Examples
+ --------
+ ...
+ """
+ expressions = {} # create a dictionary of expressions
+
+ for distance_category, parameters in coefficients.items():
+ kappa, alpha = parameters
+
+ # Note, alpha gets a minus, that is: -alpha
+ expressions[distance_category] = build_distance_function(
+ constant=constant,
+ kappa=kappa,
+ alpha=-alpha,
+ variable=population,
+ score=score,
+ )
+ # suitability=suitability) # Not used.
+ # Maybe it can, though, after successfully testing its
+ # integration to build_distance_function().
+
+ grass.debug(_("For distance '{d}':".format(d=distance)))
+ grass.debug(_(expressions[distance_category]))
+
+ msg = "Expressions per distance category: {e}".format(e=expressions)
+ grass.debug(_(msg))
+
+ # build expressions -- explicit: use the'score' kwarg!
+ expression = (
+ "eval( mobility_0 = {expression_0},"
+ " \ \n mobility_1 = {expression_1},"
+ " \ \n mobility_2 = {expression_2},"
+ " \ \n mobility_3 = {expression_3},"
+ " \ \n distance_0 = {distance} == {distance_category_0},"
+ " \ \n distance_1 = {distance} == {distance_category_1},"
+ " \ \n distance_2 = {distance} == {distance_category_2},"
+ " \ \n distance_3 = {distance} == {distance_category_3},"
+ " \ \n if( distance_0, mobility_0,"
+ " \ \n if( distance_1, mobility_1,"
+ " \ \n if( distance_2, mobility_2,"
+ " \ \n if( distance_3, mobility_3,"
+ " \ \n null() )))))"
+ )
+ grass.debug(_("Mapcalc expression: {e}".format(e=expression)))
+
+ # replace keywords appropriately
+ # 'distance' is a map
+ # 'distance_category' is a value
+ # hence: 'distance' != 'distance_category'
+ mobility_expression = expression.format(
+ expression_0=expressions[0],
+ expression_1=expressions[1],
+ expression_2=expressions[2],
+ expression_3=expressions[3],
+ distance_category_0=0,
+ distance_category_1=1,
+ distance_category_2=2,
+ distance_category_3=3,
+ distance=distance,
+ )
+ # FIXME Make the above more elegant?
+
+ msg = "Big expression (after formatting): {e}".format(e=expression)
+ grass.debug(_(msg))
+
+ return mobility_expression
+
+
+def compute_unmet_demand(
+ distance, constant, coefficients, population, score, suitability=None
+):
+ """
+ Parameters
+ ----------
+
+ distance :
+ Map of distance categories
+
+ constant :
+ Constant for the mobility function
+
+ coefficients :
+ A tuple with coefficients for the last distance category, as
+ (the example) presented in the following table:
+
+ |----------+---------+---------|
+ | Distance | Kappa | Alpha |
+ |----------+---------+---------|
+ | >4 | 0.06930 | 0.00057 |
+ |----------+---------+---------|
+
+ Note, this is the last distance category. See also the
+ mobility_function().
+
+ Note, the Alpha coefficient, is signed with a '-' in the mobility
+ function.
+
+ population :
+ A map with the distribution of the demand per distance category and
+ predefined geometric boundaries (see `r.stats.zonal` deriving the
+ 'unmet demand' map ).
+
+ score :
+ A score value for the mobility function
+
+ suitability :
+ [ NOTE: this argument is yet unused! It is meant to be used only after
+ successful integration of land suitability scores in
+ build_distance_function(). ]
+ If 'suitability' is given, it is used as a multiplication
+ factor to the base equation.
+
+ Returns
+ -------
+
+ mobility_expression :
+ A valid mapcalc expression to compute the flow based on the
+ predefined function `build_distance_function`.
+
+ Examples
+ --------
+ ...
+ """
+ distance_category = 4 # Hardcoded! FIXME
+
+ kappa, alpha = coefficients
+ unmet_demand_expression = build_distance_function(
+ constant=constant, kappa=kappa, alpha=-alpha, variable=population, score=score
+ )
+ # suitability=suitability) # Not used. Maybe it can, though,
+ # after successfull testing its integration to
+ # build_distance_function().
+
+ msg = "Expression for distance category '{d}': {e}"
+ msg = msg.format(d=distance_category, e=unmet_demand_expression)
+ grass.debug(_(msg))
+
+ # build expressions -- explicit: use the 'score' kwarg!
+ expression = (
+ "eval( unmet_demand = {expression},"
+ " \ \n distance = {distance} == {distance_category},"
+ " \ \n if( distance, unmet_demand,"
+ " \ \n null() ))"
+ )
+ grass.debug(_("Mapcalc expression: {e}".format(e=expression)))
+
+ # replace keywords appropriately
+ unmet_demand_expression = expression.format(
+ expression=unmet_demand_expression,
+ distance=distance,
+ distance_category=distance_category,
+ )
+
+ msg = "Big expression (after formatting): {e}".format(e=unmet_demand_expression)
+ grass.debug(_(msg))
+
+ return unmet_demand_expression
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/normalisation.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/normalisation.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/normalisation.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import grass.script as grass
+from grass.exceptions import CalledModuleError
+from grass.pygrass.modules.shortcuts import general as g
+from grass.pygrass.modules.shortcuts import raster as r
+from grass.pygrass.modules.shortcuts import vector as v
+
+from estimap_recreation.constants import *
+from estimap_recreation.grassy_utilities import *
+
+
+def zerofy_small_values(raster, threshhold, output_name):
+ """
+ Set the input raster map cell values to 0 if they are smaller than the
+ given threshhold
+
+ Parameters
+ ----------
+ raster :
+ Name of input raster map
+
+ threshhold :
+ Reference for which to flatten smaller raster pixel values to zero
+
+ output_name :
+ Name of output raster map
+
+ Returns
+ -------
+ Does not return any value
+
+ Examples
+ --------
+ ...
+ """
+ rounding = "if({raster} < {threshhold}, 0, {raster})"
+ rounding = rounding.format(raster=raster, threshhold=threshhold)
+ rounding_equation = EQUATION.format(result=output_name, expression=rounding)
+ grass.mapcalc(rounding_equation, overwrite=True)
+
+
+def normalize_map(raster, output_name):
+ """
+ Normalize all raster map cells by subtracting the raster map's minimum and
+ dividing by the range.
+
+ Parameters
+ ----------
+ raster :
+ Name of input raster map
+
+ output_name :
+ Name of output raster map
+
+ Returns
+ -------
+
+ Examples
+ --------
+ ...
+ """
+ # grass.debug(_("Input to normalize: {name}".format(name=raster)))
+ # grass.debug(_("Ouput: {name}".format(name=output_name)))
+
+ finding = grass.find_file(name=raster, element="cell")
+
+ if not finding["file"]:
+ grass.fatal("Raster map {name} not found".format(name=raster))
+ # else:
+ # grass.debug("Raster map {name} found".format(name=raster))
+
+ # univar_string = grass.read_command('r.univar', flags='g', map=raster)
+ # univar_string = univar_string.replace('\n', '| ').replace('\r', '| ')
+ # msg = "Univariate statistics: {us}".format(us=univar_string)
+
+ minimum = grass.raster_info(raster)["min"]
+ grass.debug(_("Minimum: {m}".format(m=minimum)))
+
+ maximum = grass.raster_info(raster)["max"]
+ grass.debug(_("Maximum: {m}".format(m=maximum)))
+
+ if minimum is None or maximum is None:
+ msg = "Minimum and maximum values of the <{raster}> map are 'None'. "
+ msg += "The {raster} map may be empty "
+ msg += "OR the MASK opacifies all non-NULL cells."
+ grass.fatal(_(msg.format(raster=raster)))
+
+ normalisation = "float(({raster} - {minimum}) / ({maximum} - {minimum}))"
+ normalisation = normalisation.format(
+ raster=raster, minimum=minimum, maximum=maximum
+ )
+
+ # Maybe this can go in the parent function? 'raster' names are too long!
+ # msg = "Normalization expression: "
+ # msg += normalisation
+ # grass.verbose(_(msg))
+
+ normalisation_equation = EQUATION.format(
+ result=output_name, expression=normalisation
+ )
+ grass.mapcalc(normalisation_equation, overwrite=True)
+
+ get_univariate_statistics(output_name)
+
+
+def zerofy_and_normalise_component(components, threshhold, output_name):
+ """
+ Sums up all maps listed in the given "components" object and derives a
+ normalised output.
+
+ To Do:
+
+ * Improve `threshold` handling. What if threshholding is not desired? How
+ to skip performing it?
+
+ Parameters
+ ----------
+ components :
+ Input list of raster maps (components)
+
+ threshhold :
+ Reference value for which to flatten all smaller raster pixel values to
+ zero
+
+ output_name :
+ Name of output raster map
+
+ Returns
+ -------
+ ...
+
+ Examples
+ --------
+ ...
+ """
+ msg = "Normalising sum of: "
+ msg += ",".join(components)
+ grass.debug(_(msg))
+ grass.verbose(_(msg))
+
+ if len(components) > 1:
+
+ # prepare string for mapcalc expression
+ components = [name.split("@")[0] for name in components]
+ components_string = SPACY_PLUS.join(components)
+ components_string = components_string.replace(" ", "")
+ components_string = components_string.replace("+", "_")
+
+ # temporary map names
+ tmp_intermediate = temporary_filename(filename=components_string)
+ tmp_output = temporary_filename(filename=components_string)
+
+ # build mapcalc expression
+ component_expression = SPACY_PLUS.join(components)
+ component_equation = EQUATION.format(
+ result=tmp_intermediate, expression=component_expression
+ )
+
+ grass.mapcalc(component_equation, overwrite=True)
+
+ elif len(components) == 1:
+ # temporary map names, if components contains one element
+ tmp_intermediate = components[0]
+ tmp_output = temporary_filename(filename=tmp_intermediate)
+
+ if threshhold > THRESHHOLD_ZERO:
+ msg = "Setting values < {threshhold} in '{raster}' to zero"
+ grass.verbose(msg.format(threshhold=threshhold, raster=tmp_intermediate))
+ zerofy_small_values(tmp_intermediate, threshhold, tmp_output)
+
+ else:
+ tmp_output = tmp_intermediate
+
+ # grass.verbose(_("Temporary map name: {name}".format(name=tmp_output)))
+ grass.debug(_("Output map name: {name}".format(name=output_name)))
+ # r.info(map=tmp_output, flags='gre')
+
+ ### FIXME
+
+ normalize_map(tmp_output, output_name)
+
+ ### FIXME
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/panos.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/panos.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/panos.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,13 @@
+def add_one(value):
+ new_value = value + 1
+ return new_value
+
+
+def add_two(value):
+ new_value = value + 2
+ return new_value
+
+
+def add_ten(value):
+ new_value = value + 20
+ return new_value
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/spectrum.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/spectrum.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/spectrum.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import grass.script as grass
+from grass.exceptions import CalledModuleError
+from grass.pygrass.modules.shortcuts import general as g
+from grass.pygrass.modules.shortcuts import raster as r
+from grass.pygrass.modules.shortcuts import vector as v
+
+from .constants import EQUATION
+
+
+def recreation_spectrum_expression(potential, opportunity):
+ """
+ Build and return a valid mapcalc expression for deriving
+ the Recreation Opportunity Spectrum
+
+ |-------------------------+-----+----------+------|
+ | Potential / Opportunity | Far | Midrange | Near |
+ |-------------------------+-----+----------+------|
+ | Low | 1 | 2 | 3 |
+ |-------------------------+-----+----------+------|
+ | Moderate | 4 | 5 | 6 |
+ |-------------------------+-----+----------+------|
+ | High | 7 | 8 | 9 |
+ |-------------------------+-----+----------+------|
+
+ Questions:
+
+ - Why not use `r.cross`?
+ - Use DUMMY strings for potential and opportunity raster map names?
+
+ Parameters
+ ----------
+ potential :
+ Map depicting potential for recreation
+
+ opportunity :
+ Map depicting opportunity for recreation
+
+ Returns
+ -------
+ expression :
+ A valid r.mapcalc expression
+
+ Examples
+ --------
+ ...
+ """
+ expression = (
+ "if( {potential} == 1 && {opportunity} == 1, 1,"
+ " \ \n if( {potential} == 1 && {opportunity} == 2, 2,"
+ " \ \n if( {potential} == 1 && {opportunity} == 3, 3,"
+ " \ \n if( {potential} == 2 && {opportunity} == 1, 4,"
+ " \ \n if( {potential} == 2 && {opportunity} == 2, 5,"
+ " \ \n if( {potential} == 2 && {opportunity} == 3, 6,"
+ " \ \n if( {potential} == 3 && {opportunity} == 1, 7,"
+ " \ \n if( {potential} == 3 && {opportunity} == 2, 8,"
+ " \ \n if( {potential} == 3 && {opportunity} == 3, 9)))))))))"
+ )
+
+ expression = expression.format(potential=potential, opportunity=opportunity)
+
+ msg = "Recreation Spectrum expression: \n"
+ msg += expression
+ grass.debug(msg)
+
+ return expression
+
+
+def compute_recreation_spectrum(potential, opportunity, spectrum):
+ """
+ Computes spectrum for recreation based on maps of potential and opportunity
+ for recreation
+
+ Parameters
+ ----------
+ potential :
+ Name for input potential for recreation map
+
+ opportunity :
+ Name for input opportunity for recreation map
+
+ Returns
+ -------
+ spectrum :
+ Name for output spectrum of recreation map
+
+ Examples
+ --------
+ ...
+ """
+ spectrum_expression = recreation_spectrum_expression(
+ potential=potential, opportunity=opportunity
+ )
+
+ spectrum_equation = EQUATION.format(result=spectrum, expression=spectrum_expression)
+
+ msg = "Recreation Spectrum equation: \n"
+ msg += spectrum_equation
+ grass.verbose(msg)
+
+ grass.mapcalc(spectrum_equation, overwrite=True)
+
+ return spectrum
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/supply_and_use.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/supply_and_use.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/supply_and_use.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,574 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import math
+import grass.script as grass
+from grass.pygrass.modules.shortcuts import general as g
+from grass.pygrass.modules.shortcuts import raster as r
+from grass.pygrass.modules.shortcuts import vector as v
+
+from .colors import MOBILITY_COLORS
+from .constants import EQUATION
+from .constants import HIGHEST_RECREATION_CATEGORY
+from .constants import SUITABILITY_SCORES_LABELS
+from .constants import COMMA
+from .constants import CSV_EXTENSION
+from .grassy_utilities import temporary_filename
+from .grassy_utilities import remove_map_at_exit, remove_files_at_exit
+from .grassy_utilities import string_to_file
+from .grassy_utilities import get_raster_statistics
+from .utilities import merge_two_dictionaries
+from .utilities import nested_dictionary_to_csv
+from .utilities import dictionary_to_csv
+
+
+def compile_use_table(supply):
+ """Compile the 'use' table out of a 'supply' table
+
+ Parameters
+ ----------
+ supply :
+ A nested Python dictionary that is compiled when runnning the
+ compute_supply() function
+
+ Returns
+ -------
+
+ Examples
+ --------
+ """
+ uses = {}
+ for outer_key, outer_value in supply.items():
+ dictionaries = outer_value
+ use_values = []
+ for key, value in dictionaries.items():
+ use_value = value[0]
+ use_values.append(use_value)
+
+ use_in_key = sum(
+ [float(x) if not math.isnan(float(x)) else 0 for x in use_values]
+ )
+
+ try:
+ uses[outer_key] = use_in_key
+ except KeyError:
+ print("Something went wrong in building the use table")
+
+ return uses
+
+
+def compute_supply(
+ base,
+ recreation_spectrum,
+ highest_spectrum,
+ base_reclassification_rules,
+ reclassified_base,
+ reclassified_base_title,
+ flow,
+ flow_map_name,
+ aggregation,
+ ns_resolution,
+ ew_resolution,
+ print_only=False,
+ flow_column_name=None,
+ vector=None,
+ supply_filename=None,
+ use_filename=None,
+):
+ """
+ Algorithmic description of the "Contribution of Ecosysten Types"
+
+ # FIXME
+ '''
+ 1 B ← {0, .., m-1} : Set of aggregational boundaries
+ 2 T ← {0, .., n-1} : Set of land cover types
+ 3 WE ← 0 : Set of weighted extents
+ 4 R ← 0 : Set of fractions
+ 5 F ← 0
+ 6 MASK ← HQR : High Quality Recreation
+ 7 foreach {b} ⊆ B do : for each aggregational boundary 'b'
+ 8 RB ← 0
+ 9 foreach {t} ⊆ T do : for each Land Type
+ 10 WEt ← Et * Wt : Weighted Extent = Extent(t) * Weight(t)
+ 11 WE ← WE⋃{WEt} : Add to set of Weighted Extents
+ 12 S ← ∑t∈WEt
+ 13 foreach t ← T do
+ 14 Rt ← WEt / ∑WE
+ 15 R ← R⋃{Rt}
+ 16 RB ← RB⋃{R}
+ '''
+ # FIXME
+
+ Parameters
+ ----------
+ recreation_spectrum:
+ Map scoring access to and quality of recreation
+
+ highest_spectrum :
+ Expected is a map of areas with highest recreational value (category 9
+ as per the report ... )
+
+ base :
+ Base land types map for final zonal statistics. Specifically to
+ ESTIMAP's recrceation mapping algorithm
+
+ base_reclassification_rules :
+ Reclassification rules for the input base map
+
+ reclassified_base :
+ Name for the reclassified base cover map
+
+ reclassified_base_title :
+ Title for the reclassified base map
+
+ ecosystem_types :
+
+ flow :
+ Map of visits, derived from the mobility function, depicting the
+ number of people living inside zones 0, 1, 2, 3. Used as a cover map
+ for zonal statistics.
+
+ flow_map_name :
+ A name for the 'flow' map. This is required when the 'flow' input
+ option is not defined by the user, yet some of the requested outputs
+ required first the production of the 'flow' map. An example is the
+ request for a supply table without requesting the 'flow' map itself.
+
+ aggregation :
+
+ ns_resolution :
+
+ ew_resolution :
+
+ statistics_filename :
+
+ supply_filename :
+ Name for CSV output file of the supply table
+
+ use_filename :
+ Name for CSV output file of the use table
+
+ flow_column_name :
+ Name for column to populate with 'flow' values
+
+ vector :
+ If 'vector' is given, a vector map of the 'flow' along with appropriate
+ attributes will be produced.
+
+ ? :
+ Land cover class percentages in ROS9 (this is: relative percentage)
+
+ output :
+ Supply table (distribution of flow for each land cover class)
+
+ Returns
+ -------
+ This function produces a map to base the production of a supply table in
+ form of CSV.
+
+ Examples
+ --------
+ """
+ # Inputs
+ flow_in_base = flow + "_" + base
+ base_scores = base + ".scores"
+
+ # Define lists and dictionaries to hold intermediate data
+ statistics_dictionary = {}
+ weighted_extents = {}
+ flows = []
+
+ # MASK areas of high quality recreation
+ r.mask(raster=highest_spectrum, overwrite=True, quiet=True)
+
+ # Reclassify land cover map to MAES ecosystem types
+ r.reclass(
+ input=base,
+ rules=base_reclassification_rules,
+ output=reclassified_base,
+ quiet=True,
+ )
+ # add to "remove_at_exit" after the reclassified maps!
+
+ # Discard areas out of MASK
+ copy_equation = EQUATION.format(
+ result=reclassified_base, expression=reclassified_base
+ )
+ r.mapcalc(copy_equation, overwrite=True)
+
+ # Count flow within each land cover category
+ r.stats_zonal(
+ base=base,
+ flags="r",
+ cover=flow_map_name,
+ method="sum",
+ output=flow_in_base,
+ overwrite=True,
+ quiet=True,
+ )
+
+ # Set colors for "flow" map
+ r.colors(map=flow_in_base, color=MOBILITY_COLORS, quiet=True)
+
+ # Parse aggregation raster categories and labels
+ categories = grass.parse_command("r.category", map=aggregation, delimiter="\t")
+
+ for category in categories:
+
+ # Intermediate names
+
+ cells = highest_spectrum + ".cells" + "." + category
+ remove_map_at_exit(cells)
+
+ extent = highest_spectrum + ".extent" + "." + category
+ remove_map_at_exit(extent)
+
+ weighted = highest_spectrum + ".weighted" + "." + category
+ remove_map_at_exit(weighted)
+
+ fractions = base + ".fractions" + "." + category
+ remove_map_at_exit(fractions)
+
+ flow_category = "_flow_" + category
+ flow = base + flow_category
+ remove_map_at_exit(flow)
+
+ flow_in_reclassified_base = reclassified_base + "_flow"
+ flow_in_category = reclassified_base + flow_category
+ flows.append(flow_in_category) # add to list for patching
+ remove_map_at_exit(flow_in_category)
+
+ # Output names
+
+ msg = "Processing aggregation raster category: {r}"
+ msg = msg.format(r=category)
+ grass.debug(_(msg))
+ # g.message(_(msg))
+
+ # First, set region to extent of the aggregation map
+ # and resolution to the one of the population map
+ # Note the `-a` flag to g.region: ?
+ # To safely modify the region: grass.use_temp_region() # FIXME
+ g.region(
+ raster=aggregation,
+ nsres=ns_resolution,
+ ewres=ew_resolution,
+ flags="a",
+ quiet=True,
+ )
+
+ msg = "|! Computational resolution matched to {raster}"
+ msg = msg.format(raster=aggregation)
+ grass.debug(_(msg))
+
+ # Build MASK for current category & high quality recreation areas
+ msg = "Setting category '{c}' of '{a}' as a MASK"
+ grass.verbose(_(msg.format(c=category, a=aggregation)))
+
+ masking = "if( {spectrum} == {highest_quality_category} && "
+ masking += "{aggregation} == {category}, "
+ masking += "1, null() )"
+ masking = masking.format(
+ spectrum=recreation_spectrum,
+ highest_quality_category=HIGHEST_RECREATION_CATEGORY,
+ aggregation=aggregation,
+ category=category,
+ )
+ masking_equation = EQUATION.format(result="MASK", expression=masking)
+ grass.mapcalc(masking_equation, overwrite=True)
+
+ # zoom to MASK
+ g.region(zoom="MASK", nsres=ns_resolution, ewres=ew_resolution, quiet=True)
+
+ # Count number of cells within each land category
+ r.stats_zonal(
+ flags="r",
+ base=base,
+ cover=highest_spectrum,
+ method="count",
+ output=cells,
+ overwrite=True,
+ quiet=True,
+ )
+ cells_categories = grass.parse_command("r.category", map=cells, delimiter="\t")
+ grass.debug(_("Cells: {c}".format(c=cells_categories)))
+
+ # Build cell category and label rules for `r.category`
+ cells_rules = "\n".join(
+ ["{0}:{1}".format(key, value) for key, value in cells_categories.items()]
+ )
+
+ # Discard areas out of MASK
+ copy_equation = EQUATION.format(result=cells, expression=cells)
+ r.mapcalc(copy_equation, overwrite=True)
+
+ # Reassign cell category labels
+ r.category(map=cells, rules="-", stdin=cells_rules, separator=":")
+
+ # Compute extent of each land category
+ extent_expression = "@{cells} * area()"
+ extent_expression = extent_expression.format(cells=cells)
+ extent_equation = EQUATION.format(result=extent, expression=extent_expression)
+ r.mapcalc(extent_equation, overwrite=True)
+
+ # Write extent figures as labels
+ r.stats_zonal(
+ flags="r",
+ base=base,
+ cover=extent,
+ method="average",
+ output=extent,
+ overwrite=True,
+ verbose=False,
+ quiet=True,
+ )
+
+ # Write land suitability scores as an ASCII file
+ temporary_reclassified_base_map = temporary_filename(filename=reclassified_base)
+ suitability_scores_as_labels = string_to_file(
+ SUITABILITY_SCORES_LABELS, filename=temporary_reclassified_base_map
+ )
+ remove_files_at_exit(suitability_scores_as_labels)
+
+ # Write scores as raster category labels
+ r.reclass(
+ input=base,
+ output=base_scores,
+ rules=suitability_scores_as_labels,
+ overwrite=True,
+ quiet=True,
+ verbose=False,
+ )
+ remove_map_at_exit(base_scores)
+
+ # Compute weighted extents
+ weighted_expression = "@{extent} * float(@{scores})"
+ weighted_expression = weighted_expression.format(
+ extent=extent, scores=base_scores
+ )
+ weighted_equation = EQUATION.format(
+ result=weighted, expression=weighted_expression
+ )
+ r.mapcalc(weighted_equation, overwrite=True)
+
+ # Write weighted extent figures as labels
+ r.stats_zonal(
+ flags="r",
+ base=base,
+ cover=weighted,
+ method="average",
+ output=weighted,
+ overwrite=True,
+ verbose=False,
+ quiet=True,
+ )
+
+ # Get weighted extents in a dictionary
+ weighted_extents = grass.parse_command(
+ "r.category", map=weighted, delimiter="\t"
+ )
+
+ # Compute the sum of all weighted extents and add to dictionary
+ category_sum = sum(
+ [
+ float(x) if not math.isnan(float(x)) else 0
+ for x in weighted_extents.values()
+ ]
+ )
+ weighted_extents["sum"] = category_sum
+
+ # Create a map to hold fractions of each weighted extent to the sum
+ # See also:
+ # https://grasswiki.osgeo.org/wiki/LANDSAT#Hint:_Minimal_disk_space_copies
+ r.reclass(
+ input=base,
+ output=fractions,
+ rules="-",
+ stdin="*=*",
+ verbose=False,
+ quiet=True,
+ )
+
+ # Compute weighted fractions of land types
+ fraction_category_label = {
+ key: float(value) / weighted_extents["sum"]
+ for (key, value) in weighted_extents.iteritems()
+ if key is not "sum"
+ }
+
+ # Build fraction category and label rules for `r.category`
+ fraction_rules = "\n".join(
+ [
+ "{0}:{1}".format(key, value)
+ for key, value in fraction_category_label.items()
+ ]
+ )
+
+ # Set rules
+ r.category(map=fractions, rules="-", stdin=fraction_rules, separator=":")
+
+ # Assert that sum of fractions is ~1
+ fraction_categories = grass.parse_command(
+ "r.category", map=fractions, delimiter="\t"
+ )
+
+ fractions_sum = sum(
+ [
+ float(x) if not math.isnan(float(x)) else 0
+ for x in fraction_categories.values()
+ ]
+ )
+ msg = "Fractions: {f}".format(f=fraction_categories)
+ grass.debug(_(msg))
+
+ # g.message(_("Sum: {:.17g}".format(fractions_sum)))
+ assert abs(fractions_sum - 1) < 1.0e-6, "Sum of fractions is != 1"
+
+ # Compute flow
+ flow_expression = "@{fractions} * @{flow}"
+ flow_expression = flow_expression.format(fractions=fractions, flow=flow_in_base)
+ flow_equation = EQUATION.format(result=flow, expression=flow_expression)
+ r.mapcalc(flow_equation, overwrite=True)
+
+ # Write flow figures as raster category labels
+ r.stats_zonal(
+ base=reclassified_base,
+ flags="r",
+ cover=flow,
+ method="sum",
+ output=flow_in_category,
+ overwrite=True,
+ verbose=False,
+ quiet=True,
+ )
+
+ # Parse flow categories and labels
+ flow_categories = grass.parse_command(
+ "r.category", map=flow_in_category, delimiter="\t"
+ )
+ grass.debug(_("Flow: {c}".format(c=flow_categories)))
+
+ # Build flow category and label rules for `r.category`
+ flow_rules = "\n".join(
+ ["{0}:{1}".format(key, value) for key, value in flow_categories.items()]
+ )
+
+ # Discard areas out of MASK
+
+ # Check here again!
+ # Output patch of all flow maps?
+
+ copy_equation = EQUATION.format(
+ result=flow_in_category, expression=flow_in_category
+ )
+ r.mapcalc(copy_equation, overwrite=True)
+
+ # Reassign cell category labels
+ r.category(map=flow_in_category, rules="-", stdin=flow_rules, separator=":")
+
+ # Update title
+ reclassified_base_title += " " + category
+ r.support(flow_in_category, title=reclassified_base_title)
+
+ # debugging
+ # r.report(
+ # flags='hn',
+ # map=(flow_in_category),
+ # units=('k','c','p'),
+ # )
+
+ if print_only:
+ r.stats(
+ input=(flow_in_category),
+ output="-",
+ flags="nacpl",
+ separator=COMMA,
+ quiet=True,
+ )
+
+ if not print_only:
+
+ if flow_column_name:
+ flow_column_prefix = flow_column_name + category
+ else:
+ flow_column_name = "flow"
+ flow_column_prefix = flow_column_name + category
+
+ # Produce vector map(s)
+ if vector:
+
+ # The following is wrong
+
+ # update_vector(vector=vector,
+ # raster=flow_in_category,
+ # methods=METHODS,
+ # column_prefix=flow_column_prefix)
+
+ # What can be done?
+
+ # Maybe update columns of an existing map from the columns of
+ # the following vectorised raster map(s)
+ # ?
+
+ raster_to_vector(
+ raster=flow_in_category, vector=flow_in_category, type="area"
+ )
+
+ # get statistics
+ dictionary = get_raster_statistics(
+ map_one=aggregation, # reclassified_base
+ map_two=flow_in_category,
+ separator="|",
+ flags="nlcap",
+ )
+
+ # merge 'dictionary' with global 'statistics_dictionary'
+ statistics_dictionary = merge_two_dictionaries(
+ statistics_dictionary, dictionary
+ )
+
+ # It is important to remove the MASK!
+ r.mask(flags="r", quiet=True)
+
+ # FIXME
+
+ # Add "reclassified_base" map to "remove_at_exit" here, so as to be after
+ # all reclassified maps that derive from it
+
+ # remove the map 'reclassified_base'
+ # g.remove(flags='f', type='raster', name=reclassified_base, quiet=True)
+ # remove_map_at_exit(reclassified_base)
+
+ if not print_only:
+ r.patch(flags="", input=flows, output=flow_in_reclassified_base, quiet=True)
+
+ if vector:
+ # Patch all flow vector maps in one
+ v.patch(
+ flags="e",
+ input=flows,
+ output=flow_in_reclassified_base,
+ overwrite=True,
+ quiet=True,
+ )
+
+ # export to csv
+ if supply_filename:
+ supply_filename += CSV_EXTENSION
+ nested_dictionary_to_csv(supply_filename, statistics_dictionary)
+
+ if use_filename:
+ use_filename += CSV_EXTENSION
+ uses = compile_use_table(statistics_dictionary)
+ dictionary_to_csv(use_filename, uses)
+
+ # Maybe return list of flow maps? Requires unique flow map names
+ return flows
Added: grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/utilities.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/utilities.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/estimap_recreation/utilities.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ at author Nikos Alexandris |
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import csv
+
+
+def merge_two_dictionaries(first, second):
+ """Merge two dictionaries in via shallow copy.
+ Source: https://stackoverflow.com/a/26853961/1172302"""
+ merged_dictionary = first.copy()
+ merged_dictionary.update(second)
+ return merged_dictionary
+
+
+def dictionary_to_csv(filename, dictionary):
+ """Write a Python dictionary as CSV named 'filename'
+
+ Parameters
+ ----------
+ filename :
+ Name for output file
+
+ dictionary :
+ Name of input Python dictionary to write to 'filename'
+
+ Returns
+ -------
+ This function does not return anything
+
+ Examples
+ --------
+ """
+ f = open(filename, "wb")
+ w = csv.writer(f)
+
+ # write a header
+ w.writerow(["category", "label", "value"])
+
+ # terminology: from 'base' and 'cover' maps
+ for base_key, value in dictionary.items():
+ base_category = base_key[0]
+ base_label = base_key[1] # .decode('utf-8')
+ if value is None or value == "":
+ continue
+ w.writerow([base_category, base_label, value])
+
+ f.close()
+
+
+def nested_dictionary_to_csv(filename, dictionary):
+ """Write out a nested Python dictionary as CSV named 'filename'
+
+ Parameters
+ ----------
+ filename :
+ Name for output file
+
+ dictionary :
+ Name of the input Python dictionary
+ """
+ f = open(filename, "wb")
+ w = csv.writer(f)
+
+ # write a header
+ w.writerow(
+ ["base", "base_label", "cover", "cover_label", "area", "count", "percents"]
+ )
+
+ # terminology: from 'base' and 'cover' maps
+ for base_key, inner_dictionary in dictionary.items():
+ base_category = base_key[0]
+ base_label = base_key[1] # .decode('utf-8')
+
+ for cover_category, inner_value in inner_dictionary.items():
+ if inner_value is None or inner_value == "":
+ continue
+ cover_label = inner_value[0]
+ area = inner_value[1]
+ pixel_count = inner_value[2]
+ pixel_percentage = inner_value[3]
+ w.writerow(
+ [
+ base_category,
+ base_label,
+ cover_category,
+ cover_label,
+ area,
+ pixel_count,
+ pixel_percentage,
+ ]
+ )
+
+ f.close()
+
+
+# This function should be better off this module # FIXME
+def get_coefficients(coefficients_string):
+ """Returns coefficients from an input coefficients_string
+
+ Parameters
+ ----------
+ coefficients_string:
+ One string which lists a metric and coefficients separated by comma
+ without spaces
+
+ Returns
+ -------
+ metric:
+ Metric to use an input option to the `r.grow.distance` module
+
+ constant:
+ A constant value for the 'attractiveness' function
+
+ kappa:
+ A Kappa coefficients for the 'attractiveness' function
+
+ alpha:
+ An alpha coefficient for the 'attractiveness' function
+
+ score
+ A score value to multiply by the generic 'attractiveness' function
+
+ Examples
+ --------
+ ...
+ """
+ coefficients = coefficients_string.split(",")
+ msg = "Distance function coefficients: "
+ metric = coefficients[0]
+ msg += "Metric='{metric}', ".format(metric=metric)
+ constant = coefficients[1]
+ msg += "Constant='{constant}', ".format(constant=constant)
+ kappa = coefficients[2]
+ msg += "Kappa='{Kappa}', ".format(Kappa=kappa)
+ alpha = coefficients[3]
+ msg += "Alpha='{alpha}', ".format(alpha=alpha)
+ try:
+ if coefficients[4]:
+ score = coefficients[4]
+ msg += "Score='{score}'".format(score=score)
+ grass.verbose(_(msg)) # FIXME REMOVEME ?
+ return metric, constant, kappa, alpha, score
+ except IndexError:
+ grass.verbose(_("Score not provided")) # FIXME REMOVEME ?
+
+ grass.verbose(_(msg)) # FIXME REMOVEME ?
+ return metric, constant, kappa, alpha
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_area_of_interest.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_area_of_interest.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_area_of_interest.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_area_of_interest.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_area_of_interest.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_bathing_water_quality.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_bathing_water_quality.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_bathing_water_quality.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_bathing_water_quality.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_bathing_water_quality.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006_suitability.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006_suitability.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006_suitability.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006_suitability.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_2006_suitability.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_legend.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_legend.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_legend.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_legend.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_corine_land_cover_legend.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_demand.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_demand.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_demand.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_demand.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_demand.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_distance_to_infrastructure.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_distance_to_infrastructure.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_distance_to_infrastructure.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_distance_to_infrastructure.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_distance_to_infrastructure.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_land_suitability.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_land_suitability.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_land_suitability.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_land_suitability.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_land_suitability.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_local_administrative_units.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_local_administrative_units.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_local_administrative_units.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_local_administrative_units.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_local_administrative_units.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_mobility.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_mobility.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_mobility.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_mobility.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_mobility.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_opportunity.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_opportunity.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_opportunity.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_opportunity.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_opportunity.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_population_2015.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_population_2015.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_population_2015.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_population_2015.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_population_2015.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_1.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_1.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_1.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_1.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_1.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_2.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_2.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_2.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_2.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_2.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_3.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_3.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_3.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_3.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_3.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_4.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_4.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_4.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_4.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_4.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_based_on_corine_land_cover_2006.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_based_on_corine_land_cover_2006.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_based_on_corine_land_cover_2006.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_based_on_corine_land_cover_2006.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_based_on_corine_land_cover_2006.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_corine.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_corine.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_corine.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_corine.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_corine.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_masked.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_masked.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_masked.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_masked.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_potential_masked.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_protected_areas.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_protected_areas.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_protected_areas.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_protected_areas.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_protected_areas.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum_high_provision_near.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum_high_provision_near.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum_high_provision_near.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum_high_provision_near.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_spectrum_high_provision_near.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_unmet_demand.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_unmet_demand.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_unmet_demand.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_unmet_demand.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_unmet_demand.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Added: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_water_resources.png
===================================================================
(Binary files differ)
Index: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_water_resources.png
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_water_resources.png 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_water_resources.png 2019-03-01 11:47:49 UTC (rev 74143)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/images/r_estimap_recreation_water_resources.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Deleted: grass-addons/grass7/raster/r.estimap.recreation/land_suitability.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/local_administrative_units.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/mobility.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/opportunity.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/population_2015.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_1.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_2.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_3.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_4.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_based_on_corine_land_cover_2006.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_corine.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/potential_masked.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/protected_areas.png
===================================================================
(Binary files differ)
Added: grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/Makefile
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/Makefile (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/Makefile 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../../..
+
+PGM = r.estimap.recreation
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script
Added: grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.html
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.html (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.html 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,1238 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.estimap.recreation</em> is an implementation of the ESTIMAP recreation algorithm
+to support mapping and modelling of ecosystem services (Zulian, 2014).
+
+<p>
+The algorithm
+estimates the capacity of ecosystems to provide opportunities
+for nature-based recreation
+and leisure
+(recreation opportunity spectrum).
+
+First,
+it bases upon look-up tables,
+to score access to or the quality
+of natural features
+(land suitability, protected areas, infrastructure, water resources)
+for their potential to support for outdoor recreation
+(potential recreation).
+
+Second,
+it implements a proximity-remoteness concept
+to integrate
+the recreation potential
+and the existing infrastructure.
+
+
+<p>
+The module offers two functionalities.
+
+One is the production of recreation related maps by using pre-processed maps
+that depict the quality of or the access to areas of recreational value.
+The other is to transform maps that depict natural features into scored maps
+that reflect the potential to support for outdoor recreational.
+
+<em>Nevertheless, it is strongly advised to understand first the concepts and
+ the terminology behind the algorithm, by reading the related sources.</em>
+
+
+<h5>Terminology</h5>
+
+First, an overview of the terminology
+
+<dl>
+ <dt> Recreation Potential</dt>
+ <dd> is ... </dd>
+ <dt> Recreation Opportunity</dt>
+ <dd> is ... </dd>
+ <dt> Recreation (Opportunity) Spectrum</dt>
+ <dd> is ... </dd>
+ <dt> Demand Distribution</dt>
+ <dd> is ... </dd>
+ <dt> Unmet Demand Distribution</dt>
+ <dd> is ... </dd>
+ <dt> Mobidtty</dt>
+ <dd> is ... </dd>
+ <dt> Flow</dt>
+ <dd> is ... </dd>
+ <dt> Supply</dt>
+ <dd> is ... </dd>
+ <dt> Use</dt>
+ <dd> is ... </dd>
+</dl>
+
+<h5>Recreation Potential</h5>
+
+<p>
+The recreation potential map,
+derives by adding and normalizing
+maps of natural <i>components</i>
+that may provide recreation opportunities.
+
+Components are user-defined, pre-processed, input raster maps,
+that score access to or quality of resources such as:
+
+<ul>
+ <li> land</li>
+ <li> natural</li>
+ <li> water</li>
+ <li> urban</li>
+</ul>
+
+<p>
+Alternatively,
+the module treats unprocessed maps,
+by providing a set of relevant scores or coefficients,
+to derive component maps required by the algorithm.
+
+
+FIXME
+1. an ASCII file with a set of land suitability scores (see below)
+2. a string listing a set of comma-separated scores for each raster category.. -- FIXME
+3. in the case of the CORINE map, use of internal rules
+FIXME
+
+For example,
+a CORINE land cover map
+may be given to the 'landuse' input option
+along with a set of land suitability scores,
+that correspond to the CORINE nomenclature.
+The latter is fed as an ASCII file
+to the 'suitability_scores' input option.
+
+<h5>Recreation Opportunity</h5>
+
+<p>
+...
+
+<h5>Recreation Spectrum</h5>
+
+<p>
+The recreation (opportunity) spectrum map,
+derives by combining the recreation potential
+and maps that depict access (i.e. infrastructure) and/or
+areas that provide opportunities for recreational activities.
+
+<p>
+<strong>Explain here</strong>
+significance of areas with the
+<em>Highest Recreation Spectrum</em>.
+
+<p>
+<div class="tg-wrap"><table>
+ <tr>
+ <th>Potential | Opportunity</th>
+ <th>Near</th>
+ <th>Midrange</th>
+ <th>Far</th>
+ </tr>
+ <tr>
+ <td>Near</td>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>Midrange</td>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ <tr>
+ <td>Far</td>
+ <td>7</td>
+ <td>8</td>
+ <td>9</td>
+ </tr>
+</table></div>
+
+<h5>Flow, Supply and Use</h5>
+
+<p>
+By integrating
+maps of
+regions of interest
+and population,
+the module
+supports the production of
+a series of
+<i>demand</i>
+and <i>flow</i> maps
+as well as exporting
+related <i>supply</i> and <i>use</i> tables.
+
+<h3>Mathematical Background</h3>
+
+<p>
+The following equation represents the logic behind ESTIMAP:
+<pre>
+Recreation <strong>Spectrum</strong> = Recreation <strong>Potential</strong> + Recreation <strong>Opportunity</strong>
+</pre>
+
+<h5>Remoteness and Proximity</h5>
+
+The base
+<em>distance</em>
+function
+to quantify
+<em>attractiveness</em>, is:
+
+<div class="code"><pre>
+( {Constant} + {Kappa} ) / ( {Kappa} + exp({alpha} * {Variable}) )
+</pre></div>
+
+where
+
+<ul>
+ <li>Constant</li>
+ <li>Coefficients
+ <ul>
+ <li>Kappa</li>
+ <li>Alpha</li>
+ </ul>
+ </li>
+ <li>Variable</li>
+</ul>
+
+<h5>Accessibility</h5>
+
+<h5>Normalization</h5>
+
+Each <em>component</em> is normalized.
+
+That is,
+all maps listed in a given component
+are summed up and normalised.
+Normalizing any raster map,
+be it a single map
+or the sum of a series of maps,
+is performed by
+subtracting its minimum value
+and dividing by its range.
+
+<h2>EXAMPLES</h2>
+
+For the sake of demonstrating the usage of the module,
+we use the following "component" maps
+<ul>
+ <li><pre>area_of_interest</pre></li>
+ <li><pre>land_suitability</pre></li>
+ <li><pre>water_resources</pre></li>
+ <li><pre>protected_areas</pre></li>
+</ul>
+(available to download at: ...)
+to derive a recreation <i>potential</i> map.
+
+<p>
+Below,
+a table overviewing
+all input and output maps
+used or produced in the examples.
+
+<p>
+<div class="tg-wrap"><table>
+ <tr>
+ <th></th>
+ <th>Input map name</th>
+ <th>Spatial Resolution</th>
+ <th>Remarks</th>
+ </tr>
+ <tr>
+ <td></td>
+ <td>area_of_interest</td>
+ <td>50 m</td>
+ <td>A map that can be used as a 'mask'</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>land_suitability</td>
+ <td>50 m</td>
+ <td>A map scoring the potential for recreation over CORINE land classes</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>water_resources</td>
+ <td>50 m</td>
+ <td>A map scoring access to water resources</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>protected_areas</td>
+ <td>50 m</td>
+ <td>A map scoring the recreational value of natural protected areas</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>distance_to_infrastructure</td>
+ <td>50 m</td>
+ <td>A map scoring access to infrastructure</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>population_2015</td>
+ <td>1000 m</td>
+ <td>The resolution of the raster map given to the 'populatio' input option
+ will define the resolution of the output maps 'demand', 'unmet' and
+ 'flow'</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>local_administrative_unit</td>
+ <td>50 m</td>
+ <td>A rasterised version of Eurostat's Local Administrative Units map</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <th>Output map name</th>
+ <th>Spatial Resolution</th>
+ <th>Remarks</th>
+ </tr>
+ <tr>
+ <td></td>
+ <td>potential<br></td>
+ <td>50 m</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>potential_1</td>
+ <td>50 m</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>potential_2</td>
+ <td>50 m</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>potential_3</td>
+ <td>50 m</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>potential_4</td>
+ <td>50 m</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>spectrum</td>
+ <td>50 m</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>opportunity</td>
+ <td>50 m</td>
+ <td>Requires to request for the 'spectrum' output</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>demand</td>
+ <td>1000 m</td>
+ <td>Depends on the 'flow' map which, in turn, depends on the 'population' input map</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>unmet</td>
+ <td>1000 m</td>
+ <td>Depends on the 'flow' map which, in turn, depends on the 'population' input map<br></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>flow</td>
+ <td>1000 m</td>
+ <td>Depends on the 'population' input map</td>
+ </tr>
+ <tr>
+ <td></td>
+ <th>Output table name</th>
+ <th></th>
+ <th></th>
+ </tr>
+ <tr>
+ <td></td>
+ <td>supply</td>
+ <td>NA</td>
+ <td></td>
+ </tr>
+</table></div>
+
+<p>
+<div>
+<center>
+ <img src="images/area_of_interest.png" alt="Example of a land suitability input map">
+ <img src="images/land_suitability.png" alt="Example of a land suitability input map">
+ <img src="images/water_resources.png" alt="Example of a water resources input map">
+ <img src="images/protected_areas.png" alt="Example of a protected areas input map">
+</center>
+</div>
+
+
+<p>
+Before anything, we need to define the extent of interest using
+<div class="code"><pre>
+g.region raster=area_of_interest
+</pre></div>
+
+
+<h3>Using pre-processed maps</h3>
+
+The first four input options of the module are designed to receive
+pre-processed input maps that classify as either
+<code>land</code>,
+<code>natural</code>,
+<code>water</code>
+and <code>infrastructure</code>
+resources.
+
+<h4>Potential</h4>
+
+<p>
+To compute a <em>potential</em> output map,
+the simplest possible command call
+requires the user
+to define the input map option
+<code>land</code> and
+define a name for the output map option
+<code>potential</code>.
+
+Using a pre-processed map
+that depicts the suitability of different land types
+to support for recreation
+(here the map named
+<code>land_suitability</code>)
+the command to execute is:
+
+<div class="code"><pre>
+r.estimap.recreation land=land_suitability potential=potential
+</pre></div>
+
+<p>
+<center>
+<img src="images/potential.png" alt="Example of a recreation potential output map">
+</center>
+
+<p>
+Note,
+this will process the input map
+<code>land_suitability</code>
+over the extent defined previously via
+<code>g.region</code>,
+which is the standard behaviour in GRASS GIS.
+
+<p>
+To exclude certain areas from the computations,
+we may use a raster map
+as a mask and feed it to the input map
+option <code>mask</code>:
+
+<div class="code"><pre>
+r.estimap.recreation land=land_suitability mask=area_of_interest potential=potential_1
+</pre></div>
+
+<p>
+<center>
+<img src="images/potential_1.png" alt="Example of a recreation potential output map while using a MASK">
+</center>
+
+The use of a mask
+(in GRASS GIS' terminology known as <strong>MASK</strong>)
+will ignore areas of <strong>No Data</strong>
+(pixels in the
+<code>area_of_interest</code>
+map assigned the NULL value).
+Successively,
+these areas will be empty in the output map
+<code>potential_1</code>.
+
+Actually,
+the same effect can be achieved
+by using GRASS GIS' native mask creation module <code>r.mask</code>
+and feed it with a raster map of interest.
+The result will be a raster map named <strong>MASK</strong>
+whose presence acts as a filter.
+
+In the following examples,
+it becomes obvious that
+if a single input map
+features such <strong>No Data</strong> areas,
+they will be propagated in the output map.
+
+<p>
+Nonetheless, it is good practice to use a <code>MASK</code>
+when one needs to ensure
+the exclusion of undesired areas
+from any computations.
+
+Also,
+note the <code>--o</code> flag:
+it is required to overwrite
+the already existing map named
+<code>potential_1</code>.
+
+<p>
+Next, we add a water component, a map named
+<code>water_resources</code>,
+modify the output map name to <code>potential_2</code>
+and execute again, without a mask:
+
+<div class="code"><pre>
+r.estimap.recreation land=land_suitability water=water_resources potential=potential_2
+</pre></div>
+
+<p>
+<center>
+<img src="images/potential_2.png" alt="Example of a recreation potential output map while using a MASK, a land suitability map and a water resources map">
+</center>
+
+At this point it becomes clear that all <code>NULL</code> cells present in the
+"water" map, are propagated in the output map <code>potential_2</code>.
+
+<p>
+Following, we provide a map of protected areas named
+<code>protected_areas</code>,
+modify the output map name to
+<code>potential_3</code>
+and repeat the command execution:
+
+<div class="code"><pre>
+r.estimap.recreation land=land_suitability water=water_resources natural=protected_areas potential=potential_3
+</pre></div>
+
+<p>
+<center>
+<img src="images/potential_3.png" alt="Example of a recreation potential output map
+while using a MASK, a land suitability map, a water resources map and a natural
+resources map">
+</center>
+
+<p>
+While the <code>land</code> option
+accepts only one map as an input,
+both the <code>water</code> and the <code>natural</code> options
+accept multiple maps as inputs.
+
+In example,
+we add a second map named
+<code>bathing_water_quality</code>
+to the water component and modify the output map name to
+<code>potential_4</code>:
+<div class="code"><pre>
+r.estimap.recreation land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas potential=potential_4
+</pre></div>
+
+
+<p>
+In general, arbitrary number of maps,
+separated by comma,
+may be added to options that accept multiple inputs.
+
+<p>
+<center>
+<img src="images/potential_4.png" alt="Example of a recreation potential output map
+while using a MASK, a land suitability map, two water resources maps and a natural
+resources map">
+</center>
+
+<p>
+This example, features also a title and a legend, so as to make sense of the
+map.
+
+<div class="code"><pre>
+d.rast potential_4
+d.legend -c -b potential_4 at=0,15,0,1 border_color=white
+d.text text="Potential" bgcolor=white
+</pre></div>
+
+
+<p>
+The different output map names
+are purposefully selected
+so as to enable a visual
+comparison of the differences
+among the differenct examples.
+
+The output maps
+<code>potential_1</code>,
+<code>potential_2</code>,
+<code>potential_3</code>
+and <code>potential_4</code>
+range within [0,3].
+Yet, they differ in the distribution of values
+due to the different set of input maps.
+
+<p>
+All of the above examples
+base upon pre-processed maps
+that score the access to and quality of
+land, water and natural resources.
+
+For using <i>raw</i>, unprocessed maps,
+read section <b>Using unprocessed maps</b>.
+
+<h4>Spectrum</h4>
+
+To derive a map
+with the recreation (opportunity)
+<code>spectrum</code>,
+we need in addition an
+<code>infrastructure</code>
+component.
+
+In this example a map that scores distance to infrastructure (such as the road
+network) named
+<code>distance_to_infrastructure</code>
+is defined as an input:
+
+<p>
+<center>
+<img src="images/distance_to_infrastructure.png" alt="Example of an input map showing distances to infrastructure">
+</center>
+
+Naturally,
+we need to define the output map option
+<code>spectrum</code> too:
+
+<div class="code"><pre>
+r.estimap.recreation \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure
+ spectrum=spectrum \
+</pre></div>
+
+or, the same command in a copy-paste friendly way:
+<div class="code"><pre>
+r.estimap.recreation land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure spectrum=spectrum
+</pre></div>
+
+<p>
+<center>
+<img src="images/spectrum.png" alt="Example of a recreation spectrum output map
+while using a MASK, a land suitability map, a water resources map and a natural
+resources map">
+</center>
+
+Missing to define the
+<code>infrastructure</code> map,
+the command will abort and inform about.
+
+<p>
+The image above, was produced via the following native GRASS GIS commands
+<div class="code"><pre>
+d.rast spectrum
+d.legend -c -b spectrum at=0,30,0,1 border_color=white
+d.text text="Spectrum" bgcolor=white
+</pre></div>
+
+<h5>Opportunity</h5>
+
+The <code>opportunity</code> map
+is actually an intermediate step
+of the algorithm.
+The option to output this map
+<code>opportunity</code>
+is meant for expert users
+who want to explore
+the fundamentals of the processing steps.
+Hence,
+it requires to define
+the output option <code>spectrum</code>
+map as well.
+
+Building upon the previous command, we add the <code>opportunity</code> output
+option:
+
+<div class="code"><pre>
+r.estimap.recreation \
+ mask=area_of_interest \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ spectrum=spectrum \
+ infrastructure=distance_to_infrastructure \
+ opportunity=opportunity
+</pre></div>
+
+or, the same command in a copy-paste friendly way:
+<div class="code"><pre>
+r.estimap.recreation mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas spectrum=spectrum infrastructure=distance_to_infrastructure opportunity=opportunity
+</pre></div>
+
+<p>
+<center>
+<img src="images/opportunity.png" alt="Example of a recreation spectrum output map
+while using a MASK, a land suitability map, a water resources map and a natural
+resources map">
+</center>
+
+
+<h4>More input maps</h4>
+
+To derive the outputs
+met <code>demand</code> distributiom,
+<code>unmet</code> demand distributiom
+and the actual <code>flow</code>,
+additional requirements are
+a <code>population</code> map
+and one of boundaries,
+as an input to the option
+<code>base</code>,
+within which to quantify the distribution of the population.
+Using a map of administrative boundaries for the latter option,
+serves for deriving comparable figures across these boundaries.
+
+The algorithm sets internally the spatial resolution
+of all related output maps
+<code>demand</code>,
+<code>unmet</code> and
+<code>flow</code>
+to the spatial resolution of the
+<code>population</code>
+input map.
+
+<p>
+Population
+<center>
+<img src="images/population_2015.png" alt="Fragment of a population map (GHSL, 2015)">
+</center>
+In this example, the population map named <code>population_2015</code> is of
+1000m^2.
+
+
+<p>
+Local administrative units
+<center>
+<img src="images/local_administrative_units.png" alt="Fragment of a local administrative units input map">
+</center>
+The map named
+<code>local_administrative_units</code>
+serves in the following example
+as the base map for the zonal statistics to obtain the demand map.
+
+<h4>Demand</h4>
+
+<div class="code"><pre>
+r.estimap.recreation --o \
+ mask=area_of_interest \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure \
+ demand=demand \
+ population=population_2015 \
+ base=local_administrative_units
+</pre></div>
+
+or, the same command in a copy-paste friendly way:
+<div class="code"><pre>
+r.estimap.recreation --o mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure demand=demand population=population_2015 base=local_administrative_units
+</pre></div>
+
+<p>
+<center>
+<img src="images/demand.png" alt="Example of a demand distribution output map while using
+a MASK
+and inputs for
+land suitability,
+water resources,
+natural resources,
+infrastructure,
+population
+and base">
+</center>
+
+<h4>Unmet Demand</h4>
+
+<div class="code"><pre>
+r.estimap.recreation --o \
+ mask=area_of_interest \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure \
+ demand=demand \
+ unmet=unmet_demand \
+ population=population_2015 \
+ base=local_administrative_units
+</pre></div>
+
+or, the same command in a copy-paste friendly way:
+<div class="code"><pre>
+r.estimap.recreation --o mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure demand=demand unmet=unmet_demand population=population_2015 base=local_administrative_units
+</pre></div>
+
+<p>
+<center>
+<img src="images/unmet_demand.png" alt="Example of an 'unmet demand' output map while using
+a MASK
+and inputs for
+land suitability,
+water resources,
+natural resources,
+infrastructure,
+population
+and base">
+</center>
+
+<h4>Flow</h4>
+
+<p>
+The
+<i>flow</i>
+bases upon the same function
+used to quantify the attractiveness
+of locations for their recreational value.
+It includes an extra
+<em>score</em>
+term.
+
+<p>
+The computation involves a
+<em>distance</em> map,
+reclassified in 5 categories
+as shown in the following table.
+
+For each distance category,
+a unique pair of coefficient values
+is assigned to the basic equation.
+
+<div class="tg-wrap"><table>
+ <tr>
+ <th>Distance</th>
+ <th>Kappa</th>
+ <th>Alpha</th>
+ </tr>
+ <tr>
+ <td>0 to 1</td>
+ <td>0.02350</td>
+ <td>0.00102</td>
+ </tr>
+ <tr>
+ <td>1 to 2</td>
+ <td>0.02651</td>
+ <td>0.00109</td>
+ </tr>
+ <tr>
+ <td>2 to 3</td>
+ <td>0.05120</td>
+ <td>0.00098</td>
+ </tr>
+ <tr>
+ <td>3 to 4</td>
+ <td>0.10700</td>
+ <td>0.00067</td>
+ </tr>
+ <tr>
+ <td>>4</td>
+ <td>0.06930</td>
+ <td>0.00057</td>
+ </tr>
+</table></div>
+
+<p>
+Note, the last distance category is not considered in deriving the final "map
+of visits".
+
+The output is essentially
+a raster map
+with the distribution of the demand
+per distance category and within predefined geometric boundaries
+
+<p>
+<div class="code"><pre>
+r.estimap.recreation --o \
+ mask=area_of_interest \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure \
+ mobility=mobility \
+ population=population_2015 \
+ base=local_administrative_units
+</pre></div>
+
+or, the same command in a copy-paste friendly way:
+<div class="code"><pre>
+r.estimap.recreation --o mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure mobility=mobility population=population_2015 base=local_administrative_units
+</pre></div>
+
+<p>
+<center>
+<img src="images/mobility.png" alt="Example of a mobility output map while using
+a MASK
+and inputs for
+land suitability,
+water resources,
+natural resources,
+infrastructure,
+population
+and base">
+</center>
+
+<h4>All in one call</h4>
+
+Of course it is possible to derive all output maps with one call:
+<div class="code"><pre>
+r.estimap.recreation --o \
+ mask=area_of_interest \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure \
+ potential=potential \
+ opportunity=opportunity \
+ spectrum=spectrum \
+ demand=demand \
+ unmet=unmet_demand \
+ mobility=mobility \
+ population=population_2015 \
+ base=local_administrative_units
+ timestamp='2018'
+</pre></div>
+
+or, the same command in a copy-paste friendly way:
+<div class="code"><pre>
+r.estimap.recreation --o mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure potential=potential opportunity=opportunity spectrum=spectrum demand=demand unmet=unmet_demand mobility=mobility population=population_2015 base=local_administrative_units timestamp='2018'
+</pre></div>
+
+<p>
+Note the use of
+the <code>timestamp</code>
+parameter!
+This concerns the <code>spectrum</code> map.
+If plans
+include working with GRASS GIS' temporal framework
+on time-series,
+this will be useful.
+
+<h4>Supply and Use tables</h4>
+
+The module can export
+<em>supply</em> and
+<em>use</em> tables,
+in form of CSV files,
+given the identically named
+<code>supply</code>
+and <code>use</code>
+file name output options are defined.
+
+In order to extract a supply table, the module requires maps
+that enable the estimation of the actual flow and how each different ecosystem
+type contributes, in terms of its areal extent, to this flow.
+
+The dependencies to extract a supply table are the following:
+
+<ul>
+ <li>the recreation potential which requires either of, or any
+ combination of, or all of the land, natural and water related
+ components</li>
+
+ <li>the recreation opportunity spectrum which requires any of the above in
+ addition to either of, or any combination of, or all of the inputs related
+ to the infrastructure component</li>
+
+ <li>the demand distribution which requires the combined minimim requirements
+ of the previous items, so as to derive areas of high recreational value,
+ in addition to a population map and a <em>base</em> map of zones, over
+ which to aggregate the population</li>
+
+ <li>and finally the land types (be it a land cover, a land use or a mixture)
+ map so as to estimate the contribution of each land type in the actual flow
+ in addition to a map of zones over which to aggregate the actual flow</li>
+</ul>
+
+Practically and in terms of components (that is pre-processed maps), the
+module requires at minimum the following input options
+
+<ul>
+ <li><code>land</code> or <code>water</code> or <code>natural</code></li>
+ <li><code>infrastructure</code></li>
+ <li><code>population</code></li>
+ <li><code>base</code></li>
+ <li><code>landcover</code></li>
+ <li><code>aggregation</code></li>
+</ul>
+
+and the output option <code>supply</code>
+
+<p>
+An example command to derive a supply table is:
+
+<div class="code"><pre>
+r.estimap.recreation \
+ land=land_suitability \
+ infrastructure=distance_to_infrastructure \
+ population=population_2015 \
+ base=local_administrative_units \
+ landcover=corine_land_cover_2006 \
+ aggregation=regions \
+ supply=supply
+</pre></div>
+
+or, instead of the land component, only using the <code>water</code> component
+
+<div class="code"><pre>
+r.estimap.recreation \
+ water=water_resources \
+ infrastructure=distance_to_infrastructure \
+ population=population_2015 \
+ base=local_administrative_units \
+ landcover=corine_land_cover_2006 \
+ land_classes=corine_accounting_to_maes_land_classes.rules \
+ aggregation=regions \
+ supply=supply
+</pre></div>
+
+or, instead, using only the <code>natural</code> component:
+
+<div class="code"><pre>
+r.estimap.recreation \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure \
+ population=population_2015 \
+ base=local_administrative_units \
+ landcover=corine_land_cover_2006 \
+ land_classes=corine_accounting_to_maes_land_classes.rules \
+ aggregation=regions \
+ supply=supply
+</pre></div>
+
+Here a "real" example:
+
+<div class="code"><pre>
+r.estimap.recreation --o mask=area_of_interest land=land_suitability water=water_resources,bathing_water_quality natural=protected_areas infrastructure=distance_to_infrastructure potential=potential opportunity=opportunity spectrum=spectrum demand=demand unmet=unmet_demand population=population_2015 base=local_administrative_units timestamp='2018' landcover=corine_land_cover_2006 aggregation=regions land_classes=../categories_and_rules/corine_accounting_to_maes_land_classes.rules supply=supply use=us
+</pre></div>
+
+which will output the following supply table
+
+<div class="code"><pre>
+base,base_label,cover,cover_label,area,count,percents
+3,Region 3,1,355.747658,6000000.000000,6,6.38%
+3,Region 3,3,216304.146140,46000000.000000,46,48.94%
+3,Region 3,2,26627.415787,46000000.000000,46,48.94%
+1,Region 1,1,1466.340177,11000000.000000,11,9.09%
+1,Region 1,3,13837.701610,10000000.000000,10,8.26%
+1,Region 1,2,105488.837775,88000000.000000,88,72.73%
+1,Region 1,4,902.359018,13000000.000000,13,10.74%
+1,Region 1,7,53.747332,4000000.000000,4,3.31%
+4,Region 4,1,26884.220460,65000000.000000,65,28.26%
+4,Region 4,3,291863.216396,70000000.000000,70,30.43%
+4,Region 4,2,48260.411774,92000000.000000,92,40.00%
+4,Region 4,4,477.251251,7000000.000000,7,3.04%
+2,Region 2,1,1113.270785,11000000.000000,11,10.19%
+2,Region 2,3,157977.541352,58000000.000000,58,53.70%
+2,Region 2,2,7701.208609,29000000.000000,29,26.85%
+2,Region 2,4,3171.919491,15000000.000000,15,13.89%
+5,Region 5,1,27748.714430,37000000.000000,37,44.58%
+5,Region 5,3,133262.033972,31000000.000000,31,37.35%
+5,Region 5,2,2713.756942,15000000.000000,15,18.07%
+5,Region 5,4,677.823622,5000000.000000,5,6.02%
+6,Region 6,1,14377.698637,31000000.000000,31,57.41%
+6,Region 6,3,56746.359740,14000000.000000,14,25.93%
+6,Region 6,2,4117.270100,13000000.000000,13,24.07%
+</pre></div>
+
+The <em>use</em> table can be requested via the <code>use</code> output option.
+
+<h3>Using unprocessed input maps</h3>
+
+<p>
+The module
+offers a pre-processing functionality
+for all of the following input components:
+
+<ul>
+ <li>landuse</li>
+ <li>suitability_scores</li>
+</ul>
+<ul>
+ <li>landcover</li>
+ <li>land_classes</li>
+</ul>
+<ul>
+ <li>lakes</li>
+ <li>lakes_coefficients</li>
+ <li>default is set to: euclidean,1,30,0.008,1</li>
+</ul>
+<ul>
+ <li>coastline</li>
+ <li>coastline_coefficients</li>
+ <li>default is set to: euclidean,1,30,0.008,1</li>
+ <li>coast_geomorphology</li>
+</ul>
+<ul>
+ <li>bathing_water</li>
+ <li>bathing_coefficients</li>
+ <li>default is set to: euclidean,1,5,0.01101</li>
+</ul>
+<ul>
+ <li>protected</li>
+ <li>protected_scores</li>
+ <li>11:11:0,12:12:0.6,2:2:0.8,3:3:0.6,4:4:0.6,5:5:1,6:6:0.8,7:7:0,8:8:0,9:9:0</li>
+</ul>
+<ul>
+ <li>anthropic</li>
+ <li>anthropic_distances</li>
+ <li>0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5</li>
+</ul>
+<ul>
+ <li>roads</li>
+ <li>roads_distances</li>
+ <li>0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5</li>
+</ul>
+
+<p>
+A first look on how this works,
+is to experiment with
+the <code>landuse</code>
+and <code>suitability_scores</code>
+input options.
+
+<p>
+Let's return to the first example, and use a fragment from the unprocessed
+CORINE land data set, instead of the <code>land_suitability</code> map. This
+requires a set of "score" rules, that correspond to the CORINE nomenclature, to
+translate the land cover types into recreation potential.
+
+<p>
+<div>
+ <center>
+ <img src="images/corine_land_cover_2006.png" alt="Fragment from the CORINE land data base ">
+ <img src="images/corine_land_cover_legend.png" alt="Legend for the CORINE land data base">
+ </center>
+</div>
+
+<p>
+In this case,
+the rules are a simple ASCII file
+(for example named <code>corine_suitability.scores</code>
+that contains the following
+
+<div class="code"><pre>
+1:1:0:0
+2:2:0.1:0.1
+3:9:0:0
+10:10:1:1
+11:11:0.1:0.1
+12:13:0.3:0.3
+14:14:0.4:0.4
+15:17:0.5:0.5
+18:18:0.6:0.6
+19:20:0.3:0.3
+21:22:0.6:0.6
+23:23:1:1
+24:24:0.8:0.8
+25:25:1:1
+26:29:0.8:0.8
+30:30:1:1
+31:31:0.8:0.8
+32:32:0.7:0.7
+33:33:0:0
+34:34:0.8:0.8
+35:35:1:1
+36:36:0.8:0.8
+37:37:1:1
+38:38:0.8:0.8
+39:39:1:1
+40:42:1:1
+43:43:0.8:0.8
+44:44:1:1
+45:45:0.3:0.3
+</pre></div>
+
+This file is provided in the <code>suitability_scores</code> option:
+
+<div class="code"><pre>
+r.estimap.recreation landuse=corine_land_cover_2006 suitability_scores=corine_suitability.scores potential=potential_corine --o
+</pre></div>
+
+<p>
+<center>
+<img src="images/potential_corine.png" alt="Example of a recreation spectrum output map
+while using a MASK, based on a fragment from the CORINE land data base">
+</center>
+
+The same can be achieved with a long one-line string too:
+
+<div class="code"><pre>
+r.estimap.recreation \
+ landuse=corine_land_cover_2006 \
+ suitability_scores="1:1:0:0,2:2:0.1:0.1,3:9:0:0,10:10:1:1,11:11:0.1:0.1,12:13:0.3:0.3,14:14:0.4:0.4,15:17:0.5:0.5,18:18:0.6:0.6,19:20:0.3:0.3,21:22:0.6:0.6,23:23:1:1,24:24:0.8:0.8,25:25:1:1,26:29:0.8:0.8,30:30:1:1,31:31:0.8:0.8,32:32:0.7:0.7,33:33:0:0,34:34:0.8:0.8,35:35:1:1,36:36:0.8:0.8,37:37:1:1,38:38:0.8:0.8,39:39:1:1,40:42:1:1,43:43:0.8:0.8,44:44:1:1,45:45:0.3:0.3" potential=potential_1 --o
+</pre></div>
+
+In fact,
+this very scoring scheme,
+for CORINE land data sets,
+is integrated in the module,
+so we obtain the same output
+even by discarding the <code>suitability_scores</code> option:
+
+<div class="code"><pre>
+r.estimap.recreation landuse=corine_land_cover_2006 suitability_scores=corine_suitability.scores potential=potential_1 --o
+</pre></div>
+
+This is so
+because CORINE is a standard choice
+among existing land data bases
+that cover european territories.
+
+In case of a user requirement to provide an alternative scoring scheme, all
+what is required is either of
+
+<ul>
+ <li>provide a new "rules" file with the desired set of scoring rules</li>
+ <li>provide a string to the <code>suitability_scores</code> option</li>
+</ul>
+
+<h2>REFERENCES</h2>
+
+<ul>
+ <li>http://publications.jrc.ec.europa.eu/repository/bitstream/JRC87585/lb-na-26474-en-n.pd</li>
+</ul>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.univar.html">r.univar</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>
+</em>
+
+<h2>AUTHOR</h2>
+
+Nikos Alexandris
+
+<h2>COPYRIGHT</h2>
+
+Copyright 2018 European Union
+
+Licensed under the EUPL, Version 1.2 or – as soon they will be
+approved by the European Commission – subsequent versions of the
+EUPL (the "Licence");
+
+You may not use this work except in compliance with the Licence.
+You may obtain a copy of the Licence at:
+
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-11-12
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the Licence is distributed on an
+"AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+either express or implied. See the Licence for the specific
+language governing permissions and limitations under the Licence.
+
+Consult the LICENCE file for details.
+
+<p><i>Last changed: $Date: 2017-11-03 18:21:39 +0100 (Fri, 03 Nov 2017) $</i>
Added: grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,668 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ MODULE: r.estimap.recreation
+
+ AUTHOR(S): Nikos Alexandris <nik at nikosalexandris.net>
+
+ First implementation as a collection of Python scripts by
+ Grazia Zulian <Grazia.Zulian at ec.europa.eu>
+
+ PURPOSE: An implementation of the Ecosystem Services Mapping Tool
+ (ESTIMAP). ESTIMAP is a collection of spatially explicit models
+ to support mapping and modelling of ecosystem services
+ at European scale.
+
+ SOURCES: https://www.bts.gov/archive/publications/journal_of_transportation_and_statistics/volume_04_number_23/paper_03/index
+
+ COPYRIGHT: Copyright 2018 European Union
+
+ Licensed under the EUPL, Version 1.2 or – as soon they will be
+ approved by the European Commission – subsequent versions of the
+ EUPL (the "Licence");
+
+ You may not use this work except in compliance with the Licence.
+ You may obtain a copy of the Licence at:
+
+ https://joinup.ec.europa.eu/collection/eupl/eupl-text-11-12
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the Licence is distributed on an
+ "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ either express or implied. See the Licence for the specific
+ language governing permissions and limitations under the Licence.
+
+ Consult the LICENCE file for details.
+"""
+
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+# --- Flags ---
+
+#%Module
+#% description: Implementation of ESTIMAP to support mapping and modelling of ecosystem services (Zulian, 2014)
+#% keywords: estimap
+#% keywords: ecosystem services
+#% keywords: recreation potential
+#%End
+
+#%flag
+#% key: e
+#% description: Match computational region to extent of land use map
+#%end
+
+#%flag
+#% key: f
+#% description: Filter maps in land and natural components before computing recreation maps
+#%end
+
+#%flag
+#% key: s
+#% description: Save temporary maps for debugging
+#%end
+
+#%flag
+#% key: i
+#% description: Print out citation and other information
+#%end
+
+#%flag
+#% key: p
+#% description: Print out results (i.e. supply table), don't export to file
+#%end
+
+"""
+exclusive: at most one of the options may be given
+required: at least one of the options must be given
+requires: if the first option is given, at least one of the subsequent options must also be given
+requires_all: if the first option is given, all of the subsequent options must also be given
+excludes: if the first option is given, none of the subsequent options may be given
+collective: all or nothing; if any option is given, all must be given
+"""
+
+# --- Components section ---
+
+#%option G_OPT_R_INPUT
+#% key: land
+#% type: string
+#% key_desc: name
+#% label: Input map scoring access to and suitability of land resources for recreation
+#% description: Arbitrary number of maps scoring access to and land resources suitability of land use classes to support recreation activities
+#% required: no
+#% guisection: Components
+#%end
+
+#%option G_OPT_R_INPUTS
+#% key: natural
+#% key_desc: name
+#% label: Input maps scoring access to and quality of inland natural resources
+#% description: Arbitrary number of maps scoring access to and quality of inland natural resources
+#% required: no
+#% guisection: Components
+#%end
+
+#%option G_OPT_R_INPUTS
+#% key: water
+#% key_desc: name
+#% label: Input maps scoring access to and quality of water resources
+#% description: Arbitrary number of maps scoring access to and quality of water resources such as lakes, sea, bathing waters and riparian zones
+#% required: no
+#% guisection: Components
+#%end
+
+#%option G_OPT_R_INPUTS
+#% key: urban
+#% key_desc: name
+#% description: Input maps scoring recreational value of urban surfaces
+#% required: no
+#% guisection: Components
+#%end
+
+#%option G_OPT_R_INPUTS
+#% key: infrastructure
+#% type: string
+#% key_desc: name
+#% label: Input maps scoring infrastructure to reach locations of recreation activities
+#% description: Infrastructure to reach locations of recreation activities [required to derive recreation spectrum map]
+#% required: no
+#% guisection: Components
+#%end
+
+#%option G_OPT_R_INPUTS
+#% key: recreation
+#% type: string
+#% key_desc: name
+#% label: Input maps scoring recreational facilities, amenities and services
+#% description: Recreational opportunities facilities, amenities and services [required to derive recreation spectrum map]
+#% required: no
+#% guisection: Components
+#%end
+
+# ---Land---
+
+#%option G_OPT_R_INPUT
+#% key: landuse
+#% type: string
+#% key_desc: name
+#% label: Input land features map from which to derive suitability for recreation
+#% description: Input to derive suitability of land use classes to support recreation activities. Requires scores, overrides suitability.
+#% required: no
+#% guisection: Land
+#%end
+
+#%rules
+#% exclusive: land
+#%end
+
+#%option G_OPT_F_INPUT
+#% key: suitability_scores
+#% type: string
+#% key_desc: filename
+#% label: Input recreational suitability scores for the categories of the 'landuse' map
+#% description: Scores for suitability of land to support recreation activities. Expected are rules for `r.recode` that correspond to categories of the input 'landuse' map. If the 'landuse' map is given and 'suitability_scores not provided, the module will use internal rules for the CORINE land classes.
+#% required: no
+#% guisection: Land
+#%end
+
+#%rules
+#% excludes: land, suitability_scores
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: landcover
+#% type: string
+#% key_desc: name
+#% label: Input land cover map from which to derive cover percentages within zones of high recreational value
+#% description: Input to derive percentage of land classes within zones of high recreational value.
+#% required: no
+#% guisection: Land
+#%end
+
+#%option G_OPT_F_INPUT
+#% key: land_classes
+#% type: string
+#% key_desc: filename
+#% label: Input reclassification rules for the classes of the 'landcover' map
+#% description: Expected are rules for `r.reclass` that correspond to classes of the input 'landcover' map. If 'landcover' map is given and 'land_classess' not provided, the module will use internal rules for the Urban Atlas land classes
+#% required: no
+#% guisection: Land
+#%end
+
+# --- Water ---
+
+#%option G_OPT_R_INPUT
+#% key: lakes
+#% key_desc: name
+#% label: Input map of inland waters resources for which to score accessibility
+#% description: Map of inland water resources to compute proximity for, score accessibility based on a distance function
+#% required: no
+#% guisection: Water
+#%end
+
+#%option
+#% key: lakes_coefficients
+#% type: string
+#% key_desc: Coefficients
+#% label: Input distance function coefficients for the 'lakes' map
+#% description: Distance function coefficients to compute proximity: distance metric, constant, kappa, alpha and score. Refer to the manual for details.
+#% multiple: yes
+#% required: no
+#% guisection: Water
+#% answer: euclidean,1,30,0.008,1
+#%end
+
+##%rules
+##% requires: lakes, lakes_coefficients
+##%end
+
+#%option G_OPT_R_INPUT
+#% key: coastline
+#% key_desc: name
+#% label: Input sea coast map for which to compute proximity
+#% description: Input map to compute coast proximity, scored based on a distance function
+#% required: no
+#% guisection: Water
+#%end
+
+#%option
+#% key: coastline_coefficients
+#% key_desc: Coefficients
+#% label: Input distance function coefficients for the 'coastline' map
+#% description: Distance function coefficients to compute proximity: distance metric, constant, kappa, alpha and score. Refer to the manual for details.
+#% multiple: yes
+#% required: no
+#% guisection: Water
+#% answer: euclidean,1,30,0.008,1
+#%end
+
+#%rules
+#% requires: coastline, coastline_coefficients
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: coast_geomorphology
+#% key_desc: name
+#% label: Input map scoring recreation potential in coast
+#% description: Coastal geomorphology, scored as suitable to support recreation activities
+#% required: no
+#% guisection: Water
+#%end
+
+#%rules
+#% requires: coast_geomorphology, coastline
+#%end
+
+##%option
+##% key: geomorphology_coefficients
+##% key_desc: Coefficients
+##% label: Input distance function coefficients
+##% description: Distance function coefficients to compute proximity: distance metric, constant, kappa, alpha and score. Refer to the manual for details.
+##% multiple: yes
+##% required: no
+##% guisection: Water
+##% answer: euclidean,1,30,0.008,1
+##%end
+
+##%rules
+##% requires: coast_geomorphology, geomorphology_coefficients
+##%end
+
+#%option G_OPT_R_INPUT
+#% key: bathing_water
+#% key_desc: name
+#% label: Input bathing water quality map
+#% description: Bathing water quality index. The higher, the greater is the recreational value.
+#% required: no
+#% guisection: Water
+#%end
+
+#%option
+#% key: bathing_coefficients
+#% type: string
+#% key_desc: Coefficients
+#% label: Input distance function coefficients for the 'bathing_water' map
+#% description: Distance function coefficients to compute proximity to bathing waters: distance metric, constant, kappa and alpha. Refer to the manual for details.
+#% multiple: yes
+#% required: no
+#% guisection: Water
+#% answer: euclidean,1,5,0.01101
+#%end
+
+#%rules
+#% requires: bathing_water, bathing_coefficients
+#%end
+
+##%rules
+##% exclusive: lakes
+##% exclusive: coastline
+##% excludes: water, coast_geomorphology, coast_proximity, marine, lakes, lakes_proximity, bathing_water
+##%end
+
+# --- Natural ---
+
+#%option G_OPT_R_INPUT
+#% key: protected
+#% key_desc: filename
+#% label: Input protected areas map
+#% description: Input map depicting natural protected areas
+#% required: no
+#% guisection: Natural
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: protected_scores
+#% type: string
+#% key_desc: rules
+#% label: Input recreational value scores for the classes of the 'protected' map
+#% description: Scores for recreational value of designated areas. Expected are rules for `r.recode` that correspond to classes of the input land use map. If the 'protected' map is given and 'protected_scores' are not provided, the module will use internal rules for the IUCN categories.
+#% required: no
+#% guisection: Anthropic
+#% answer: 11:11:0,12:12:0.6,2:2:0.8,3:3:0.6,4:4:0.6,5:5:1,6:6:0.8,7:7:0,8:8:0,9:9:0
+#%end
+
+##%rules
+##% exclusive: natural, protected
+##% exclusive: protected, natural
+###% requires: protected, protected_scores
+##%end
+
+# --- Artificial areas ---
+
+#%option G_OPT_R_INPUT
+#% key: artificial
+#% key_desc: name
+#% label: Input map of artificial surfaces
+#% description: Partial input map to compute proximity to artificial areas, scored via a distance function
+#% required: no
+#% guisection: Water
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: artificial_distances
+#% type: string
+#% key_desc: rules
+#% label: Input distance classification rules
+#% description: Categories for distance to artificial surfaces. Expected are rules for `r.recode` that correspond to distance values in the 'artificial' map
+#% required: no
+#% guisection: Anthropic
+#% answer: 0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5
+#%end
+
+#%rules
+#% requires: artificial, artificial_distances
+#%end
+
+# --- Road ---
+
+#%option G_OPT_R_INPUT
+#% key: roads
+#% key_desc: name
+#% label: Input map of primary road network
+#% description: Input map to compute roads proximity, scored based on a distance function
+#% required: no
+#% guisection: Infrastructure
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: roads_distances
+##% key: roads_scores
+#% type: string
+#% key_desc: rules
+#% label: Input distance classification rules
+#% description: Categories for distance to roads. Expected are rules for `r.recode` that correspond to distance values in the roads map
+#% required: no
+#% guisection: Anthropic
+#% answer: 0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5
+#%end
+
+#%rules
+#% requires: roads, roads_distances
+#% collective: artificial, roads
+#%end
+
+# --- Recreation ---
+
+#######################################################################
+# Offer input for potential?
+
+# #%option G_OPT_R_OUTPUT
+# #% key: recreation_potential
+# #% key_desc: name
+# #% description: Recreation potential map
+# #% required: no
+# #% answer: recreation_potential
+# #% guisection: Components
+# #%end
+
+#
+#######################################################################
+
+## Review the following item's "parsing rules"!
+
+##%rules
+##% excludes: infrastructure, roads
+##%end
+
+# --- Devaluation ---
+
+#%option G_OPT_R_INPUTS
+#% key: devaluation
+#% key_desc: name
+#% label: Input map of devaluing elements
+#% description: Maps hindering accessibility to and degrading quality of various resources or infrastructure relating to recreation
+#% required: no
+#% guisection: Devaluation
+#%end
+
+# --- MASK ---
+
+#%option G_OPT_R_INPUT
+#% key: mask
+#% key_desc: name
+#% description: A raster map to apply as a MASK
+#% required: no
+#%end
+
+# --- Output ---
+
+#%option G_OPT_R_OUTPUT
+#% key: potential
+#% key_desc: name
+#% label: Output map of recreation potential
+#% description: Recreation potential map classified in 3 categories
+#% required: no
+#% guisection: Output
+#%end
+
+#%rules
+#% requires: potential, land, natural, water, landuse, protected, lakes, coastline
+#%end
+
+#%option G_OPT_R_OUTPUT
+#% key: opportunity
+#% key_desc: name
+#% label: Output intermediate map of recreation opportunity
+#% description: Intermediate step in deriving the 'spectrum' map, classified in 3 categories, meant for expert use
+#% required: no
+#% guisection: Output
+#%end
+
+#%rules
+#% requires: opportunity, infrastructure, roads
+#%end
+
+#%option G_OPT_R_OUTPUT
+#% key: spectrum
+#% key_desc: name
+#% label: Output map of recreation spectrum
+#% description: Recreation spectrum map classified by default in 9 categories
+#% required: no
+#% guisection: Output
+#%end
+
+#%rules
+#% requires: spectrum, infrastructure, roads
+##% requires: spectrum, landcover
+#% required: land, landcover, landuse
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: spectrum_distances
+#% type: string
+#% key_desc: rules
+#% label: Input distance classification rules for the 'spectrum' map
+#% description: Classes for distance to areas of high recreational spectrum. Expected are rules for `r.recode` that correspond to classes of the input spectrum of recreation use map.
+#% required: no
+#% guisection: Output
+#% answer: 0:1000:1,1000:2000:2,2000:3000:3,3000:4000:4,4000:*:5
+#%end
+
+# --- Required for Cumulative Opportunity Model ---
+
+#%option G_OPT_R_INPUT
+#% key: base
+#% key_desc: name
+#% description: Input base map for zonal statistics
+#% required: no
+#%end
+
+#%option G_OPT_V_INPUT
+#% key: base_vector
+#% key_desc: name
+#% description: Input base vector map for zonal statistics
+#% required: no
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: aggregation
+#% key_desc: name
+#% description: Input map of regions over which to aggregate the actual flow
+#% required: no
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: population
+#% key_desc: name
+#% description: Input map of population density
+#% required: no
+#%end
+
+#%option G_OPT_R_OUTPUT
+#% key: demand
+#% type: string
+#% key_desc: name
+#% label: Output map of demand distribution
+#% description: Demand distribution output map: population density per Local Administrative Unit and areas of high recreational value
+#% required: no
+#% guisection: Output
+#%end
+
+#%option G_OPT_R_OUTPUT
+#% key: unmet
+#% type: string
+#% key_desc: name
+#% label: Output map of unmet demand distribution
+#% description: Unmet demand distribution output map: population density per Local Administrative Unit and areas of high recreational value
+#% required: no
+#% guisection: Output
+#%end
+
+#%rules
+#% requires_all: demand, population, base
+#% requires: demand, infrastructure, artificial, roads
+#% requires: unmet, demand
+#%end
+
+#%option G_OPT_R_OUTPUT
+#% key: flow
+#% type: string
+#% key_desc: name
+#% label: Output map of flow
+#% description: Flow output map: population (per Local Administrative Unit) near areas of high recreational value
+#% required: no
+#% guisection: Output
+#%end
+
+#%rules
+#% requires_all: flow, population, base
+#% requires: flow, infrastructure, artificial, roads
+#%end
+
+#%option G_OPT_F_OUTPUT
+#% key: supply
+#% key_desc: prefix
+#% type: string
+#% label: Output prefix for the file name of the supply table CSV
+#% description: Supply table CSV output file names will get this prefix
+#% multiple: no
+#% required: no
+#% guisection: Output
+#%end
+
+#%option G_OPT_F_OUTPUT
+#% key: use
+#% key_desc: prefix
+#% type: string
+#% label: Output prefix for the file name of the supply table CSV
+#% description: Supply table CSV output file names will get this prefix
+#% multiple: no
+#% required: no
+#% guisection: Output
+#%end
+
+#%rules
+#% requires: opportunity, spectrum, demand, flow, supply
+#% required: potential, spectrum, demand, flow, supply, use
+#%end
+
+#%rules
+#% requires: supply, land, natural, water, landuse, protected, lakes, coastline
+#% requires_all: supply, population
+#% requires_all: supply, landcover, land_classes
+#% requires: supply, base, base_vector, aggregation
+#% requires: supply, landcover, landuse
+#% requires_all: use, population
+#% requires: use, base, base_vector, aggregation
+#% requires: use, landcover, landuse
+#%end
+
+# --- Various ---
+
+#%option
+#% key: metric
+#% key_desc: Metric
+#% label: Distance metric to areas of highest recreation opportunity spectrum
+#% description: Distance metric to areas of highest recreation opportunity spectrum
+#% multiple: yes
+#% options: euclidean,squared,maximum,manhattan,geodesic
+#% required: no
+#% guisection: Output
+#% answer: euclidean
+#%end
+
+#%option
+#% key: units
+#% key_desc: Units
+#% label: Units to report
+#% description: Units to report the demand distribution
+#% multiple: yes
+#% options: mi,me,k,a,h,c,p
+#% required: no
+#% guisection: Output
+#% answer: k
+#%end
+
+#%option
+#% key: timestamp
+#% type: string
+#% label: Timestamp
+#% description: Timestamp for the recreation potential raster map
+#% required: no
+#%end
+
+# required librairies
+
+import datetime
+import os
+import subprocess
+import sys
+import time
+from pprint import pprint as pp
+
+if "GISBASE" not in os.environ:
+ sys.exit("Exiting: You must be in GRASS GIS to run this program.")
+
+import grass.script as grass
+
+from grass.script.utils import set_path
+try:
+ # set python path to the shared libraries
+ set_path('r.estimap.recreation', 'estimap_recreation', '..')
+ # constants
+ from estimap_recreation.colors import *
+ from estimap_recreation.constants import *
+ from estimap_recreation.labels import *
+ # main
+ from estimap_recreation.main import main as main_estimap
+except ImportError:
+ try:
+ set_path('r.estimap.recreation', 'estimap_recreation', os.path.join('..', 'etc', 'r.estimap.recreation'))
+ # constants
+ from estimap_recreation.colors import *
+ from estimap_recreation.constants import *
+ from estimap_recreation.labels import *
+ # main
+ from estimap_recreation.main import main as main_estimap
+ except ImportError:
+ gcore.warning('estimap_recreation not in the python path!')
+
+
+def main(options, flags):
+ sys.exit(main_estimap())
+
+if __name__ == "__main__":
+ options, flags = grass.parser()
+ main(options, flags)
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation/r.estimap.recreation.py
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.html
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.html 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.html 2019-03-01 11:47:49 UTC (rev 74143)
@@ -221,7 +221,7 @@
<li><pre>water_resources</pre></li>
<li><pre>protected_areas</pre></li>
</ul>
-(available to download at: ...)
+(available to download at: ...)
to derive a recreation <i>potential</i> map.
<p>
@@ -371,10 +371,10 @@
<p>
<div>
<center>
- <img src="area_of_interest.png" alt="Example of a land suitability input map">
- <img src="land_suitability.png" alt="Example of a land suitability input map">
- <img src="water_resources.png" alt="Example of a water resources input map">
- <img src="protected_areas.png" alt="Example of a protected areas input map">
+ <img src="images/r_estimap_recreation_area_of_interest.png" alt="Example of a land suitability input map">
+ <img src="images/r_estimap_recreation_land_suitability.png" alt="Example of a land suitability input map">
+ <img src="images/r_estimap_recreation_water_resources.png" alt="Example of a water resources input map">
+ <img src="images/r_estimap_recreation_protected_areas.png" alt="Example of a protected areas input map">
</center>
</div>
@@ -420,7 +420,7 @@
<p>
<center>
-<img src="potential.png" alt="Example of a recreation potential output map">
+<img src="images/r_estimap_recreation_potential.png" alt="Example of a recreation potential output map">
</center>
<p>
@@ -443,7 +443,7 @@
<p>
<center>
-<img src="potential_1.png" alt="Example of a recreation potential output map while using a MASK">
+<img src="images/r_estimap_recreation_potential_1.png" alt="Example of a recreation potential output map while using a MASK">
</center>
The use of a mask
@@ -493,7 +493,7 @@
<p>
<center>
-<img src="potential_2.png" alt="Example of a recreation potential output map while using a MASK, a land suitability map and a water resources map">
+<img src="images/r_estimap_recreation_potential_2.png" alt="Example of a recreation potential output map while using a MASK, a land suitability map and a water resources map">
</center>
At this point it becomes clear that all <code>NULL</code> cells present in the
@@ -512,7 +512,7 @@
<p>
<center>
-<img src="potential_3.png" alt="Example of a recreation potential output map
+<img src="images/r_estimap_recreation_potential_3.png" alt="Example of a recreation potential output map
while using a MASK, a land suitability map, a water resources map and a natural
resources map">
</center>
@@ -540,7 +540,7 @@
<p>
<center>
-<img src="potential_4.png" alt="Example of a recreation potential output map
+<img src="images/r_estimap_recreation_potential_4.png" alt="Example of a recreation potential output map
while using a MASK, a land suitability map, two water resources maps and a natural
resources map">
</center>
@@ -597,7 +597,7 @@
<p>
<center>
-<img src="distance_to_infrastructure.png" alt="Example of an input map showing distances to infrastructure">
+<img src="images/r_estimap_recreation_distance_to_infrastructure.png" alt="Example of an input map showing distances to infrastructure">
</center>
Naturally,
@@ -620,7 +620,7 @@
<p>
<center>
-<img src="spectrum.png" alt="Example of a recreation spectrum output map
+<img src="images/r_estimap_recreation_spectrum.png" alt="Example of a recreation spectrum output map
while using a MASK, a land suitability map, a water resources map and a natural
resources map">
</center>
@@ -673,7 +673,7 @@
<p>
<center>
-<img src="opportunity.png" alt="Example of a recreation spectrum output map
+<img src="images/r_estimap_recreation_opportunity.png" alt="Example of a recreation spectrum output map
while using a MASK, a land suitability map, a water resources map and a natural
resources map">
</center>
@@ -706,7 +706,7 @@
<p>
Population
<center>
-<img src="population_2015.png" alt="Fragment of a population map (GHSL, 2015)">
+<img src="images/r_estimap_recreation_population_2015.png" alt="Fragment of a population map (GHSL, 2015)">
</center>
In this example, the population map named <code>population_2015</code> is of
1000m^2.
@@ -715,7 +715,7 @@
<p>
Local administrative units
<center>
-<img src="local_administrative_units.png" alt="Fragment of a local administrative units input map">
+<img src="images/r_estimap_recreation_local_administrative_units.png" alt="Fragment of a local administrative units input map">
</center>
The map named
<code>local_administrative_units</code>
@@ -743,7 +743,7 @@
<p>
<center>
-<img src="demand.png" alt="Example of a demand distribution output map while using
+<img src="images/r_estimap_recreation_demand.png" alt="Example of a demand distribution output map while using
a MASK
and inputs for
land suitability,
@@ -776,7 +776,7 @@
<p>
<center>
-<img src="unmet_demand.png" alt="Example of an 'unmet demand' output map while using
+<img src="images/r_estimap_recreation_unmet_demand.png" alt="Example of an 'unmet demand' output map while using
a MASK
and inputs for
land suitability,
@@ -871,7 +871,7 @@
<p>
<center>
-<img src="mobility.png" alt="Example of a mobility output map while using
+<img src="images/r_estimap_recreation_mobility.png" alt="Example of a mobility output map while using
a MASK
and inputs for
land suitability,
@@ -946,7 +946,7 @@
<li>the demand distribution which requires the combined minimim requirements
of the previous items, so as to derive areas of high recreational value,
- in addition to a population map and a <em>base</em> map of zones, over
+ in addition to a population map and a <em>base</em> map of zones, over
which to aggregate the population</li>
<li>and finally the land types (be it a land cover, a land use or a mixture)
@@ -1110,8 +1110,8 @@
<p>
<div>
<center>
- <img src="corine_land_cover_2006.png" alt="Fragment from the CORINE land data base ">
- <img src="corine_land_cover_legend.png" alt="Legend for the CORINE land data base">
+ <img src="images/r_estimap_recreation_corine_land_cover_2006.png" alt="Fragment from the CORINE land data base ">
+ <img src="images/r_estimap_recreation_corine_land_cover_legend.png" alt="Legend for the CORINE land data base">
</center>
</div>
@@ -1161,7 +1161,7 @@
<p>
<center>
-<img src="potential_corine.png" alt="Example of a recreation spectrum output map
+<img src="images/r_estimap_recreation_potential_corine.png" alt="Example of a recreation spectrum output map
while using a MASK, based on a fragment from the CORINE land data base">
</center>
Deleted: grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.py 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/r.estimap.recreation.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -1,4103 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
- MODULE: r.estimap.recreation
-
- AUTHOR(S): Nikos Alexandris <nik at nikosalexandris.net>
-
- First implementation as a collection of Python scripts by
- Grazia Zulian <Grazia.Zulian at ec.europa.eu>
-
- PURPOSE: An implementation of the Ecosystem Services Mapping Tool
- (ESTIMAP). ESTIMAP is a collection of spatially explicit models
- to support mapping and modelling of ecosystem services
- at European scale.
-
- SOURCES: https://www.bts.gov/archive/publications/journal_of_transportation_and_statistics/volume_04_number_23/paper_03/index
-
- COPYRIGHT: Copyright 2018 European Union
-
- Licensed under the EUPL, Version 1.2 or – as soon they will be
- approved by the European Commission – subsequent versions of the
- EUPL (the "Licence");
-
- You may not use this work except in compliance with the Licence.
- You may obtain a copy of the Licence at:
-
- https://joinup.ec.europa.eu/collection/eupl/eupl-text-11-12
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the Licence is distributed on an
- "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- either express or implied. See the Licence for the specific
- language governing permissions and limitations under the Licence.
-
- Consult the LICENCE file for details.
-"""
-
-'''Flags'''
-
-#%Module
-#% description: Implementation of ESTIMAP to support mapping and modelling of ecosystem services (Zulian, 2014)
-#% keywords: estimap
-#% keywords: ecosystem services
-#% keywords: recreation potential
-#%End
-
-#%flag
-#% key: e
-#% description: Match computational region to extent of land use map
-#%end
-
-#%flag
-#% key: f
-#% description: Filter maps in land and natural components before computing recreation maps
-#%end
-
-#%flag
-#% key: s
-#% description: Save temporary maps for debugging
-#%end
-
-#%flag
-#% key: i
-#% description: Print out citation and other information
-#%end
-
-#%flag
-#% key: p
-#% description: Print out results (i.e. supply table), don't export to file
-#%end
-
-'''
-exclusive: at most one of the options may be given
-required: at least one of the options must be given
-requires: if the first option is given, at least one of the subsequent options must also be given
-requires_all: if the first option is given, all of the subsequent options must also be given
-excludes: if the first option is given, none of the subsequent options may be given
-collective: all or nothing; if any option is given, all must be given
-'''
-
-'''Components section'''
-
-#%option G_OPT_R_INPUT
-#% key: land
-#% type: string
-#% key_desc: name
-#% label: Input map scoring access to and suitability of land resources for recreation
-#% description: Arbitrary number of maps scoring access to and land resources suitability of land use classes to support recreation activities
-#% required : no
-#% guisection: Components
-#%end
-
-#%option G_OPT_R_INPUTS
-#% key: natural
-#% key_desc: name
-#% label: Input maps scoring access to and quality of inland natural resources
-#% description: Arbitrary number of maps scoring access to and quality of inland natural resources
-#% required : no
-#% guisection: Components
-#%end
-
-#%option G_OPT_R_INPUTS
-#% key: water
-#% key_desc: name
-#% label: Input maps scoring access to and quality of water resources
-#% description: Arbitrary number of maps scoring access to and quality of water resources such as lakes, sea, bathing waters and riparian zones
-#% required : no
-#% guisection: Components
-#%end
-
-#%option G_OPT_R_INPUTS
-#% key: urban
-#% key_desc: name
-#% description: Input maps scoring recreational value of urban surfaces
-#% required : no
-#% guisection: Components
-#%end
-
-#%option G_OPT_R_INPUTS
-#% key: infrastructure
-#% type: string
-#% key_desc: name
-#% label: Input maps scoring infrastructure to reach locations of recreation activities
-#% description: Infrastructure to reach locations of recreation activities [required to derive recreation spectrum map]
-#% required: no
-#% guisection: Components
-#%end
-
-#%option G_OPT_R_INPUTS
-#% key: recreation
-#% type: string
-#% key_desc: name
-#% label: Input maps scoring recreational facilities, amenities and services
-#% description: Recreational opportunities facilities, amenities and services [required to derive recreation spectrum map]
-#% required: no
-#% guisection: Components
-#%end
-
-'''Land'''
-
-#%option G_OPT_R_INPUT
-#% key: landuse
-#% type: string
-#% key_desc: name
-#% label: Input land features map from which to derive suitability for recreation
-#% description: Input to derive suitability of land use classes to support recreation activities. Requires scores, overrides suitability.
-#% required : no
-#% guisection: Land
-#%end
-
-#%rules
-#% exclusive: land
-#%end
-
-#%option G_OPT_F_INPUT
-#% key: suitability_scores
-#% type: string
-#% key_desc: filename
-#% label: Input recreational suitability scores for the categories of the 'landuse' map
-#% description: Scores for suitability of land to support recreation activities. Expected are rules for `r.recode` that correspond to categories of the input 'landuse' map. If the 'landuse' map is given and 'suitability_scores not provided, the module will use internal rules for the CORINE land classes.
-#% required: no
-#% guisection: Land
-#%end
-
-#%rules
-#% excludes: land, suitability_scores
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: landcover
-#% type: string
-#% key_desc: name
-#% label: Input land cover map from which to derive cover percentages within zones of high recreational value
-#% description: Input to derive percentage of land classes within zones of high recreational value.
-#% required : no
-#% guisection: Land
-#%end
-
-#%option G_OPT_F_INPUT
-#% key: land_classes
-#% type: string
-#% key_desc: filename
-#% label: Input reclassification rules for the classes of the 'landcover' map
-#% description: Expected are rules for `r.reclass` that correspond to classes of the input 'landcover' map. If 'landcover' map is given and 'land_classess' not provided, the module will use internal rules for the Urban Atlas land classes
-#% required: no
-#% guisection: Land
-#%end
-
-'''Water'''
-
-#%option G_OPT_R_INPUT
-#% key: lakes
-#% key_desc: name
-#% label: Input map of inland waters resources for which to score accessibility
-#% description: Map of inland water resources to compute proximity for, score accessibility based on a distance function
-#% required : no
-#% guisection: Water
-#%end
-
-#%option
-#% key: lakes_coefficients
-#% type: string
-#% key_desc: Coefficients
-#% label: Input distance function coefficients for the 'lakes' map
-#% description: Distance function coefficients to compute proximity: distance metric, constant, kappa, alpha and score. Refer to the manual for details.
-#% multiple: yes
-#% required: no
-#% guisection: Water
-#% answer: euclidean,1,30,0.008,1
-#%end
-
-##%rules
-##% requires: lakes, lakes_coefficients
-##%end
-
-#%option G_OPT_R_INPUT
-#% key: coastline
-#% key_desc: name
-#% label: Input sea coast map for which to compute proximity
-#% description: Input map to compute coast proximity, scored based on a distance function
-#% required : no
-#% guisection: Water
-#%end
-
-#%option
-#% key: coastline_coefficients
-#% key_desc: Coefficients
-#% label: Input distance function coefficients for the 'coastline' map
-#% description: Distance function coefficients to compute proximity: distance metric, constant, kappa, alpha and score. Refer to the manual for details.
-#% multiple: yes
-#% required: no
-#% guisection: Water
-#% answer: euclidean,1,30,0.008,1
-#%end
-
-#%rules
-#% requires: coastline, coastline_coefficients
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: coast_geomorphology
-#% key_desc: name
-#% label: Input map scoring recreation potential in coast
-#% description: Coastal geomorphology, scored as suitable to support recreation activities
-#% required : no
-#% guisection: Water
-#%end
-
-#%rules
-#% requires: coast_geomorphology, coastline
-#%end
-
-##%option
-##% key: geomorphology_coefficients
-##% key_desc: Coefficients
-##% label: Input distance function coefficients
-##% description: Distance function coefficients to compute proximity: distance metric, constant, kappa, alpha and score. Refer to the manual for details.
-##% multiple: yes
-##% required: no
-##% guisection: Water
-##% answer: euclidean,1,30,0.008,1
-##%end
-
-##%rules
-##% requires: coast_geomorphology, geomorphology_coefficients
-##%end
-
-#%option G_OPT_R_INPUT
-#% key: bathing_water
-#% key_desc: name
-#% label: Input bathing water quality map
-#% description: Bathing water quality index. The higher, the greater is the recreational value.
-#% required : no
-#% guisection: Water
-#%end
-
-#%option
-#% key: bathing_coefficients
-#% type: string
-#% key_desc: Coefficients
-#% label: Input distance function coefficients for the 'bathing_water' map
-#% description: Distance function coefficients to compute proximity to bathing waters: distance metric, constant, kappa and alpha. Refer to the manual for details.
-#% multiple: yes
-#% required: no
-#% guisection: Water
-#% answer: euclidean,1,5,0.01101
-#%end
-
-#%rules
-#% requires: bathing_water, bathing_coefficients
-#%end
-
-##%rules
-##% exclusive: lakes
-##% exclusive: coastline
-##% excludes: water, coast_geomorphology, coast_proximity, marine, lakes, lakes_proximity, bathing_water
-##%end
-
-'''Natural'''
-
-#%option G_OPT_R_INPUT
-#% key: protected
-#% key_desc: filename
-#% label: Input protected areas map
-#% description: Input map depicting natural protected areas
-#% required : no
-#% guisection: Natural
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: protected_scores
-#% type: string
-#% key_desc: rules
-#% label: Input recreational value scores for the classes of the 'protected' map
-#% description: Scores for recreational value of designated areas. Expected are rules for `r.recode` that correspond to classes of the input land use map. If the 'protected' map is given and 'protected_scores' are not provided, the module will use internal rules for the IUCN categories.
-#% required : no
-#% guisection: Anthropic
-#% answer: 11:11:0,12:12:0.6,2:2:0.8,3:3:0.6,4:4:0.6,5:5:1,6:6:0.8,7:7:0,8:8:0,9:9:0
-#%end
-
-##%rules
-##% exclusive: natural, protected
-##% exclusive: protected, natural
-###% requires: protected, protected_scores
-##%end
-
-'''Artificial areas'''
-
-#%option G_OPT_R_INPUT
-#% key: artificial
-#% key_desc: name
-#% label: Input map of artificial surfaces
-#% description: Partial input map to compute proximity to artificial areas, scored via a distance function
-#% required : no
-#% guisection: Water
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: artificial_distances
-#% type: string
-#% key_desc: rules
-#% label: Input distance classification rules
-#% description: Categories for distance to artificial surfaces. Expected are rules for `r.recode` that correspond to distance values in the 'artificial' map
-#% required : no
-#% guisection: Anthropic
-#% answer: 0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5
-#%end
-
-#%rules
-#% requires: artificial, artificial_distances
-#%end
-
-'''Roads'''
-
-#%option G_OPT_R_INPUT
-#% key: roads
-#% key_desc: name
-#% label: Input map of primary road network
-#% description: Input map to compute roads proximity, scored based on a distance function
-#% required : no
-#% guisection: Infrastructure
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: roads_distances
-##% key: roads_scores
-#% type: string
-#% key_desc: rules
-#% label: Input distance classification rules
-#% description: Categories for distance to roads. Expected are rules for `r.recode` that correspond to distance values in the roads map
-#% required : no
-#% guisection: Anthropic
-#% answer: 0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5
-#%end
-
-#%rules
-#% requires: roads, roads_distances
-#% collective: artificial, roads
-#%end
-
-'''Recreation'''
-
-#######################################################################
-# Offer input for potential?
-
-# #%option G_OPT_R_OUTPUT
-# #% key: recreation_potential
-# #% key_desc: name
-# #% description: Recreation potential map
-# #% required: no
-# #% answer: recreation_potential
-# #% guisection: Components
-# #%end
-
-#
-#######################################################################
-
-## Review the following item's "parsing rules"!
-
-##%rules
-##% excludes: infrastructure, roads
-##%end
-
-'''Devaluation'''
-
-#%option G_OPT_R_INPUTS
-#% key: devaluation
-#% key_desc: name
-#% label: Input map of devaluing elements
-#% description: Maps hindering accessibility to and degrading quality of various resources or infrastructure relating to recreation
-#% required : no
-#% guisection: Devaluation
-#%end
-
-'''MASK'''
-
-#%option G_OPT_R_INPUT
-#% key: mask
-#% key_desc: name
-#% description: A raster map to apply as a MASK
-#% required : no
-#%end
-
-'''Output'''
-
-#%option G_OPT_R_OUTPUT
-#% key: potential
-#% key_desc: name
-#% label: Output map of recreation potential
-#% description: Recreation potential map classified in 3 categories
-#% required: no
-#% guisection: Output
-#%end
-
-#%rules
-#% requires: potential, land, natural, water, landuse, protected, lakes, coastline
-#%end
-
-#%option G_OPT_R_OUTPUT
-#% key: opportunity
-#% key_desc: name
-#% label: Output intermediate map of recreation opportunity
-#% description: Intermediate step in deriving the 'spectrum' map, classified in 3 categories, meant for expert use
-#% required: no
-#% guisection: Output
-#%end
-
-#%rules
-#% requires: opportunity, infrastructure, roads
-#%end
-
-#%option G_OPT_R_OUTPUT
-#% key: spectrum
-#% key_desc: name
-#% label: Output map of recreation spectrum
-#% description: Recreation spectrum map classified by default in 9 categories
-#% required: no
-#% guisection: Output
-#%end
-
-#%rules
-#% requires: spectrum, infrastructure, roads
-##% requires: spectrum, landcover
-#% required: land, landcover, landuse
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: spectrum_distances
-#% type: string
-#% key_desc: rules
-#% label: Input distance classification rules for the 'spectrum' map
-#% description: Classes for distance to areas of high recreational spectrum. Expected are rules for `r.recode` that correspond to classes of the input spectrum of recreation use map.
-#% required : no
-#% guisection: Output
-#% answer: 0:1000:1,1000:2000:2,2000:3000:3,3000:4000:4,4000:*:5
-#%end
-
-'''Required for Cumulative Opportunity Model'''
-
-#%option G_OPT_R_INPUT
-#% key: base
-#% key_desc: name
-#% description: Input base map for zonal statistics
-#% required : no
-#%end
-
-#%option G_OPT_V_INPUT
-#% key: base_vector
-#% key_desc: name
-#% description: Input base vector map for zonal statistics
-#% required : no
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: aggregation
-#% key_desc: name
-#% description: Input map of regions over which to aggregate the actual flow
-#% required : no
-#%end
-
-#%option G_OPT_R_INPUT
-#% key: population
-#% key_desc: name
-#% description: Input map of population density
-#% required : no
-#%end
-
-#%option G_OPT_R_OUTPUT
-#% key: demand
-#% type: string
-#% key_desc: name
-#% label: Output map of demand distribution
-#% description: Demand distribution output map: population density per Local Administrative Unit and areas of high recreational value
-#% required : no
-#% guisection: Output
-#%end
-
-#%option G_OPT_R_OUTPUT
-#% key: unmet
-#% type: string
-#% key_desc: name
-#% label: Output map of unmet demand distribution
-#% description: Unmet demand distribution output map: population density per Local Administrative Unit and areas of high recreational value
-#% required : no
-#% guisection: Output
-#%end
-
-#%rules
-#% requires_all: demand, population, base
-#% requires: demand, infrastructure, artificial, roads
-#% requires: unmet, demand
-#%end
-
-#%option G_OPT_R_OUTPUT
-#% key: flow
-#% type: string
-#% key_desc: name
-#% label: Output map of flow
-#% description: Flow output map: population (per Local Administrative Unit) near areas of high recreational value
-#% required : no
-#% guisection: Output
-#%end
-
-#%rules
-#% requires_all: flow, population, base
-#% requires: flow, infrastructure, artificial, roads
-#%end
-
-#%option G_OPT_F_OUTPUT
-#% key: supply
-#% key_desc: prefix
-#% type: string
-#% label: Output prefix for the file name of the supply table CSV
-#% description: Supply table CSV output file names will get this prefix
-#% multiple: no
-#% required: no
-#% guisection: Output
-#%end
-
-#%option G_OPT_F_OUTPUT
-#% key: use
-#% key_desc: prefix
-#% type: string
-#% label: Output prefix for the file name of the supply table CSV
-#% description: Supply table CSV output file names will get this prefix
-#% multiple: no
-#% required: no
-#% guisection: Output
-#%end
-
-#%rules
-#% requires: opportunity, spectrum, demand, flow, supply
-#% required: potential, spectrum, demand, flow, supply, use
-#%end
-
-#%rules
-#% requires: supply, land, natural, water, landuse, protected, lakes, coastline
-#% requires_all: supply, population
-#% requires_all: supply, landcover, land_classes
-#% requires: supply, base, base_vector, aggregation
-#% requires: supply, landcover, landuse
-#% requires_all: use, population
-#% requires: use, base, base_vector, aggregation
-#% requires: use, landcover, landuse
-#%end
-
-'''Various'''
-
-#%option
-#% key: metric
-#% key_desc: Metric
-#% label: Distance metric to areas of highest recreation opportunity spectrum
-#% description: Distance metric to areas of highest recreation opportunity spectrum
-#% multiple: yes
-#% options: euclidean,squared,maximum,manhattan,geodesic
-#% required: no
-#% guisection: Output
-#% answer: euclidean
-#%end
-
-#%option
-#% key: units
-#% key_desc: Units
-#% label: Units to report
-#% description: Units to report the demand distribution
-#% multiple: yes
-#% options: mi,me,k,a,h,c,p
-#% required: no
-#% guisection: Output
-#% answer: k
-#%end
-
-#%option
-#% key: timestamp
-#% type: string
-#% label: Timestamp
-#% description: Timestamp for the recreation potential raster map
-#% required: no
-#%end
-
-# required librairies
-
-import os, sys, subprocess
-import datetime, time
-import csv
-import math
-# import heapq
-
-'''Fake a file-like object from an in-script hardcoded string?'''
-# import StringIO
-# from cStringIO import StringIO
-
-import atexit
-import grass.script as grass
-from grass.exceptions import CalledModuleError
-from grass.pygrass.modules.shortcuts import general as g
-from grass.pygrass.modules.shortcuts import raster as r
-from grass.pygrass.modules.shortcuts import vector as v
-
-if "GISBASE" not in os.environ:
- g.message(_("You must be in GRASS GIS to run this program."))
- sys.exit(1)
-
-# from scoring_schemes import corine
-
-# globals
-
-global grass_render_directory
-grass_render_directory = "/geo/grassdb/render"
-
-global equation, citation, spacy_plus
-citation_recreation_potential='Zulian (2014)'
-spacy_plus = ' + '
-equation = "{result} = {expression}" # basic equation for mapcalc
-
-global THRESHHOLD_ZERO, THRESHHOLD_0001, THRESHHOLD_0003
-THRESHHOLD_ZERO = 0
-THRESHHOLD_0001 = 0.0001
-
-global CSV_EXTENSION, COMMA, EUCLIDEAN, NEIGHBORHOOD_SIZE, NEIGHBORHOOD_METHOD
-CSV_EXTENSION = '.csv'
-COMMA='comma'
-EUCLIDEAN='euclidean'
-# units='k'
-NEIGHBORHOOD_SIZE = 11 # this and below, required for neighborhood_function
-NEIGHBORHOOD_METHOD = 'mode'
-
-WATER_PROXIMITY_CONSTANT = 1
-WATER_PROXIMITY_KAPPA = 30
-WATER_PROXIMITY_ALPHA = 0.008
-WATER_PROXIMITY_SCORE = 1
-BATHING_WATER_PROXIMITY_CONSTANT = 1
-BATHING_WATER_PROXIMITY_KAPPA = 5
-BATHING_WATER_PROXIMITY_ALPHA = 0.1101
-
-SUITABILITY_SCORES='''1:1:0:0
-2:2:0.1:0.1
-3:9:0:0
-10:10:1:1
-11:11:0.1:0.1
-12:13:0.3:0.3
-14:14:0.4:0.4
-15:17:0.5:0.5
-18:18:0.6:0.6
-19:20:0.3:0.3
-21:22:0.6:0.6
-23:23:1:1
-24:24:0.8:0.8
-25:25:1:1
-26:29:0.8:0.8
-30:30:1:1
-31:31:0.8:0.8
-32:32:0.7:0.7
-33:33:0:0
-34:34:0.8:0.8
-35:35:1:1
-36:36:0.8:0.8
-37:37:1:1
-38:38:0.8:0.8
-39:39:1:1
-40:42:1:1
-43:43:0.8:0.8
-44:44:1:1
-45:45:0.3:0.3'''
-
-SUITABILITY_SCORES_LABELS='''1 thru 1 = 1 0
-2 thru 2 = 2 0.1
-3 thru 9 = 9 0
-10 thru 10 = 10 1
-11 thru 11 = 11 0.1
-12 thru 13 = 13 0.3
-14 thru 14 = 14 0.4
-15 thru 17 = 17 0.5
-18 thru 18 = 18 0.6
-19 thru 20 = 20 0.3
-21 thru 22 = 22 0.6
-23 thru 23 = 23 1
-24 thru 24 = 24 0.8
-25 thru 25 = 25 1
-26 thru 29 = 29 0.8
-30 thru 30 = 30 1
-31 thru 31 = 31 0.8
-32 thru 32 = 32 0.7
-33 thru 33 = 33 0
-34 thru 34 = 34 0.8
-35 thru 35 = 35 1
-36 thru 36 = 36 0.8
-37 thru 37 = 37 1
-38 thru 38 = 38 0.8
-39 thru 39 = 39 1
-40 thru 42 = 42 1
-43 thru 43 = 43 0.8
-44 thru 44 = 44 1
-45 thru 45 = 45 0.3'''
-
-URBAN_ATLAS_CATEGORIES = '''11100
-11200
-12100
-12200
-12300
-12400
-13100
-13200
-13300
-14100
-14200
-21100
-21200
-21300
-22100
-22200
-22300
-23100
-24100
-24200
-24300
-24400
-31100
-31200
-31300
-32100
-32200
-32300
-32400
-33100
-33200
-33300
-33400
-33500
-41100
-41200
-42100
-42200
-42300
-'''
-
-URBAN_ATLAS_TO_MAES_NOMENCLATURE='''
-11100 = 1 Urban
-11210 = 1 Urban
-11220 = 1 Urban
-11230 = 1 Urban
-11240 = 1 Urban
-11300 = 1 Urban
-12100 = 1 Urban
-12210 = 1 Urban
-12220 = 1 Urban
-12230 = 1 Urban
-12300 = 1 Urban
-12400 = 1 Urban
-13100 = 1 Urban
-13300 = 1 Urban
-13400 = 1 Urban
-14100 = 1 Urban
-14200 = 1 Urban
-21000 = 2 Cropland
-22000 = 2 Cropland
-23000 = 2 Cropland
-25400 = 2 Cropland
-31000 = 3 Woodland and forest
-32000 = 3 Woodland and forest
-33000 = 3 Woodland and forest
-40000 = 4 Grassland
-50000 = 5 Heathland and shrub
-'''
-
-RECREATION_POTENTIAL_CATEGORIES = '''0.0:0.2:1
-0.2:0.4:2
-0.4:*:3'''
-#artificial_distance_categories=
-#'0:500:1,500.000001:1000:2,1000.000001:5000:3,5000.000001:10000:4,10000.00001:*:5'
-RECREATION_OPPORTUNITY_CATEGORIES = RECREATION_POTENTIAL_CATEGORIES
-
-#
-## FIXME -- No hardcodings please.
-#
-
-POTENTIAL_CATEGORY_LABELS = '''1:Low
-2:Moderate
-3:High
-'''
-
-OPPORTUNITY_CATEGORY_LABELS = '''1:Far
-2:Midrange
-3:Near
-'''
-
-SPECTRUM_CATEGORY_LABELS = '''1:Low provision (far)
-2:Low provision (midrange)
-3:Low provision (near)
-4:Moderate provision (far)
-5:Moderate provision (midrange)
-6:Moderate provision (near)
-7:High provision (far)
-8:High provision (midrange)
-9:High provision (near)
-'''
-
-SPECTRUM_DISTANCE_CATEGORY_LABELS = '''1:0 to 1 km
-2:1 to 2 km
-3:2 to 3 km
-4:3 to 4 km
-5:>4 km
-'''
-
-#
-## FIXME -- No hardcodings please.
-#
-
-HIGHEST_RECREATION_CATEGORY = 9
-
-SCORE_COLORS = """ # http://colorbrewer2.org/?type=diverging&scheme=RdYlGn&n=11
-0.0% 165:0:38
-10.0% 215:48:39
-20.0% 244:109:67
-30.0% 253:174:97
-40.0% 254:224:139
-50.0% 255:255:191
-60.0% 217:239:139
-70.0% 166:217:106
-80.0% 102:189:99
-90.0% 26:152:80
-100.0% 0:104:55"""
-
-POTENTIAL_COLORS = """ # Cubehelix color table generated using:
-# r.colors.cubehelix -dn ncolors=3 map=recreation_potential nrotations=0.33 gamma=1.5 hue=0.9 dark=0.3 output=recreation_potential.colors
-0.000% 55:29:66
-33.333% 55:29:66
-33.333% 157:85:132
-66.667% 157:85:132
-66.667% 235:184:193
-100.000% 235:184:193"""
-
-OPPORTUNITY_COLORS = """# Cubehelix color table generated using:
-# r.colors.cubehelix -dn ncolors=3 map=recreation_potential nrotations=0.33 gamma=1.5 hue=0.9 dark=0.3 output=recreation_potential.colors
-0.000% 55:29:66
-33.333% 55:29:66
-33.333% 157:85:132
-66.667% 157:85:132
-66.667% 235:184:193
-100.000% 235:184:193"""
-
-SPECTRUM_COLORS = """# Cubehelix color table generated using:
-# r.colors.cubehelix -dn ncolors=9 map=recreation_spectrum nrotations=0.33 gamma=1.5 hue=0.9 dark=0.3 output=recreation_spectrum.colors
-0.000% 55:29:66
-11.111% 55:29:66
-11.111% 79:40:85
-22.222% 79:40:85
-22.222% 104:52:102
-33.333% 104:52:102
-33.333% 131:67:118
-44.444% 131:67:118
-44.444% 157:85:132
-55.556% 157:85:132
-55.556% 180:104:145
-66.667% 180:104:145
-66.667% 202:128:159
-77.778% 202:128:159
-77.778% 221:156:175
-88.889% 221:156:175
-88.889% 235:184:193
-100.000% 235:184:193"""
-
-MOBILITY_CONSTANT = 1
-MOBILITY_COEFFICIENTS = { 0 : (0.02350, 0.00102),
- 1 : (0.02651, 0.00109),
- 2 : (0.05120, 0.00098),
- 3 : (0.10700, 0.00067),
- 4 : (0.06930, 0.00057)}
-MOBILITY_SCORE = 52
-MOBILITY_COLORS = 'wave'
-LANDCOVER_FRACTIONS_COLOR='wave'
-
-METHODS='sum'
-
-# helper functions
-
-def run(cmd, **kwargs):
- """Pass required arguments to grass commands (?)"""
- grass.run_command(cmd, quiet=True, **kwargs)
-
-def tmp_map_name(**kwargs):
- """Return a temporary map name, for example:
-
- Parameters
- ----------
- name :
- Name of input raster map
-
- Returns
- -------
- temporary_filename :
- A temporary file name for the input raster map
-
- Examples
- --------
- >>> tmp_map_name(potential)
- tmp.SomeTemporaryString.potential
- """
- temporary_absolute_filename = grass.tempfile()
- temporary_filename = "tmp." + grass.basename(temporary_absolute_filename)
- if 'name' in kwargs:
- name = kwargs.get('name')
- temporary_filename = temporary_filename + '.' + str(name)
- return temporary_filename
-
-def cleanup():
- """Clean up temporary maps"""
-
- if rename_at_exit:
- if demand in rename_at_exit:
- g.rename(raster=(demand_copy,demand))
-
- # get list of temporary maps
- temporary_raster_maps = grass.list_strings(type='raster',
- pattern='tmp.{pid}*'.format(pid=os.getpid()))
-
- # inform
- if any([temporary_raster_maps, remove_at_exit,
- remove_normal_files_at_exit]):
- g.message("Removing temporary files")
-
- # remove temporary maps
- if temporary_raster_maps:
- g.remove(flags='f',
- type="raster",
- pattern='tmp.{pid}*'.format(pid=os.getpid()),
- quiet=True)
-
- # remove raster and vector maps in handcrafted list
- if remove_at_exit:
- g.remove(flags='f',
- type=('raster','vector'),
- name=','.join(remove_at_exit),
- quiet=True)
-
- # remove normal files at OS level
- if remove_normal_files_at_exit:
- for item in remove_normal_files_at_exit:
- os.unlink(item)
-
- # # remove MASK ? FIXME
- # if grass.find_file(name='MASK', element='cell')['file']:
- # r.mask(flags='r', verbose=True)
-
-def string_to_file(string, **kwargs):
- """Split series of strings separated by comma in lines and write as an
- ASCII file
-
- Parameters
- ----------
- string :
- A string where commas will be replaced by a newline
-
- kwargs :
- Optional key-word argument 'name'
-
- Returns
- -------
- filename :
- Name of the ASCII file into where the transformed string is written
-
- Examples
- --------
-
- """
- string = string.split(',')
- string = '\n'.join(string)
- # string = string.splitlines()
-
- msg = "String split in lines: {s}".format(s=string)
- grass.debug(_(msg))
-
- if 'name' in kwargs:
- name = kwargs.get('name')
- filename = tmp_map_name(name=name)
-
- # # Use a file-like object instead?
- # import tempfile
- # ascii_file = tempfile.TemporaryFile()
-
- try:
- ascii_file = open(filename, "w")
- ascii_file.writelines(string)
- # ascii_file.seek(0) # in case of a file-like object
-
- # if DEBUG, then do:
- # for line in ascii_file:
- # grass.debug(_(line.rstrip()))
-
- except IOError as error:
- print ("IOError :", error)
- return
-
- finally:
- ascii_file.close()
- return filename # how would that work with a file-like object?
- # Will be removed right after `.close()` -- How to possibly re-use it
- # outside the function?
- # Wrap complete main() in a `try` statement?
-
-def save_map(mapname):
- """Helper function to save some in-between maps, assisting in debugging
-
- Parameters
- ----------
- mapname :
- ...
-
- Returns
- -------
- newname :
- New name for the input raster map
-
- Examples
- --------
- """
- # run('r.info', map=mapname, flags='r')
- # run('g.copy', raster=(mapname, 'DebuggingMap'))
-
- #
- # Needs re-design! FIXME
- #
-
- newname = mapname
- if save_temporary_maps:
- newname = 'output_' + mapname
- run('g.rename', raster=(mapname, newname))
- return newname
-
-def merge_two_dictionaries(a, b):
- """Merge two dictionaries in via shallow copy.
- Source: https://stackoverflow.com/a/26853961/1172302"""
- merged_dictionary = a.copy()
- merged_dictionary.update(b)
- return merged_dictionary
-
-def dictionary_to_csv(filename, dictionary):
- """Write a Python dictionary as CSV named 'filename'
-
- Parameters
- ----------
- filename :
- Name for output file
-
- dictionary :
- Name of input Python dictionary to write to 'filename'
-
- Returns
- -------
- This function does not return anything
-
- Examples
- --------
- """
- f = open(filename, "wb")
- w = csv.writer(f)
-
- # write a header
- w.writerow(['category', 'label', 'value'])
-
- # terminology: from 'base' and 'cover' maps
- for base_key, value in dictionary.items():
- base_category = base_key[0]
- base_label = base_key[1] # .decode('utf-8')
- if value is None or value == '':
- continue
- w.writerow([base_category,
- base_label,
- value])
-
- f.close()
-
-def nested_dictionary_to_csv(filename, dictionary):
- """Write out a nested Python dictionary as CSV named 'filename'
-
- Parameters
- ----------
- filename :
- Name for output file
-
- dictionary :
- Name of the input Python dictionary
- """
- f = open(filename, "wb")
- w = csv.writer(f)
-
- # write a header
- w.writerow(['base',
- 'base_label',
- 'cover',
- 'cover_label',
- 'area',
- 'count',
- 'percents'])
-
- # terminology: from 'base' and 'cover' maps
- for base_key, inner_dictionary in dictionary.items():
- base_category = base_key[0]
- base_label = base_key[1] # .decode('utf-8')
-
- for cover_category, inner_value in inner_dictionary.items():
- if inner_value is None or inner_value == '':
- continue
- cover_label = inner_value[0]
- area = inner_value[1]
- pixel_count = inner_value[2]
- pixel_percentage = inner_value[3]
- w.writerow([base_category,
- base_label,
- cover_category,
- cover_label,
- area,
- pixel_count,
- pixel_percentage])
-
- f.close()
-
-def append_map_to_component(raster, component_name, component_list):
- """Appends raster map to given list of components
-
- Parameters
- ----------
- raster :
- Input raster map name
-
- component_name :
- Name of the component to add the raster map to
-
- component_list :
- List of raster maps to add the input 'raster' map
-
- Returns
- -------
-
- Examples
- --------
- ...
- """
- component_list.append(raster)
- msg = "Map {name} included in the '{component}' component"
- msg = msg.format(name=raster, component=component_name)
- grass.verbose(_(msg))
-
-def get_univariate_statistics(raster):
- """
- Return and print basic univariate statistics of the input raster map
-
- Parameters
- ----------
- raster :
- Name of input raster map
-
- Returns
- -------
- univariate :
- Univariate statistics min, mean, max and variance of the input raster
- map
-
- Example
- -------
- ...
- """
- univariate = grass.parse_command('r.univar', flags='g', map=raster)
- if info:
- minimum = univariate['min']
- mean = univariate['mean']
- maximum = univariate['max']
- variance = univariate['variance']
- msg = "min {mn} | mean {avg} | max {mx} | variance {v}"
- msg = msg.format(mn=minimum, avg=mean, mx=maximum, v=variance)
- grass.verbose(_(msg))
- return univariate
-
-def recode_map(raster, rules, colors, output):
- """Scores a raster map based on a set of category recoding rules.
-
- This is a wrapper around r.recode
-
- Parameters
- ----------
- raster :
- Name of input raster map
-
- rules :
- Rules for r.recode
-
- colors :
- Color rules for r.colors
-
- output :
- Name of output raster map
-
- Returns
- -------
- Does not return any value
-
- Examples
- --------
- ...
- """
- msg = "Setting NULL cells in {name} map to 0"
- msg = msg.format(name=raster)
- grass.debug(_(msg))
-
- # ------------------------------------------
- r.null(map=raster, null=0) # Set NULLs to 0
- msg = "To Do: confirm if setting the '{raster}' map's NULL cells to 0 is right"
- msg = msg.format(raster=raster)
- grass.debug(_(msg))
- # Is this right?
- # ------------------------------------------
-
- r.recode(input=raster,
- rules=rules,
- output=output)
-
- r.colors(map=output,
- rules='-',
- stdin=SCORE_COLORS,
- quiet=True)
-
- # if save_temporary_maps:
- # tmp_output = save_map(output)
-
- grass.verbose(_("Scored map {name}:".format(name=raster)))
-
-def float_to_integer(double):
- """Converts an FCELL or DCELL raster map into a CELL raster map
-
- Parameters
- ----------
- double :
- An 'FCELL' or 'DCELL' type raster map
-
- Returns
- -------
- This function does not return any value
-
- Examples
- --------
- ..
- """
- expression = 'int({double})'
- expression = expression.format(double=double)
- equation=equation.format(result=double, expression=expression)
- r.mapcalc(equation)
-
-def get_coefficients(coefficients_string):
- """Returns coefficients from an input coefficients_string
-
- Parameters
- ----------
- coefficients_string:
- One string which lists a metric and coefficients separated by comma
- without spaces
-
- Returns
- -------
- metric:
- Metric to use an input option to the `r.grow.distance` module
-
- constant:
- A constant value for the 'attractiveness' function
-
- kappa:
- A Kappa coefficients for the 'attractiveness' function
-
- alpha:
- An alpha coefficient for the 'attractiveness' function
-
- score
- A score value to multiply by the generic 'attractiveness' function
-
- Examples
- --------
- ...
- """
- coefficients = coefficients_string.split(',')
- msg = "Distance function coefficients: "
- metric = coefficients[0]
- msg += "Metric='{metric}', ".format(metric=metric)
- constant = coefficients[1]
- msg += "Constant='{constant}', ".format(constant=constant)
- kappa = coefficients[2]
- msg += "Kappa='{Kappa}', ".format(Kappa=kappa)
- alpha = coefficients[3]
- msg += "Alpha='{alpha}', ".format(alpha=alpha)
- try:
- if coefficients[4]:
- score = coefficients[4]
- msg += "Score='{score}'".format(score=score)
- grass.verbose(_(msg))
- return metric, constant, kappa, alpha, score
- except IndexError:
- grass.verbose(_("Score not provided"))
-
- grass.verbose(_(msg))
- return metric, constant, kappa, alpha
-
-def build_distance_function(constant, kappa, alpha, variable, **kwargs):
- """
- Build a valid `r.mapcalc` expression based on the following "space-time"
- function:
-
- ( {constant} + {kappa} ) / ( {kappa} + exp({alpha} * {variable}) )
-
- Parameters
- ----------
- constant :
- 1
-
- kappa :
- A constant named 'K'
-
- alpha :
- A constant named 'a'
-
- variable :
- The main input variable: for 'attractiveness' it is 'distance', for
- 'flow' it is 'population'
-
- kwargs :
- More keyword arguments such as: 'score', 'suitability'
-
- score :
- If 'score' is given, it used as a multiplication factor to the base
- equation.
-
- suitability :
- If 'suitability' is given, it is used as a multiplication factor to
- the base equation.
-
- Returns
- -------
- function:
- A valid `r.mapcalc` expression
-
- Examples
- --------
- ..
- """
- numerator = "{constant} + {kappa}"
- numerator = numerator.format(constant = constant, kappa = kappa)
-
- denominator = "{kappa} + exp({alpha} * {variable})"
- denominator = denominator.format(
- kappa = kappa,
- alpha = alpha,
- variable = variable) # variable "formatted" by a caller function
-
- function = " ( {numerator} ) / ( {denominator} )"
- function = function.format(
- numerator = numerator,
- denominator = denominator)
- grass.debug("Function without score: {f}".format(f=function))
-
- if 'score' in kwargs:
- score = kwargs.get('score')
- function += " * {score}" # need for float()?
- function = function.format(score=score)
- grass.debug(_("Function after adding 'score': {f}".format(f=function)))
-
- # Integrate land suitability scores in the distance function ? ------------
-
- # if 'suitability' in kwargs:
- # suitability = kwargs.get('suitability')
- # function += " * {suitability}" # FIXME : Confirm Correctness
- # function = function.format(suitability=suitability)
- # msg = "Function after adding 'suitability': {f}".format(f=function)
- # grass.debug(_(msg))
-
- # -------------------------------------------------------------------------
-
- del(numerator)
- del(denominator)
-
- return function
-
-def compute_attractiveness(raster, metric, constant, kappa, alpha, **kwargs):
- """
- Compute a raster map whose values follow an (euclidean) distance function
- ( {constant} + {kappa} ) / ( {kappa} + exp({alpha} * {distance}) ), where:
-
- Source: http://publications.jrc.ec.europa.eu/repository/bitstream/JRC87585/lb-na-26474-en-n.pd
-
- Parameters
- ----------
- constant : 1
-
- kappa :
- A constant named 'K'
-
- alpha :
- A constant named 'a'
-
- distance :
- A distance map based on the input raster
-
- score :
- A score term to multiply the distance function
-
- kwargs :
- Optional keyword arguments, such as 'mask' and 'output'. The 'mask'
- is inverted to selectively exclude non-NULL cells from distance
- related computations. The 'output' is used to name the computed
- proximity map.
-
- Returns
- -------
- tmp_output :
- A temporary proximity to features raster map.
-
- Examples
- --------
- ...
-
- """
- distance_terms = [str(raster),
- str(metric),
- 'distance',
- str(constant),
- str(kappa),
- str(alpha)]
-
- if 'score' in kwargs:
- score = kwargs.get('score')
- grass.debug(_("Score for attractiveness equation: {s}".format(s=score)))
- distance_terms += str(score)
-
- # tmp_distance = tmp_map_name('_'.join(distance_terms))
- tmp_distance = tmp_map_name(name='_'.join([raster, metric]))
- r.grow_distance(input=raster,
- distance=tmp_distance,
- metric=metric,
- quiet=True,
- overwrite=True)
-
- if 'mask' in kwargs:
- mask = kwargs.get('mask')
- # global mask
- msg = "Inverted masking to exclude non-NULL cells "
- msg += "from distance related computations based on '{mask}'"
- msg = msg.format(mask=mask)
- grass.verbose(_(msg))
- r.mask(raster=mask, flags='i', overwrite=True, quiet=True)
-
- # FIXME: use a parameters dictionary, avoid conditionals
- if 'score' in kwargs:
- distance_function = build_distance_function(
- constant=constant,
- kappa=kappa,
- alpha=alpha,
- variable=tmp_distance,
- score=score)
-
- # FIXME: use a parameters dictionary, avoid conditionals
- if not 'score' in kwargs:
- distance_function = build_distance_function(
- constant=constant,
- kappa=kappa,
- alpha=alpha,
- variable=tmp_distance)
-
- # temporary maps will be removed
- if 'output_name' in kwargs:
- tmp_distance_map = tmp_map_name(name=kwargs.get('output_name'))
- else:
- basename = '_'.join([raster, 'attractiveness'])
- tmp_distance_map = tmp_map_name(name=basename)
-
- distance_function = equation.format(result=tmp_distance_map,
- expression=distance_function)
-
- msg = "Distance function: {f}".format(f=distance_function)
- grass.verbose(_(msg))
- del(msg)
-
- grass.mapcalc(distance_function, overwrite=True)
-
- r.null(map=tmp_distance_map, null=0) # Set NULLs to 0
-
- compress_status = grass.read_command(
- 'r.compress',
- flags='g',
- map=tmp_distance_map)
- grass.verbose(_("Compress status: {s}".format(s=compress_status)))
-
- del(distance_function)
-
- tmp_output = save_map(tmp_distance_map)
- return tmp_distance_map
-
-def neighborhood_function(raster, method, size, distance_map):
- """
- Parameters
- ----------
- raster :
- Name of input raster map for which to apply r.neighbors
-
- method :
- Method for r.neighbors
-
- size :
- Size for r.neighbors
-
- distance :
- A distance map
-
- Returns
- -------
- filtered_output :
- A neighborhood filtered raster map
-
- Examples
- --------
- ...
- """
- r.null(map=raster, null=0) # Set NULLs to 0
-
- neighborhood_output = distance_map + '_' + method
- msg = "Neighborhood operator '{method}' and size '{size}' for map '{name}'"
- msg = msg.format(method=method, size=size, name=neighborhood_output)
- grass.verbose(_(msg))
-
- r.neighbors(input=raster,
- output=neighborhood_output,
- method=method,
- size=size,
- overwrite=True)
-
- scoring_function = "{neighborhood} * {distance}"
- scoring_function = scoring_function.format(
- neighborhood=neighborhood_output,
- distance=distance_map)
-
- filtered_output = distance_map
- filtered_output += '_' + method + '_' + str(size)
-
- neighborhood_function = equation.format(result=filtered_output,
- expression=scoring_function)
- # ---------------------------------------------------------------
- grass.debug(_("Expression: {e}".format(e=neighborhood_function)))
- # ---------------------------------------------------------------
- grass.mapcalc(neighborhood_function, overwrite=True)
-
- # tmp_distance_map = filtered_output
-
- # r.compress(distance_map, flags='g')
-
- del(method)
- del(size)
- del(neighborhood_output)
- del(scoring_function)
- # del(filtered_output)
-
- return filtered_output
-
-def smooth_map(raster, method, size):
- """
- Parameters
- ----------
- raster :
-
- method :
-
- size :
-
- Returns
- -------
-
- Examples
- --------
- """
- r.neighbors(
- input=raster,
- output=raster,
- method=method,
- size=size,
- overwrite=True,
- quiet=True)
-
-def smooth_component(component, method, size):
- """
- component:
-
- method:
-
- size:
- """
- try:
- if len(component) > 1:
- for item in component:
- smooth_map(item,
- method=method,
- size=size)
- else:
- smooth_map(component[0],
- method=method,
- size=size)
-
- except IndexError:
- grass.verbose(_("Index Error")) # FIXME: some useful message... ?
-
-def zerofy_small_values(raster, threshhold, output_name):
- """
- Set the input raster map cell values to 0 if they are smaller than the
- given threshhold
-
- Parameters
- ----------
- raster :
- Name of input raster map
-
- threshhold :
- Reference for which to flatten smaller raster pixel values to zero
-
- output_name :
- Name of output raster map
-
- Returns
- -------
- Does not return any value
-
- Examples
- --------
- ...
- """
- rounding='if({raster} < {threshhold}, 0, {raster})'
- rounding = rounding.format(raster=raster, threshhold=threshhold)
- rounding_equation = equation.format(result=output_name, expression=rounding)
- grass.mapcalc(rounding_equation, overwrite=True)
-
-def normalize_map (raster, output_name):
- """
- Normalize all raster map cells by subtracting the raster map's minimum and
- dividing by the range.
-
- Parameters
- ----------
- raster :
- Name of input raster map
-
- output_name :
- Name of output raster map
-
- Returns
- -------
-
- Examples
- --------
- ...
- """
- # grass.debug(_("Input to normalize: {name}".format(name=raster)))
- # grass.debug(_("Ouput: {name}".format(name=output_name)))
-
- finding = grass.find_file(name=raster, element='cell')
-
- if not finding['file']:
- grass.fatal("Raster map {name} not found".format(name=raster))
- # else:
- # grass.debug("Raster map {name} found".format(name=raster))
-
- # univar_string = grass.read_command('r.univar', flags='g', map=raster)
- # univar_string = univar_string.replace('\n', '| ').replace('\r', '| ')
- # msg = "Univariate statistics: {us}".format(us=univar_string)
-
- minimum = grass.raster_info(raster)['min']
- grass.debug(_("Minimum: {m}".format(m=minimum)))
-
- maximum = grass.raster_info(raster)['max']
- grass.debug(_("Maximum: {m}".format(m=maximum)))
-
- if minimum is None or maximum is None:
- msg = "Minimum and maximum values of the <{raster}> map are 'None'. "
- msg += "The {raster} map may be empty "
- msg += "OR the MASK opacifies all non-NULL cells."
- grass.fatal(_(msg.format(raster=raster)))
-
- normalisation = 'float(({raster} - {minimum}) / ({maximum} - {minimum}))'
- normalisation = normalisation.format(raster=raster, minimum=minimum,
- maximum=maximum)
-
- # Maybe this can go in the parent function? 'raster' names are too long!
- if info:
- msg = "Normalization expression: "
- msg += normalisation
- grass.verbose(_(msg))
- #
-
- normalisation_equation = equation.format(result=output_name,
- expression=normalisation)
- grass.mapcalc(normalisation_equation, overwrite=True)
-
- get_univariate_statistics(output_name)
-
- del(minimum)
- del(maximum)
- del(normalisation)
- del(normalisation_equation)
-
-def zerofy_and_normalise_component(components, threshhold, output_name):
- """
- Sums up all maps listed in the given "components" object and derives a
- normalised output.
-
- To Do:
-
- * Improve `threshold` handling. What if threshholding is not desired? How
- to skip performing it?
-
- Parameters
- ----------
- components :
- Input list of raster maps (components)
-
- threshhold :
- Reference value for which to flatten all smaller raster pixel values to
- zero
-
- output_name :
- Name of output raster map
-
- Returns
- -------
- ...
-
- Examples
- --------
- ...
- """
- msg = "Normalising sum of: "
- msg += ','.join(components)
- grass.debug(_(msg))
- grass.verbose(_(msg))
-
- if len(components) > 1:
-
- # prepare string for mapcalc expression
- components = [ name.split('@')[0] for name in components ]
- components_string = spacy_plus.join(components)
- components_string = components_string.replace(' ', '')
- components_string = components_string.replace('+', '_')
-
- # temporary map names
- tmp_intermediate = tmp_map_name(name=components_string)
- tmp_output = tmp_map_name(name=components_string)
-
- # build mapcalc expression
- component_expression = spacy_plus.join(components)
- component_equation = equation.format(result=tmp_intermediate,
- expression=component_expression)
-
- grass.mapcalc(component_equation, overwrite=True)
-
- del(components_string)
- del(component_expression)
- del(component_equation)
-
- elif len(components) == 1:
- # temporary map names, if components contains one element
- tmp_intermediate = components[0]
- tmp_output = tmp_map_name(name=tmp_intermediate)
-
- if threshhold > THRESHHOLD_ZERO:
- msg = "Setting values < {threshhold} in '{raster}' to zero"
- grass.verbose(msg.format(threshhold=threshhold, raster=tmp_intermediate))
- zerofy_small_values(tmp_intermediate, threshhold, tmp_output)
-
- else:
- tmp_output = tmp_intermediate
-
- # grass.verbose(_("Temporary map name: {name}".format(name=tmp_output)))
- grass.debug(_("Output map name: {name}".format(name=output_name)))
- # r.info(map=tmp_output, flags='gre')
-
- ### FIXME
-
- normalize_map(tmp_output, output_name)
-
- ### FIXME
-
- del(tmp_intermediate)
- del(tmp_output)
- del(output_name)
-
-def classify_recreation_component(component, rules, output_name):
- """
- Recode an input recreation component based on given rules
-
- To Do:
-
- - Potentially, test range of input recreation component, i.e. ranging in
- [0,1]
-
- Parameters
- ----------
- component :
- Name of input raster map
-
- rules :
- Rules for r.recode
-
- output_name :
- Name for output raster map
-
- Returns
- -------
- Does not return any value
-
- Examples
- --------
- ...
-
- """
- r.recode(input=component,
- rules='-',
- stdin=rules,
- output=output_name)
-
-def compute_artificial_proximity(raster, distance_categories, **kwargs):
- """
- Compute proximity to artificial surfaces
-
- 1. Distance to features
- 2. Classify distances
-
- Parameters
- ----------
- raster :
- Name of input raster map
-
- distance_categories :
- Category rules to recode the input distance map
-
- kwargs :
- Optional arguments: output_file
-
- Returns
- -------
- tmp_output :
- Name of the temporary output map for internal, in-script, re-use
-
- Examples
- --------
- ...
- """
- artificial_distances = tmp_map_name(name=raster)
-
- grass.run_command("r.grow.distance",
- input = raster,
- distance = artificial_distances,
- metric = EUCLIDEAN,
- quiet = True,
- overwrite = True)
-
- if 'output_name' in kwargs:
- # temporary maps will be removed
- tmp_output = tmp_map_name(name=kwargs.get('output_name'))
- grass.debug(_("Pre-defined output map name {name}".format(name=tmp_output)))
-
- else:
- tmp_output = tmp_map_name(name='artificial_proximity')
- grass.debug(_("Hardcoded temporary map name {name}".format(name=tmp_output)))
-
- msg = "Computing proximity to '{mapname}'"
- msg = msg.format(mapname=raster)
- grass.verbose(_(msg))
- del(msg)
- grass.run_command("r.recode",
- input = artificial_distances,
- output = tmp_output,
- rules = distance_categories,
- overwrite = True)
-
- output = grass.find_file(name=tmp_output, element='cell')
- if not output['file']:
- grass.fatal("Proximity map {name} not created!".format(name=raster))
-# else:
-# g.message(_("Output map {name}:".format(name=tmp_output)))
-
- return tmp_output
-
-def artificial_accessibility_expression(artificial_proximity, roads_proximity):
- """
- Build an r.mapcalc compatible expression to compute accessibility to
- artificial surfaces based on the following accessibility classification
- rules for artificial surfaces:
-
-|-------------------+-------+------------+-------------+--------------+---------|
-| Anthropic \ Roads | < 500 | 500 - 1000 | 1000 - 5000 | 5000 - 10000 | > 10000 |
-|-------------------+-------+------------+-------------+--------------+---------|
-| < 500 | 1 | 1 | 2 | 3 | 4 |
-|-------------------+-------+------------+-------------+--------------+---------|
-| 500 - 1000 | 1 | 1 | 2 | 3 | 4 |
-|-------------------+-------+------------+-------------+--------------+---------|
-| 1000 - 5000 | 2 | 2 | 2 | 4 | 5 |
-|-------------------+-------+------------+-------------+--------------+---------|
-| 5000 - 10000 | 3 | 3 | 4 | 5 | 5 |
-|-------------------+-------+------------+-------------+--------------+---------|
-| > 10000 | 3 | 4 | 4 | 5 | 5 |
-|-------------------+-------+------------+-------------+--------------+---------|
-
- Parameters
- ----------
- artificial :
- Proximity to artificial surfaces
-
- roads :
- Proximity to roads
-
- Returns
- -------
- expression
- Valid r.mapcalc expression
-
-
- Examples
- --------
- ...
- """
- expression = ('if( {artificial} <= 2 && {roads} <= 2, 1,'
- ' \ \n if( {artificial} == 1 && {roads} == 3, 2,'
- ' \ \n if( {artificial} == 2 && {roads} == 3, 2,'
- ' \ \n if( {artificial} == 3 && {roads} <= 3, 2,'
- ' \ \n if( {artificial} <= 2 && {roads} == 4, 3,'
- ' \ \n if( {artificial} == 4 && {roads} == 2, 3,'
- ' \ \n if( {artificial} >= 4 && {roads} == 1, 3,'
- ' \ \n if( {artificial} <= 2 && {roads} == 5, 4,'
- ' \ \n if( {artificial} == 3 && {roads} == 4, 4,'
- ' \ \n if( {artificial} >= 4 && {roads} == 3, 4,'
- ' \ \n if( {artificial} == 5 && {roads} == 2, 4,'
- ' \ \n if( {artificial} >= 3 && {roads} == 5, 5,'
- ' \ \n if( {artificial} >= 4 && {roads} == 4, 5)))))))))))))')
-
- expression = expression.format(artificial=artificial_proximity,
- roads=roads_proximity)
- return expression
-
-def compute_artificial_accessibility(artificial_proximity, roads_proximity, **kwargs):
- """Compute artificial proximity
-
- Parameters
- ----------
- artificial_proximity :
- Artificial surfaces...
-
- roads_proximity :
- Road infrastructure
-
- kwargs :
- Optional input parameters
-
- Returns
- -------
- output :
- ...
-
- Examples
- --------
- ...
- """
- artificial = grass.find_file(name=artificial_proximity, element='cell')
- if not artificial['file']:
- grass.fatal("Raster map {name} not found".format(name=artificial_proximity))
-
- roads = grass.find_file(name=roads_proximity, element='cell')
- if not roads['file']:
- grass.fatal("Raster map {name} not found".format(name=roads_proximity))
-
- accessibility_expression = artificial_accessibility_expression(
- artificial_proximity,
- roads_proximity)
- if 'output_name' in kwargs:
- # temporary maps will be removed!
- tmp_output = tmp_map_name(name=kwargs.get('output_name'))
- else:
- basename = 'artificial_accessibility'
- tmp_output = tmp_map_name(name=basename)
-
- accessibility_equation = equation.format(result=tmp_output,
- expression=accessibility_expression)
-
- if info:
- msg = "Equation for proximity to artificial areas: \n"
- msg += accessibility_equation
- grass.debug(msg)
- del(msg)
-
- grass.verbose(_("Computing accessibility to artificial surfaces"))
- grass.mapcalc(accessibility_equation, overwrite=True)
-
- del(accessibility_expression)
- del(accessibility_equation)
-
- output = save_map(tmp_output)
-
- return output
-
-def recreation_spectrum_expression(potential, opportunity):
- """
- Build and return a valid mapcalc expression for deriving
- the Recreation Opportunity Spectrum
-
- |-------------------------+-----+----------+------|
- | Potential / Opportunity | Far | Midrange | Near |
- |-------------------------+-----+----------+------|
- | Low | 1 | 2 | 3 |
- |-------------------------+-----+----------+------|
- | Moderate | 4 | 5 | 6 |
- |-------------------------+-----+----------+------|
- | High | 7 | 8 | 9 |
- |-------------------------+-----+----------+------|
-
- Questions:
-
- - Why not use `r.cross`?
- - Use DUMMY strings for potential and opportunity raster map names?
-
- Parameters
- ----------
- potential :
- Map depicting potential for recreation
-
- opportunity :
- Map depicting opportunity for recreation
-
- Returns
- -------
- expression :
- A valid r.mapcalc expression
-
- Examples
- --------
- ...
- """
- expression = ('if( {potential} == 1 && {opportunity} == 1, 1,'
- ' \ \n if( {potential} == 1 && {opportunity} == 2, 2,'
- ' \ \n if( {potential} == 1 && {opportunity} == 3, 3,'
- ' \ \n if( {potential} == 2 && {opportunity} == 1, 4,'
- ' \ \n if( {potential} == 2 && {opportunity} == 2, 5,'
- ' \ \n if( {potential} == 2 && {opportunity} == 3, 6,'
- ' \ \n if( {potential} == 3 && {opportunity} == 1, 7,'
- ' \ \n if( {potential} == 3 && {opportunity} == 2, 8,'
- ' \ \n if( {potential} == 3 && {opportunity} == 3, 9)))))))))')
-
- expression = expression.format(potential=potential,
- opportunity=opportunity)
-
- msg = "Recreation Spectrum expression: \n"
- msg += expression
- grass.debug(msg)
- del(msg)
-
- return expression
-
-def compute_recreation_spectrum(potential, opportunity, spectrum):
- """
- Computes spectrum for recreation based on maps of potential and opportunity
- for recreation
-
- Parameters
- ----------
- potential :
- Name for input potential for recreation map
-
- opportunity :
- Name for input opportunity for recreation map
-
- Returns
- -------
- spectrum :
- Name for output spectrum of recreation map
-
- Examples
- --------
- ...
- """
- spectrum_expression = recreation_spectrum_expression(
- potential=potential,
- opportunity=opportunity)
-
- spectrum_equation = equation.format(result=spectrum,
- expression=spectrum_expression)
-
- if info:
- msg = "Recreation Spectrum equation: \n"
- msg += spectrum_equation
- g.message(msg)
- del(msg)
-
- grass.mapcalc(spectrum_equation, overwrite=True)
-
- del(spectrum_expression)
- del(spectrum_equation)
- return spectrum
-
-def update_meta(raster, title):
- """
- Update metadata of given raster map
-
- Parameters
- ----------
- raster :
- ...
-
- title :
- ...
-
- Returns
- -------
- Does not return any value
-
- Examples
- --------
- ...
- """
- history = '\n' + citation_recreation_potential
- description_string = 'Recreation {raster} map'
- description = description_string.format(raster=raster)
-
- title = '{title}'.format(title=title)
- units = 'Meters'
-
- source1 = 'Source 1'
- source2 = 'Source 2'
-
- r.support(map=raster, title=title, description=description, units=units,
- source1=source1, source2=source2, history=history)
-
- if timestamp:
- r.timestamp(map=raster, date=timestamp)
-
- del(history)
- del(description)
- del(title)
- del(units)
- del(source1)
- del(source2)
-
-def export_map(input_name, title, categories, colors, output_name):
- """
- Export a raster map by renaming the (temporary) raster map name
- 'input_name' to the requested output raster map name 'output_name'.
- This function is (mainly) used to export either of the intermediate
- recreation 'potential' or 'opportunity' maps.
-
- Parameters
- ----------
- raster :
- Input raster map name
-
- title :
- Title for the output raster map
-
- categories :
- Categories and labels for the output raster map
-
- colors :
- Colors for the output raster map
-
- output_name :
- Output raster map name
-
- Returns
- -------
- output_name :
- This function will return the requested 'output_name'
-
- Examples
- --------
- ..
- """
- finding = grass.find_file(name=input_name,
- element='cell')
- if not finding['file']:
- grass.fatal("Raster map {name} not found".format(name=input_name))
- del(finding)
-
- # inform
- msg = "\nOutputting '{raster}' map\n"
- msg = msg.format(raster=input_name)
- grass.verbose(_(msg))
- del(msg)
-
- # get categories and labels
- raster_categories = 'categories_of_'
- raster_categories += input_name
- raster_category_labels = string_to_file(
- string = categories,
- name = raster_categories)
-
- # add ascii file to removal list
- remove_normal_files_at_exit.append(raster_category_labels)
-
- # apply categories and description
- r.category(map=input_name,
- rules=raster_category_labels,
- separator=':')
-
- # update meta and colors
- update_meta(input_name, title)
- r.colors(map=input_name,
- rules='-',
- stdin=colors,
- quiet=True)
- # rename to requested output name
- g.rename(
- raster=(
- input_name,
- output_name),
- quiet=True)
-
- return output_name
-
-def mobility_function(distance, constant, coefficients, population, score,
- **kwargs):
- """
- The following 'mobility' function, is identical to the one used in
- `compute_attractiveness()`, excluding, however, the 'score' term:
-
- if(L10<>0,(1+$D$3)/($D$3+exp(-$E$3*L10))*52,0)
-
- Source: Excel file provided by the MAES Team, Land Resources, D3
-
- ------------------------------------------------------------------
- if L<>0; then
- # (1 + D) / (D + exp(-E * L)) * 52)
-
- # D: Kappa
- # -E: Alpha -- Note the '-' sign in front of E
- # L: Population (within boundary, within distance buffer)
- ------------------------------------------------------------------
-
- Parameters
- ----------
-
- distance :
- Map of distance categories
-
- constant :
- Constant for the mobility function
-
- coefficients :
- A dictionary with a set for coefficients for each distance category, as
- (the example) presented in the following table:
-
- |----------+---------+---------|
- | Distance | Kappa | Alpha |
- |----------+---------+---------|
- | 0 to 1 | 0.02350 | 0.00102 |
- |----------+---------+---------|
- | 1 to 2 | 0.02651 | 0.00109 |
- |----------+---------+---------|
- | 2 to 3 | 0.05120 | 0.00098 |
- |----------+---------+---------|
- | 3 to 4 | 0.10700 | 0.00067 |
- |----------+---------+---------|
- | >4 | 0.06930 | 0.00057 |
- |----------+---------+---------|
-
- Note, the last distance category is not considered in deriving the
- final "map of visits".
-
- Note, the Alpha coefficient, is signed with a '-' in the mobility
- function.
-
- population :
- A map with the distribution of the demand per distance category and
- predefined geometric boundaries (see `r.stats.zonal` deriving the
- 'demand' map ).
-
- score :
- A score value for the mobility function
-
- **kwargs :
- Optional parameters. For example, the land suitability if integration
- in the build_distance_function() will be successfull.
-
- Returns
- -------
-
- mobility_expression :
- A valid mapcalc expression to compute the flow based on the
- predefined function `build_distance_function`.
-
- Examples
- --------
- ...
- """
- expressions={} # create a dictionary of expressions
-
- # Not used. It can be though if integration to build_distance_function() is
- # successfull. ------------------------------------------------------------
-
- # if 'suitability' in kwargs:
- # suitability = kwargs.get('suitability')
- # -------------------------------------------------------------------------
-
- for distance_category, parameters in coefficients.items():
-
- kappa, alpha = parameters
-
- # Note, alpha gets a minus, that is: -alpha
- expressions[distance_category]=build_distance_function(
- constant=constant,
- kappa=kappa,
- alpha=-alpha,
- variable=population,
- score=score)
- # suitability=suitability) # Not used.
- # Maybe it can, though, after successfully testing its
- # integration to build_distance_function().
-
- grass.debug(_("For distance '{d}':".format(d=distance)))
- grass.debug(_(expressions[distance_category]))
-
- msg = "Expressions per distance category: {e}".format(e=expressions)
- grass.debug(_(msg))
-
- # build expressions -- explicit: use the'score' kwarg!
- expression = ('eval( mobility_0 = {expression_0},'
- ' \ \n mobility_1 = {expression_1},'
- ' \ \n mobility_2 = {expression_2},'
- ' \ \n mobility_3 = {expression_3},'
- ' \ \n distance_0 = {distance} == {distance_category_0},'
- ' \ \n distance_1 = {distance} == {distance_category_1},'
- ' \ \n distance_2 = {distance} == {distance_category_2},'
- ' \ \n distance_3 = {distance} == {distance_category_3},'
- ' \ \n if( distance_0, mobility_0,'
- ' \ \n if( distance_1, mobility_1,'
- ' \ \n if( distance_2, mobility_2,'
- ' \ \n if( distance_3, mobility_3,'
- ' \ \n null() )))))')
- grass.debug(_("Mapcalc expression: {e}".format(e=expression)))
-
- # replace keywords appropriately
- # 'distance' is a map
- # 'distance_category' is a value
- # hence: 'distance' != 'distance_category'
- mobility_expression = expression.format(
- expression_0 = expressions[0],
- expression_1 = expressions[1],
- expression_2 = expressions[2],
- expression_3 = expressions[3],
- distance_category_0 = 0,
- distance_category_1 = 1,
- distance_category_2 = 2,
- distance_category_3 = 3,
- distance = distance)
- # FIXME Make the above more elegant?
-
- msg = "Big expression (after formatting): {e}".format(e=expression)
- grass.debug(_(msg))
-
- return mobility_expression
-
-def compute_unmet_demand(distance, constant, coefficients, population, score,
- **kwargs):
- """
- Parameters
- ----------
-
- distance :
- Map of distance categories
-
- constant :
- Constant for the mobility function
-
- coefficients :
- A tuple with coefficients for the last distance category, as
- (the example) presented in the following table:
-
- |----------+---------+---------|
- | Distance | Kappa | Alpha |
- |----------+---------+---------|
- | >4 | 0.06930 | 0.00057 |
- |----------+---------+---------|
-
- Note, this is the last distance category. See also the
- mobility_function().
-
- Note, the Alpha coefficient, is signed with a '-' in the mobility
- function.
-
- population :
- A map with the distribution of the demand per distance category and
- predefined geometric boundaries (see `r.stats.zonal` deriving the
- 'unmet demand' map ).
-
- score :
- A score value for the mobility function
-
- **kwargs :
- Optional parameters. For example, the land suitability if integration
- in the build_distance_function() will be successfull.
-
- Returns
- -------
-
- mobility_expression :
- A valid mapcalc expression to compute the flow based on the
- predefined function `build_distance_function`.
-
- Examples
- --------
- ...
- """
- distance_category = 4 # Hardcoded! FIXME
-
- kappa, alpha = coefficients
- unmet_demand_expression = build_distance_function(
- constant=constant,
- kappa=kappa,
- alpha=-alpha,
- variable=population,
- score=score)
- # suitability=suitability) # Not used. Maybe it can, though,
- # after successfull testing its integration to
- # build_distance_function().
-
- msg = "Expression for distance category '{d}': {e}"
- msg = msg.format(d=distance_category, e=unmet_demand_expression)
- grass.debug(_(msg))
-
- # build expressions -- explicit: use the 'score' kwarg!
- expression = ('eval( unmet_demand = {expression},'
- ' \ \n distance = {distance} == {distance_category},'
- ' \ \n if( distance, unmet_demand,'
- ' \ \n null() ))')
- grass.debug(_("Mapcalc expression: {e}".format(e=expression)))
-
- # replace keywords appropriately
- unmet_demand_expression = expression.format(
- expression = unmet_demand_expression,
- distance = distance,
- distance_category = distance_category)
-
- msg = "Big expression (after formatting): {e}".format(
- e=unmet_demand_expression)
- grass.debug(_(msg))
-
- return unmet_demand_expression
-
-def update_vector(vector, raster, methods, column_prefix):
- """
-
- Parameters
- ----------
- vector :
- Vector map whose attribute table to update with results of the
- v.rast.stats call
-
- raster :
- Source raster map for statistics
-
- methods :
- Descriptive statistics for the `v.rast.stats` call
-
- column_prefix :
- Prefix for the names of the columns created by the `v.rast.stats` call
-
- Returns
- -------
- This helper function executes `v.rast.stats`. It does not return any
- value.
-
- Examples
- --------
- ..
- """
- run('v.rast.stats',
- map=vector,
- flags='c',
- raster=raster,
- method=methods,
- column_prefix=column_prefix,
- overwrite=True)
- # grass.verbose(_("Updating vector map '{v}'".format(v=vector)))
-
-def get_raster_statistics(map_one, map_two, separator, flags):
- """
- Parameters
- ----------
- map_one :
- First map as input to `r.stats`
-
- map_two :
- Second map as input to `r.stats`
-
- separator :
- Character to use as separator in `r.stats`
-
- flags :
- Flags for `r.stats`
-
- Returns
- -------
- dictionary :
- A nested dictionary that holds categorical statistics for both maps
- 'map_one' and 'map_two'.
-
- - The 'outer_key' is the raster category _and_ label of 'map_one'.
- - The 'inner_key' is the raster map category of 'map_two'.
- - The 'inner_value' is the list of statistics for map two, as returned
- for `r.stats`.
-
- Example of a nested dictionary:
-
- {(u'3',
- u'Region 3'):
- {u'1': [
- u'355.747658',
- u'6000000.000000',
- u'6',
- u'6.38%'],
- u'3': [
- u'216304.146140',
- u'46000000.000000',
- u'46',
- u'48.94%'],
- u'2': [
- u'26627.415787',
- u'46000000.000000',
- u'46',
- u'48.94%']}}
- """
-
- statistics = grass.read_command(
- 'r.stats',
- input=(map_one, map_two),
- output='-',
- flags=flags,
- separator=separator,
- quiet=True)
- statistics = statistics.split('\n')[:-1]
-
- dictionary = dict()
-
- # build a nested dictionary where:
- for row in statistics:
- row = row.split('|')
- outer_key = ( row[0], row[1])
- inner_key = row[2]
- inner_value = row[3:]
- inner_dictionary = {inner_key: inner_value}
- try:
- dictionary[outer_key][inner_key] = inner_value
- except KeyError:
- dictionary[outer_key] = { inner_key : inner_value}
-
- return dictionary
-
-def compile_use_table(supply):
- """Compile the 'use' table out of a 'supply' table
-
- Parameters
- ----------
- supply :
- A nested Python dictionary that is compiled when runnning the
- compute_supply() function
-
- Returns
- -------
-
- Examples
- --------
- """
- uses = {}
- for outer_key, outer_value in supply.items():
- dictionaries = statistics_dictionary[outer_key]
-
- use_values = []
- for key, value in dictionaries.items():
- use_value = value[0]
- use_values.append(use_value)
-
- use_in_key = sum([float(x)
- if not math.isnan(float(x))
- else 0
- for x in use_values])
-
- try:
- uses[outer_key] = use_in_key
- except KeyError:
- print "Something went wrong in building the use table"
-
- return uses
-
-def compute_supply(base,
- recreation_spectrum,
- highest_spectrum,
- base_reclassification_rules,
- reclassified_base,
- reclassified_base_title,
- flow,
- flow_map_name,
- aggregation,
- ns_resolution,
- ew_resolution,
- **kwargs):
- """
- Algorithmic description of the "Contribution of Ecosysten Types"
-
- # FIXME
- '''
- 1 B ← {0, .., m-1} : Set of aggregational boundaries
- 2 T ← {0, .., n-1} : Set of land cover types
- 3 WE ← 0 : Set of weighted extents
- 4 R ← 0 : Set of fractions
- 5 F ← 0
- 6 MASK ← HQR : High Quality Recreation
- 7 foreach {b} ⊆ B do : for each aggregational boundary 'b'
- 8 RB ← 0
- 9 foreach {t} ⊆ T do : for each Land Type
- 10 WEt ← Et * Wt : Weighted Extent = Extent(t) * Weight(t)
- 11 WE ← WE⋃{WEt} : Add to set of Weighted Extents
- 12 S ← ∑t∈WEt
- 13 foreach t ← T do
- 14 Rt ← WEt / ∑WE
- 15 R ← R⋃{Rt}
- 16 RB ← RB⋃{R}
- '''
- # FIXME
-
- Parameters
- ----------
- recreation_spectrum:
- Map scoring access to and quality of recreation
-
- highest_spectrum :
- Expected is a map of areas with highest recreational value (category 9
- as per the report ... )
-
- base :
- Base land types map for final zonal statistics. Specifically to
- ESTIMAP's recrceation mapping algorithm
-
- base_reclassification_rules :
- Reclassification rules for the input base map
-
- reclassified_base :
- Name for the reclassified base cover map
-
- reclassified_base_title :
- Title for the reclassified base map
-
- ecosystem_types :
-
- flow :
- Map of visits, derived from the mobility function, depicting the
- number of people living inside zones 0, 1, 2, 3. Used as a cover map
- for zonal statistics.
-
- flow_map_name :
- A name for the 'flow' map. This is required when the 'flow' input
- option is not defined by the user, yet some of the requested outputs
- required first the production of the 'flow' map. An example is the
- request for a supply table without requesting the 'flow' map itself.
-
- aggregation :
-
- ns_resolution :
-
- ew_resolution :
-
- statistics_filename :
-
- **kwargs :
- Optional keyword arguments, such as: 'csv_prefix'
-
- ? :
- Land cover class percentages in ROS9 (this is: relative percentage)
-
- output :
- Supply table (distribution of flow for each land cover class)
-
- Returns
- -------
- This function produces a map to base the production of a supply table in
- form of CSV.
-
- Examples
- --------
- """
- # Inputs
- flow_in_base = flow + '_' + base
- base_scores = base + '.scores'
-
- # Define lists and dictionaries to hold intermediate data
- weighted_extents = {}
- flows = []
- global statistics_dictionary
- statistics_dictionary = {}
-
- # MASK areas of high quality recreation
- r.mask(raster=highest_spectrum, overwrite=True, quiet=True)
-
- # Reclassify land cover map to MAES ecosystem types
- r.reclass(input=base,
- rules=base_reclassification_rules,
- output=reclassified_base,
- quiet=True)
- # add to "remove_at_exit" after the reclassified maps!
-
- # Discard areas out of MASK
- copy_equation = equation.format(result=reclassified_base,
- expression=reclassified_base)
- r.mapcalc(copy_equation, overwrite=True)
- del(copy_equation)
-
- # Count flow within each land cover category
- r.stats_zonal(base=base,
- flags='r',
- cover=flow_map_name,
- method='sum',
- output=flow_in_base,
- overwrite=True,
- quiet=True)
-
- # Set colors for "flow" map
- r.colors(map=flow_in_base,
- color=MOBILITY_COLORS,
- quiet=True)
-
- # Parse aggregation raster categories and labels
- categories = grass.parse_command('r.category',
- map=aggregation,
- delimiter='\t')
-
- for category in categories:
-
- # Intermediate names
-
- cells = highest_spectrum + '.cells' + '.' + category
- remove_at_exit.append(cells)
-
- extent = highest_spectrum + '.extent' + '.' + category
- remove_at_exit.append(extent)
-
- weighted = highest_spectrum + '.weighted' + '.' + category
- remove_at_exit.append(weighted)
-
- fractions = base + '.fractions' + '.' + category
- remove_at_exit.append(fractions)
-
- flow_category = '_flow_' + category
- flow = base + flow_category
- remove_at_exit.append(flow)
-
- flow_in_reclassified_base = reclassified_base + '_flow'
- flow_in_category = reclassified_base + flow_category
- del(flow_category)
- flows.append(flow_in_category) # add to list for patching
- remove_at_exit.append(flow_in_category)
-
- # Output names
-
- msg = "Processing aggregation raster category: {r}"
- msg = msg.format(r=category)
- grass.debug(_(msg))
- # g.message(_(msg))
- del(msg)
-
- # First, set region to extent of the aggregation map
- # and resolution to the one of the population map
- # Note the `-a` flag to g.region: ?
- # To safely modify the region: grass.use_temp_region() # FIXME
- g.region(raster=aggregation,
- nsres=ns_resolution,
- ewres=ew_resolution,
- flags='a',
- quiet=True)
-
- msg = "|! Computational resolution matched to {raster}"
- msg = msg.format(raster=aggregation)
- grass.debug(_(msg))
- del(msg)
-
- # Build MASK for current category & high quality recreation areas
- msg = "Setting category '{c}' of '{a}' as a MASK"
- grass.verbose(_(msg.format(c=category, a=aggregation)))
- del(msg)
-
- masking = 'if( {spectrum} == {highest_quality_category} && '
- masking += '{aggregation} == {category}, '
- masking += '1, null() )'
- masking = masking.format(
- spectrum=recreation_spectrum,
- highest_quality_category=HIGHEST_RECREATION_CATEGORY,
- aggregation=aggregation,
- category=category)
-
- masking_equation = equation.format(
- result='MASK',
- expression = masking)
-
- grass.mapcalc(masking_equation, overwrite=True)
-
- del(masking)
- del(masking_equation)
-
- # zoom to MASK
- g.region(zoom='MASK',
- nsres=ns_resolution,
- ewres=ew_resolution,
- quiet=True)
-
- # Count number of cells within each land category
- r.stats_zonal(
- flags='r',
- base=base,
- cover=highest_spectrum,
- method='count',
- output=cells,
- overwrite=True,
- quiet=True)
- cells_categories = grass.parse_command('r.category',
- map=cells,
- delimiter='\t')
- grass.debug(_("Cells: {c}".format(c=cells_categories)))
-
- # Build cell category and label rules for `r.category`
- cells_rules = '\n'.join(['{0}:{1}'.format(key, value)
- for key, value
- in cells_categories.items()])
- del(cells_categories)
-
- # Discard areas out of MASK
- copy_equation = equation.format(result=cells,
- expression=cells)
- r.mapcalc(copy_equation, overwrite=True)
- del(copy_equation)
-
- # Reassign cell category labels
- r.category(
- map=cells,
- rules='-',
- stdin=cells_rules,
- separator=':')
- del(cells_rules)
-
- # Compute extent of each land category
- extent_expression = "@{cells} * area()"
- extent_expression = extent_expression.format(cells=cells)
- extent_equation = equation.format(
- result=extent,
- expression=extent_expression)
- r.mapcalc(extent_equation, overwrite=True)
-
- # Write extent figures as labels
- r.stats_zonal(
- flags='r',
- base=base,
- cover=extent,
- method='average',
- output=extent,
- overwrite=True,
- verbose=False,
- quiet=True)
-
- # Write land suitability scores as an ASCII file
- suitability_scores_as_labels = string_to_file(
- SUITABILITY_SCORES_LABELS,
- name=reclassified_base)
- remove_normal_files_at_exit.append(suitability_scores_as_labels)
-
- # Write scores as raster category labels
- r.reclass(input=base,
- output=base_scores,
- rules=suitability_scores_as_labels,
- overwrite=True,
- quiet=True,
- verbose=False)
- remove_at_exit.append(base_scores)
-
- # Compute weighted extents
- weighted_expression = "@{extent} * float(@{scores})"
- weighted_expression = weighted_expression.format(
- extent=extent,
- scores=base_scores)
- weighted_equation = equation.format(
- result=weighted,
- expression = weighted_expression)
- r.mapcalc(weighted_equation, overwrite=True)
-
- # Write weighted extent figures as labels
- r.stats_zonal(
- flags='r',
- base=base,
- cover=weighted,
- method='average',
- output=weighted,
- overwrite=True,
- verbose=False,
- quiet=True)
-
- # Get weighted extents in a dictionary
- weighted_extents = grass.parse_command('r.category',
- map=weighted,
- delimiter='\t')
-
- # Compute the sum of all weighted extents and add to dictionary
- category_sum = sum([float(x)
- if not math.isnan(float(x))
- else 0
- for x
- in weighted_extents.values()])
- weighted_extents['sum'] = category_sum
-
- # Create a map to hold fractions of each weighted extent to the sum
- # See also:
- # https://grasswiki.osgeo.org/wiki/LANDSAT#Hint:_Minimal_disk_space_copies
- r.reclass(
- input=base,
- output=fractions,
- rules='-',
- stdin='*=*',
- verbose=False,
- quiet=True)
-
- # Compute weighted fractions of land types
- fraction_category_label = {key: float(value) / weighted_extents['sum']
- for (key, value)
- in weighted_extents.iteritems()
- if key is not 'sum'}
-
- # Build fraction category and label rules for `r.category`
- fraction_rules = '\n'.join(['{0}:{1}'.format(key, value)
- for key, value
- in fraction_category_label.items()])
- del(fraction_category_label)
-
- # Set rules
- r.category(
- map=fractions,
- rules='-',
- stdin=fraction_rules,
- separator=':')
- del(fraction_rules)
-
- # Assert that sum of fractions is ~1
- fraction_categories = grass.parse_command('r.category',
- map=fractions,
- delimiter='\t')
-
- fractions_sum = sum([float(x)
- if not math.isnan(float(x))
- else 0
- for x
- in fraction_categories.values()])
- msg = "Fractions: {f}".format(f=fraction_categories)
- grass.debug(_(msg))
- del(msg)
-
- # g.message(_("Sum: {:.17g}".format(fractions_sum)))
- assert abs(fractions_sum -1 ) < 1.e-6, "Sum of fractions is != 1"
-
- # Compute flow
- flow_expression = "@{fractions} * @{flow}"
- flow_expression = flow_expression.format(fractions=fractions,
- flow=flow_in_base)
- flow_equation = equation.format(
- result=flow,
- expression=flow_expression)
- r.mapcalc(flow_equation, overwrite=True)
-
- # Write flow figures as raster category labels
- r.stats_zonal(base=reclassified_base,
- flags='r',
- cover=flow,
- method='sum',
- output=flow_in_category,
- overwrite=True,
- verbose=False,
- quiet=True)
-
- # Parse flow categories and labels
- flow_categories = grass.parse_command('r.category',
- map=flow_in_category,
- delimiter='\t')
- grass.debug(_("Flow: {c}".format(c=flow_categories)))
-
- # Build flow category and label rules for `r.category`
- flow_rules = '\n'.join(['{0}:{1}'.format(key, value)
- for key, value
- in flow_categories.items()])
- del(flow_categories)
-
- # Discard areas out of MASK
-
- # Check here again!
- # Output patch of all flow maps?
-
- copy_equation = equation.format(result=flow_in_category,
- expression=flow_in_category)
- r.mapcalc(copy_equation, overwrite=True)
- del(copy_equation)
-
- # Reassign cell category labels
- r.category(
- map=flow_in_category,
- rules='-',
- stdin=flow_rules,
- separator=':')
- del(flow_rules)
-
- # Update title
- reclassified_base_title += ' ' + category
- r.support(flow_in_category,
- title=reclassified_base_title)
-
- # if info:
- # r.report(flags='hn',
- # map=(flow_in_category),
- # units=('k','c','p'))
-
- if print_only:
- r.stats(input=(flow_in_category),
- output='-',
- flags='nacpl',
- separator=COMMA,
- quiet=True)
-
- if not print_only:
-
- if 'flow_column_name' in kwargs:
- flow_column_name = kwargs.get('flow_column_name')
- flow_column_prefix = flow_column_name + category
- else:
- flow_column_name = 'flow'
- flow_column_prefix = flow_column_name + category
-
- # Produce vector map(s)
- if 'vector' in kwargs:
-
- vector = kwargs.get('vector')
-
- # The following is wrong
-
- # update_vector(vector=vector,
- # raster=flow_in_category,
- # methods=METHODS,
- # column_prefix=flow_column_prefix)
-
- # What can be done?
-
- # Maybe update columns of an existing map from the columns of
- # the following vectorised raster map(s)
- # ?
-
- r.to_vect(
- input=flow_in_category,
- output=flow_in_category,
- type='area',
- quiet=True)
-
- # Value is the ecosystem type
- v.db_renamecolumn(
- map=flow_in_category,
- column=('value', 'ecosystem'))
-
- # New column for flow values
- addcolumn_string = flow_column_name + ' double'
- v.db_addcolumn(
- map=flow_in_category,
- columns=addcolumn_string)
-
- # The raster category 'label' is the 'flow'
- v.db_update(
- map=flow_in_category,
- column='flow',
- query_column='label')
- v.db_dropcolumn(
- map=flow_in_category,
- columns='label')
-
- # Update the aggregation raster categories
- v.db_addcolumn(
- map=flow_in_category,
- columns='aggregation_id int')
- v.db_update(
- map=flow_in_category,
- column='aggregation_id',
- value=category)
-
- v.colors(map=flow_in_category,
- raster=flow_in_category,
- quiet=True)
-
- # get statistics
- dictionary = get_raster_statistics(
- map_one=aggregation, # reclassified_base
- map_two=flow_in_category,
- separator='|',
- flags='nlcap')
-
- # merge 'dictionary' with global 'statistics_dictionary'
- statistics_dictionary = merge_two_dictionaries(
- statistics_dictionary,
- dictionary)
- del(dictionary)
-
- # It is important to remove the MASK!
- r.mask(flags='r', quiet=True)
-
-
- # FIXME
-
- # Add "reclassified_base" map to "remove_at_exit" here, so as to be after
- # all reclassified maps that derive from it
-
- # remove the map 'reclassified_base'
- # g.remove(flags='f', type='raster', name=reclassified_base, quiet=True)
- # remove_at_exit.append(reclassified_base)
-
- if not print_only:
-
- r.patch(flags='',
- input=flows,
- output=flow_in_reclassified_base,
- quiet=True)
-
- if 'vector' in kwargs:
- # Patch all flow vector maps in one
- v.patch(flags='e',
- input=flows,
- output=flow_in_reclassified_base,
- overwrite=True,
- quiet=True)
-
- # export to csv
- if 'supply_filename' in kwargs:
-
- supply_filename = kwargs.get('supply_filename')
- supply_filename += CSV_EXTENSION
- nested_dictionary_to_csv(supply_filename,
- statistics_dictionary)
- del(supply_filename)
-
- if 'use_filename' in kwargs:
-
- use_filename = kwargs.get('use_filename')
- use_filename += CSV_EXTENSION
- uses = compile_use_table(statistics_dictionary)
- dictionary_to_csv(use_filename, uses)
- del(use_filename)
- del(statistics_dictionary)
- del(uses)
-
- # Maybe return list of flow maps? Requires unique flow map names
- return flows
-
- grass.del_temp_region() # restoring previous region settings
- # grass.verbose("Original Region restored")
-
-def main():
- """
- Main program
- """
-
- '''Flags and Options'''
-
- global average_filter
- average_filter = flags['f']
-
- global info, save_temporary_maps, print_only
- landuse_extent = flags['e']
- save_temporary_maps = flags['s']
- info = flags['i']
- print_only = flags['p']
-
- global timestamp
- timestamp = options['timestamp']
-
- global remove_at_exit, remove_normal_files_at_exit, rename_at_exit
- remove_at_exit = []
- remove_normal_files_at_exit = []
- rename_at_exit = []
-
- global metric, units
- metric = options['metric']
- units = options['units']
- if len(units) > 1:
- units = units.split(',')
-
- '''names for input, output, output suffix, options'''
-
- global mask
- mask = options['mask']
-
- '''
- following some hard-coded names -- review and remove!
- '''
-
- land = options['land']
- land_component_map_name = tmp_map_name(name='land_component')
-
- water = options['water']
- water_component_map_name = tmp_map_name(name='water_component')
-
- natural = options['natural']
- natural_component_map_name = tmp_map_name(name='natural_component')
-
- urban = options['urban']
- urban_component_map='urban_component'
-
- infrastructure = options['infrastructure']
- infrastructure_component_map_name = tmp_map_name(name='infrastructure_component')
-
- recreation = options['recreation']
- recreation_component_map_name = tmp_map_name(name='recreation_component')
-
- '''Land components'''
-
- landuse = options['landuse']
- if landuse:
- # Check datatype: a land use map should be categorical, i.e. of type CELL
- landuse_datatype = grass.raster.raster_info(landuse)['datatype']
- if landuse_datatype != 'CELL':
- msg = ("The '{landuse}' input map "
- "should be a categorical one "
- "and of type 'CELL'. "
- "Perhaps you meant to use the 'land' input option instead?")
- grass.fatal(_(msg.format(landuse=landuse)))
-
- suitability_map_name = tmp_map_name(name='suitability')
- suitability_scores = options['suitability_scores']
-
- if landuse and suitability_scores and ':' not in suitability_scores:
- msg = "Suitability scores from file: {scores}."
- msg = msg.format(scores = suitability_scores)
- grass.verbose(_(msg))
-
- if landuse and not suitability_scores:
- msg = "Using internal rules to score land use classes in '{map}'"
- msg = msg.format(map=landuse)
- grass.warning(_(msg))
-
- suitability_scores = string_to_file(SUITABILITY_SCORES,
- name=suitability_map_name)
- remove_normal_files_at_exit.append(suitability_scores)
-
- if landuse and suitability_scores and ':' in suitability_scores:
- msg = "Using provided string of rules to score land use classes in {map}"
- msg = msg.format(map=landuse)
- grass.verbose(_(msg))
- suitability_scores = string_to_file(suitability_scores,
- name=suitability_map_name)
- remove_normal_files_at_exit.append(suitability_scores)
-
-
- # FIXME -----------------------------------------------------------------
-
- # Use one landcover input if supply is requested
- # Use one set of land cover reclassification rules
-
- landcover = options['landcover']
-
- if not landcover:
- landcover = landuse
- msg = "Land cover map 'landcover' not given. "
- msg += "Attempt to use the '{landuse}' map to derive areal statistics"
- msg = msg.format(landuse=landuse)
- grass.verbose(_(msg))
-
- maes_ecosystem_types = 'maes_ecosystem_types'
- maes_ecosystem_types_scores = 'maes_ecosystem_types_scores'
- landcover_reclassification_rules = options['land_classes']
-
- # if 'land_classes' is a file
- if (landcover and
- landcover_reclassification_rules and
- ':' not in landcover_reclassification_rules):
- msg = "Land cover reclassification rules from file: {rules}."
- msg = msg.format(rules = landcover_reclassification_rules)
- grass.verbose(_(msg))
-
- # if 'land_classes' not given
- if landcover and not landcover_reclassification_rules:
-
- # if 'landcover' is not the MAES land cover,
- # then use internal reclassification rules
- # how to test:
- # 1. landcover is not a "MAES" land cover
- # 2. landcover is an Urban Atlas one?
-
- msg = "Using internal rules to reclassify the '{map}' map"
- msg = msg.format(map=landcover)
- grass.verbose(_(msg))
-
- landcover_reclassification_rules = string_to_file(
- URBAN_ATLAS_TO_MAES_NOMENCLATURE,
- name=maes_ecosystem_types)
- remove_normal_files_at_exit.append(landcover_reclassification_rules)
-
- # if landcover is a "MAES" land cover, no need to reclassify!
-
- if (landuse and
- landcover_reclassification_rules and
- ':' in landcover_reclassification_rules):
- msg = "Using provided string of rules to reclassify the '{map}' map"
- msg = msg.format(map=landcover)
- grass.verbose(_(msg))
- landcover_reclassification_rules = string_to_file(
- landcover_reclassification_rules,
- name=maes_land_classes)
- remove_normal_files_at_exit.append(landcover_reclassification_rules)
-
- # FIXME -----------------------------------------------------------------
-
- '''Water components'''
-
- lakes = options['lakes']
- lakes_coefficients = options['lakes_coefficients']
- lakes_proximity_map_name = 'lakes_proximity'
- coastline = options['coastline']
- coast_proximity_map_name = 'coast_proximity'
- coast_geomorphology = options['coast_geomorphology']
- # coast_geomorphology_coefficients = options['geomorphology_coefficients']
- coast_geomorphology_map_name = 'coast_geomorphology'
- bathing_water = options['bathing_water']
- bathing_water_coefficients = options['bathing_coefficients']
- bathing_water_proximity_map_name = 'bathing_water_proximity'
-
- '''Natural components'''
-
- protected = options['protected']
- protected_scores = options['protected_scores']
- protected_areas_map_name = 'protected_areas'
-
- '''Artificial areas'''
-
- artificial = options['artificial']
- artificial_proximity_map_name='artificial_proximity'
- artificial_distance_categories = options['artificial_distances']
-
- roads = options['roads']
- roads_proximity_map_name = 'roads_proximity'
- roads_distance_categories = options['roads_distances']
-
- artificial_accessibility_map_name='artificial_accessibility'
-
- '''Devaluation'''
-
- devaluation = options['devaluation']
-
- '''Aggregational boundaries'''
-
- base = options['base']
- base_vector = options['base_vector']
- aggregation = options['aggregation']
-
- '''Population'''
-
- population = options['population']
- if population:
- population_ns_resolution = grass.raster_info(population)['nsres']
- population_ew_resolution = grass.raster_info(population)['ewres']
-
- '''Outputs'''
-
- potential_title = "Recreation potential"
- recreation_potential = options['potential'] # intermediate / output
- recreation_potential_map_name = tmp_map_name(name='recreation_potential')
-
- opportunity_title = "Recreation opportunity"
- recreation_opportunity=options['opportunity']
- recreation_opportunity_map_name='recreation_opportunity'
-
- spectrum_title = "Recreation spectrum"
- # if options['spectrum']:
- recreation_spectrum = options['spectrum'] # output
- # else:
- # recreation_spectrum = 'recreation_spectrum'
- # recreation_spectrum_component_map_name =
- # tmp_map_name(name='recreation_spectrum_component_map')
-
- spectrum_distance_categories = options['spectrum_distances']
- if ':' in spectrum_distance_categories:
- spectrum_distance_categories = string_to_file(
- spectrum_distance_categories,
- name=recreation_spectrum)
- # remove_at_exit.append(spectrum_distance_categories) -- Not a map!
- remove_normal_files_at_exit.append(spectrum_distance_categories)
-
- highest_spectrum = 'highest_recreation_spectrum'
- crossmap = 'crossmap' # REMOVEME
-
- demand = options['demand']
- unmet_demand = options['unmet']
-
- flow = options['flow']
- flow_map_name = 'flow'
-
- supply = options['supply'] # use as CSV filename prefix
- use = options['use'] # use as CSV filename prefix
-
- """ First, care about the computational region"""
-
- if mask:
- msg = "Masking NULL cells based on '{mask}'".format(mask=mask)
- grass.verbose(_(msg))
- r.mask(raster=mask, overwrite=True, quiet=True)
-
- if landuse_extent:
- grass.use_temp_region() # to safely modify the region
- g.region(flags='p', raster=landuse) # Set region to 'mask'
- msg = "|! Computational resolution matched to {raster}"
- msg = msg.format(raster=landuse)
- g.message(_(msg))
-
- """Land Component
- or Suitability of Land to Support Recreation Activities (SLSRA)"""
-
- land_component = [] # a list, use .extend() wherever required
-
- if land:
-
- land_component = land.split(',')
-
- if landuse and suitability_scores:
-
- msg = "Deriving land suitability from '{landuse}' "
- msg += "based on rules described in file '{rules}'"
- grass.verbose(msg.format(landuse=landuse, rules=suitability_scores))
-
- # suitability is the 'suitability_map_name'
- recode_map(raster=landuse,
- rules=suitability_scores,
- colors=SCORE_COLORS,
- output=suitability_map_name)
-
- append_map_to_component(
- raster=suitability_map_name,
- component_name='land',
- component_list=land_component)
-
- '''Water Component'''
-
- water_component = []
- water_components = []
-
- if water:
-
- water_component = water.split(',')
- msg = "Water component includes currently: {component}"
- msg = msg.format(component=water_component)
- grass.debug(_(msg))
- # grass.verbose(_(msg))
-
- if lakes:
-
- if lakes_coefficients:
- metric, constant, kappa, alpha, score = get_coefficients(
- lakes_coefficients)
-
- lakes_proximity = compute_attractiveness(
- raster = lakes,
- metric = EUCLIDEAN,
- constant = constant,
- kappa = kappa,
- alpha = alpha,
- score = score,
- mask = lakes)
-
- del(constant)
- del(kappa)
- del(alpha)
- del(score)
-
- append_map_to_component(
- raster=lakes_proximity,
- component_name='water',
- component_list=water_components)
-
- if coastline:
-
- coast_proximity = compute_attractiveness(
- raster = coastline,
- metric = EUCLIDEAN,
- constant = WATER_PROXIMITY_CONSTANT,
- alpha = WATER_PROXIMITY_ALPHA,
- kappa = WATER_PROXIMITY_KAPPA,
- score = WATER_PROXIMITY_SCORE)
-
- append_map_to_component(
- raster=coast_proximity,
- component_name='water',
- component_list=water_components)
-
- if coast_geomorphology:
-
- try:
-
- if not coastline:
- msg = "The coastline map is required in order to "
- msg += "compute attractiveness based on the "
- msg += "coast geomorphology raster map"
- msg = msg.format(c=water_component)
- grass.fatal(_(msg))
-
- except NameError:
- grass.fatal(_("No coast proximity"))
-
- coast_attractiveness = neighborhood_function(
- raster=coast_geomorphology,
- method = NEIGHBORHOOD_METHOD,
- size = NEIGHBORHOOD_SIZE,
- distance_map=coast_proximity)
-
- append_map_to_component(
- raster=coast_attractiveness,
- component_name='water',
- component_list=water_components)
-
- if bathing_water:
-
- if bathing_water_coefficients:
- metric, constant, kappa, alpha = get_coefficients(
- bathing_water_coefficients)
-
- bathing_water_proximity = compute_attractiveness(
- raster = bathing_water,
- metric = EUCLIDEAN,
- constant = constant,
- kappa = kappa,
- alpha = alpha)
-
- del(constant)
- del(kappa)
- del(alpha)
-
- append_map_to_component(
- raster=bathing_water_proximity,
- component_name='water',
- component_list=water_components)
-
- # merge water component related maps in one list
- water_component += water_components
-
- '''Natural Component'''
-
- natural_component = []
- natural_components = []
-
- if natural:
-
- natural_component = natural.split(',')
-
- if protected:
- msg = "Scoring protected areas '{protected}' based on '{rules}'"
- grass.verbose(_(msg.format(protected=protected, rules=protected_scores)))
-
- protected_areas = protected_areas_map_name
-
- recode_map(raster=protected,
- rules=protected_scores,
- colors=SCORE_COLORS,
- output=protected_areas)
-
- append_map_to_component(
- raster=protected_areas,
- component_name='natural',
- component_list=natural_components)
-
- # merge natural resources component related maps in one list
- natural_component += natural_components
-
- """ Normalize land, water, natural inputs
- and add them to the recreation potential component"""
-
- recreation_potential_component = []
-
- if land_component:
-
- for dummy_index in land_component:
-
- # remove 'land_map' from 'land_component'
- # process and add it back afterwards
- land_map = land_component.pop(0)
-
- '''
- This section sets NULL cells to 0.
- Because `r.null` operates on the complete input raster map,
- manually subsetting the input map is required.
- '''
- suitability_map = tmp_map_name(name=land_map)
- subset_land = equation.format(result = suitability_map,
- expression = land_map)
- r.mapcalc(subset_land)
-
- grass.debug(_("Setting NULL cells to 0")) # REMOVEME ?
- r.null(map=suitability_map, null=0) # Set NULLs to 0
-
- msg = "\nAdding land suitability map '{suitability}' "
- msg += "to 'Recreation Potential' component\n"
- msg = msg.format(suitability = suitability_map)
- grass.verbose(_(msg))
-
- # add 'suitability_map' to 'land_component'
- land_component.append(suitability_map)
-
- if len(land_component) > 1:
- grass.verbose(_("\nNormalize 'Land' component\n"))
- zerofy_and_normalise_component(land_component, THRESHHOLD_ZERO,
- land_component_map_name)
- recreation_potential_component.extend(land_component)
- else:
- recreation_potential_component.extend(land_component)
-
- if land_component and average_filter:
- smooth_component(
- land_component,
- method='average',
- size=7)
-
- # remove_at_exit.extend(land_component)
-
- if len(water_component) > 1:
- grass.verbose(_("\nNormalize 'Water' component\n"))
- zerofy_and_normalise_component(water_component, THRESHHOLD_ZERO,
- water_component_map_name)
- recreation_potential_component.append(water_component_map_name)
- else:
- recreation_potential_component.extend(water_component)
-
- # remove_at_exit.append(water_component_map_name)
-
- if len(natural_component) > 1:
- grass.verbose(_("\nNormalize 'Natural' component\n"))
- zerofy_and_normalise_component(
- components=natural_component,
- threshhold=THRESHHOLD_ZERO,
- output_name=natural_component_map_name)
- recreation_potential_component.append(natural_component_map_name)
- else:
- recreation_potential_component.extend(natural_component)
-
- if natural_component and average_filter:
- smooth_component(
- natural_component,
- method='average',
- size=7)
-
- # remove_at_exit.append(natural_component_map_name)
-
- """ Recreation Potential [Output] """
-
- tmp_recreation_potential = tmp_map_name(name=recreation_potential_map_name)
-
- msg = "Computing intermediate 'Recreation Potential' map: '{potential}'"
- grass.verbose(_(msg.format(potential=tmp_recreation_potential)))
- grass.debug(_("Maps: {maps}".format(maps=recreation_potential_component)))
-
- zerofy_and_normalise_component(
- components = recreation_potential_component,
- threshhold = THRESHHOLD_ZERO,
- output_name = tmp_recreation_potential)
-
- # recode recreation_potential
- tmp_recreation_potential_categories = tmp_map_name(
- name=recreation_potential)
-
- msg = "\nClassifying '{potential}' map"
- msg = msg.format(potential=tmp_recreation_potential)
- grass.verbose(_(msg))
-
- classify_recreation_component(
- component = tmp_recreation_potential,
- rules = RECREATION_POTENTIAL_CATEGORIES,
- output_name = tmp_recreation_potential_categories)
-
- if recreation_potential:
-
- # export 'recreation_potential' map and
- # use 'output_name' for the temporary 'potential' map for spectrum
- tmp_recreation_potential_categories = export_map(
- input_name = tmp_recreation_potential_categories,
- title = potential_title,
- categories = POTENTIAL_CATEGORY_LABELS,
- colors = POTENTIAL_COLORS,
- output_name = recreation_potential)
-
- # Infrastructure to access recreational facilities, amenities, services
- # Required for recreation opportunity and successively recreation spectrum
-
- if infrastructure and not any([recreation_opportunity,
- recreation_spectrum, demand, flow, supply]):
- msg = ("Infrastructure is not required "
- "to derive the 'potential' recreation map.")
- grass.warning(_(msg))
-
- if any([recreation_opportunity, recreation_spectrum, demand, flow, supply]):
-
- infrastructure_component = []
- infrastructure_components = []
-
- if infrastructure:
- infrastructure_component.append(infrastructure)
-
- '''Artificial surfaces (includung Roads)'''
-
- if artificial and roads:
-
- msg = "Roads distance categories: {c}"
- msg = msg.format(c=roads_distance_categories)
- grass.debug(_(msg))
- roads_proximity = compute_artificial_proximity(
- raster = roads,
- distance_categories = roads_distance_categories,
- output_name = roads_proximity_map_name)
-
- msg = "Artificial distance categories: {c}"
- msg = msg.format(c=artificial_distance_categories)
- grass.debug(_(msg))
- artificial_proximity = compute_artificial_proximity(
- raster = artificial,
- distance_categories = artificial_distance_categories,
- output_name = artificial_proximity_map_name)
-
- artificial_accessibility = compute_artificial_accessibility(
- artificial_proximity,
- roads_proximity,
- output_name = artificial_accessibility_map_name)
-
- infrastructure_components.append(artificial_accessibility)
-
- # merge infrastructure component related maps in one list
- infrastructure_component += infrastructure_components
-
- # # Recreational facilities, amenities, services
-
- # recreation_component = []
- # recreation_components = []
-
- # if recreation:
- # recreation_component.append(recreation)
-
- # # merge recreation component related maps in one list
- # recreation_component += recreation_components
-
- """ Recreation Spectrum """
-
- if any([recreation_spectrum, demand, flow, supply]):
-
- recreation_opportunity_component = []
-
- # input
- zerofy_and_normalise_component(
- components = infrastructure_component,
- threshhold = THRESHHOLD_ZERO,
- output_name = infrastructure_component_map_name)
-
- recreation_opportunity_component.append(
- infrastructure_component_map_name)
-
- # # input
- # zerofy_and_normalise_component(recreation_component,
- # THRESHHOLD_0001, recreation_component_map_name)
- # recreation_opportunity_component.append(recreation_component_map_name)
- # remove_at_exit.append(recreation_component_map_name)
-
- # intermediate
-
- # REVIEW --------------------------------------------------------------
- tmp_recreation_opportunity = tmp_map_name(
- name=recreation_opportunity_map_name)
- msg = "Computing intermediate opportunity map '{opportunity}'"
- grass.debug(_(msg.format(opportunity=tmp_recreation_opportunity)))
-
- grass.verbose(_("\nNormalize 'Recreation Opportunity' component\n"))
- grass.debug(_("Maps: {maps}".format(maps=recreation_opportunity_component)))
-
- zerofy_and_normalise_component(
- components = recreation_opportunity_component,
- threshhold = THRESHHOLD_0001,
- output_name = tmp_recreation_opportunity)
-
- # Why threshhold 0.0003? How and why it differs from 0.0001?
- # -------------------------------------------------------------- REVIEW
-
- msg = "Classifying '{opportunity}' map"
- grass.verbose(msg.format(opportunity=tmp_recreation_opportunity))
- del(msg)
-
- # recode opportunity_component
- tmp_recreation_opportunity_categories = tmp_map_name(
- name=recreation_opportunity)
-
- classify_recreation_component(
- component = tmp_recreation_opportunity,
- rules = RECREATION_OPPORTUNITY_CATEGORIES,
- output_name = tmp_recreation_opportunity_categories)
-
- ''' Recreation Opportunity [Output]'''
-
- if recreation_opportunity:
-
- # export 'recreation_opportunity' map and
- # use 'output_name' for the temporary 'potential' map for spectrum
- tmp_recreation_opportunity_categories = export_map(
- input_name = tmp_recreation_opportunity_categories,
- title = opportunity_title,
- categories = OPPORTUNITY_CATEGORY_LABELS,
- colors = OPPORTUNITY_COLORS,
- output_name = recreation_opportunity)
-
- # Recreation Spectrum: Potential + Opportunity [Output]
-
- if not recreation_spectrum and any([demand, flow, supply]):
- recreation_spectrum = tmp_map_name(name='recreation_spectrum')
- remove_at_exit.append(recreation_spectrum)
-
- recreation_spectrum = compute_recreation_spectrum(
- potential = tmp_recreation_potential_categories,
- opportunity = tmp_recreation_opportunity_categories,
- spectrum = recreation_spectrum)
-
- msg = "Writing '{spectrum}' map"
- msg = msg.format(spectrum=recreation_spectrum)
- grass.verbose(_(msg))
- del(msg)
- get_univariate_statistics(recreation_spectrum)
-
- # get category labels
- spectrum_categories = 'categories_of_'
- spectrum_categories += recreation_spectrum
- spectrum_category_labels = string_to_file(
- SPECTRUM_CATEGORY_LABELS,
- name=spectrum_categories)
-
- # add to list for removal
- remove_normal_files_at_exit.append(spectrum_category_labels)
-
- # update category labels, meta and colors
- spectrum_categories = 'categories_of_'
-
- r.category(map=recreation_spectrum,
- rules=spectrum_category_labels,
- separator=':')
-
- update_meta(recreation_spectrum, spectrum_title)
-
- r.colors(map=recreation_spectrum, rules='-', stdin = SPECTRUM_COLORS,
- quiet=True)
-
- if base_vector:
- update_vector(vector=base_vector,
- raster=recreation_spectrum,
- methods=METHODS,
- column_prefix='spectrum')
-
- """Valuation Tables"""
-
- if any([demand, flow, supply, aggregation]):
-
- '''Highest Recreation Spectrum == 9'''
-
- expression = "if({spectrum} == {highest_recreation_category}, {spectrum}, null())"
- highest_spectrum_expression = expression.format(
- spectrum=recreation_spectrum,
- highest_recreation_category=HIGHEST_RECREATION_CATEGORY)
- highest_spectrum_equation = equation.format(result=highest_spectrum,
- expression=highest_spectrum_expression)
- r.mapcalc(highest_spectrum_equation, overwrite=True)
-
- '''Distance map'''
-
- distance_to_highest_spectrum = tmp_map_name(name=highest_spectrum)
- r.grow_distance(input=highest_spectrum,
- distance=distance_to_highest_spectrum,
- metric=metric,
- quiet=True,
- overwrite=True)
-
- '''Distance categories'''
-
- distance_categories_to_highest_spectrum = 'categories_of_'
- distance_categories_to_highest_spectrum += distance_to_highest_spectrum
- remove_at_exit.append(distance_categories_to_highest_spectrum) # FIXME
-
- recode_map(raster=distance_to_highest_spectrum,
- rules=spectrum_distance_categories,
- colors=SCORE_COLORS,
- output=distance_categories_to_highest_spectrum)
-
- spectrum_distance_category_labels = string_to_file(
- SPECTRUM_DISTANCE_CATEGORY_LABELS,
- name=distance_categories_to_highest_spectrum)
- remove_normal_files_at_exit.append(spectrum_distance_category_labels)
-
- r.category(map=distance_categories_to_highest_spectrum,
- rules=spectrum_distance_category_labels,
- separator=':')
-
- '''Combine Base map and Distance Categories'''
-
- tmp_crossmap = tmp_map_name(name=crossmap)
- r.cross(input=(distance_categories_to_highest_spectrum, base),
- flags='z',
- output=tmp_crossmap,
- quiet=True)
-
- grass.use_temp_region() # to safely modify the region
- g.region(nsres=population_ns_resolution,
- ewres=population_ew_resolution,
- flags='a') # Resolution should match 'population' FIXME
- msg = "|! Computational extent & resolution matched to {raster}"
- msg = msg.format(raster=landuse)
- grass.verbose(_(msg))
-
- # if info:
- # population_statistics = get_univariate_statistics(population)
- # population_total = population_statistics['sum']
- # msg = "|i Population statistics: {s}".format(s=population_total)
- # g.message(_(msg))
-
- '''Demand Distribution'''
-
- if any([flow, supply, aggregation]) and not demand:
- demand = tmp_map_name(name='demand')
-
- r.stats_zonal(base=tmp_crossmap,
- flags='r',
- cover=population,
- method='sum',
- output=demand,
- overwrite=True,
- quiet=True)
-
- # ------------------------------------------- REMOVEME
- # if info:
- # r.report(map=demand, units=('k','c','p'))
- # ------------------------------------------- REMOVEME
-
- # copy 'reclassed' as 'normal' map (r.mapcalc)
- # so as to enable removal of it and its 'base' map
- demand_copy = demand + '_copy'
- copy_expression = "{input_raster}"
- copy_expression = copy_expression.format(input_raster=demand)
- copy_equation = equation.format(result=demand_copy,
- expression=copy_expression)
- r.mapcalc(copy_equation, overwrite=True)
-
- # remove the reclassed map 'demand'
- g.remove(flags='f', type='raster', name=demand, quiet=True)
-
- # rename back to 'demand'
- g.rename(raster=(demand_copy,demand), quiet=True)
-
- if demand and base_vector:
- update_vector(vector=base_vector,
- raster=demand,
- methods=METHODS,
- column_prefix='demand')
-
- '''Unmet Demand'''
-
- if unmet_demand:
-
- # compute unmet demand
-
- unmet_demand_expression = compute_unmet_demand(
- distance=distance_categories_to_highest_spectrum,
- constant=MOBILITY_CONSTANT,
- coefficients=MOBILITY_COEFFICIENTS[4],
- population=demand,
- score=MOBILITY_SCORE)
- # suitability=suitability) # Not used.
- # Maybe it can, though, after successfully testing its
- # integration to build_distance_function().
-
- grass.debug(_("Unmet demand function: {f}".format(f=unmet_demand_expression)))
-
- unmet_demand_equation = equation.format(result=unmet_demand,
- expression=unmet_demand_expression)
- r.mapcalc(unmet_demand_equation, overwrite=True)
-
- if base_vector:
- update_vector(vector=base_vector,
- raster=unmet_demand,
- methods=METHODS,
- column_prefix='unmet')
-
- '''Mobility function'''
-
- if not flow and any([supply, aggregation]):
-
- flow = flow_map_name
- remove_at_exit.append(flow)
-
- if flow or any ([supply, aggregation]):
-
- mobility_expression = mobility_function(
- distance=distance_categories_to_highest_spectrum,
- constant=MOBILITY_CONSTANT,
- coefficients=MOBILITY_COEFFICIENTS,
- population=demand,
- score=MOBILITY_SCORE)
- # suitability=suitability) # Not used.
- # Maybe it can, though, after successfully testing its
- # integration to build_distance_function().
-
- msg = "Mobility function: {f}"
- grass.debug(_(msg.format(f=mobility_expression)))
- del(msg)
-
- '''Flow map'''
-
- mobility_equation = equation.format(result=flow,
- expression=mobility_expression)
- r.mapcalc(mobility_equation, overwrite=True)
-
- if base_vector:
- update_vector(vector=base_vector,
- raster=flow_map_name,
- methods=METHODS,
- column_prefix='flow')
-
- '''Supply Table'''
-
- if aggregation:
-
- supply_parameters = {}
-
- if supply:
- supply_parameters.update({'supply_filename': supply})
-
- if use:
- supply_parameters.update({'use_filename': use})
-
- if base_vector:
- supply_parameters.update({'vector': base_vector})
-
- compute_supply(
- base = landcover,
- recreation_spectrum = recreation_spectrum,
- highest_spectrum = highest_spectrum,
- base_reclassification_rules = landcover_reclassification_rules,
- reclassified_base = maes_ecosystem_types,
- reclassified_base_title = 'MAES ecosystem types',
- flow = flow,
- flow_map_name = flow_map_name,
- aggregation = aggregation,
- ns_resolution = population_ns_resolution,
- ew_resolution = population_ew_resolution,
- **supply_parameters)
-
- # restore region
- if landuse_extent:
- grass.del_temp_region() # restoring previous region settings
- grass.verbose("Original Region restored")
-
- # print citation
- if info:
- citation = 'Citation: ' + citation_recreation_potential
- g.message(citation)
-
-if __name__ == "__main__":
- options, flags = grass.parser()
- atexit.register(cleanup)
- sys.exit(main())
Added: grass-addons/grass7/raster/r.estimap.recreation/requirements-dev.txt
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/requirements-dev.txt (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/requirements-dev.txt 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1 @@
+pytest >= 4.0
Added: grass-addons/grass7/raster/r.estimap.recreation/setup.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/setup.py (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/setup.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+import os
+import sys
+
+from setuptools import setup, find_packages
+
+os.chdir(os.path.dirname(sys.argv[0]) or ".")
+
+with open("README.md", "r") as fh:
+ long_description = fh.read()
+
+setup(
+ name="r.estimap.recreation",
+ version="3",
+ description="Implementation of ESTIMAP recreation as a GRASS GIS add-on",
+ long_description=long_description,
+ url="https://gitlab.com/natcapes/r.estimap.recreation",
+ author="Nikos Alexandris",
+ author_email="nik at nikosalexandris.net",
+ # list of valid classifiers
+ # https://pypi.python.org/pypi?%3Aaction=list_classifiers
+ classifiers=[
+ "Development Status :: 3 - Beta",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 3",
+ "License :: EUPL v 1.2 :: GNU General Public License v3 or later (GPLv3+)",
+ ],
+ packages=find_packages(),
+)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/spectrum.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/spectrum_high_provision_near.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/test.r.estimap.recreation.py
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/test.r.estimap.recreation.py 2019-02-28 20:51:39 UTC (rev 74142)
+++ grass-addons/grass7/raster/r.estimap.recreation/test.r.estimap.recreation.py 2019-03-01 11:47:49 UTC (rev 74143)
@@ -1,205 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
-Name Tests on ...
-Purpose Test for no difference between the input and output raster maps
-after recoding based on a set of pre-defind rules
-
-License (C) 2018 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: Nikos Alexandris
-"""
-
-"""Libraries"""
-
-from grass.gunittest.case import TestCase
-from grass.gunittest.gmodules import SimpleModule
-import grass.script as g
-
-import restimap as restimap
-import tempfile
-
-"""Globals"""
-
-# PRECISION=[0.1, 0.01, 0.001]
-
-CORINE_LAND_COVER_CLASSES="""
-north: 1
-south: 0
-east: 45
-west: 0
-rows: 1
-cols: 45
-null: -1
-type: int
-multiplier: 1
-
-1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45"""
-# print "CORINE land cover classes:", CORINE_LAND_COVER_CLASSES
-corine_input='corine_input'
-
-CORINE_LAND_COVER_CLASSES_MINIMUM=1
-# print "Minimum category integer for CORINE land cover class :", CORINE_LAND_COVER_CLASSES_MINIMUM
-
-CORINE_LAND_COVER_CLASSES_MAXIMUM=48
-# print "Maximum category integer for CORINE land cover class:", CORINE_LAND_COVER_CLASSES_MAXIMUM
-
-CORINE_LAND_COVER_CLASSES_SUITABILITY_SCORES="""
-north: 1
-south: 0
-east: 45
-west: 0
-rows: 1
-cols: 45
-null: -1
-type: dcell
-multiplier: 1
-
-0 0.1 0 0 0 0 0 0 0 1 0.1 0.3 0.3 0.4 0.5 0.5 0.5 0.6 0.3 0.3 0.6 0.6 1 0.8 1 0.8 0.8 0.8 0.8 1 0.8 0.7 0 0.8 1 0.8 1 0.8 1 1 1 1 0.8 1 0.3"""
-# print "Suitability scores map:", CORINE_LAND_COVER_CLASSES_SUITABILITY_SCORES
-
-suitability_map='suitability_map'
-corine_recoded='corine_recoded'
-
-"""Test Case Class"""
-
-# def recode_map(raster, rules, colors, output):
-
-class TestCORINE(TestCase):
-
- gisenv = SimpleModule('g.gisenv', get='MAPSET')
- TestCase.runModule(gisenv, expecting_stdout=True)
- print "Mapset: ", gisenv.outputs.stdout.strip()
-
- # TODO: replace by unified handing of maps
- to_remove = []
-
- # glist = SimpleModule('g.list',
- # type='raster',
- # mapset='.',
- # flags='p')
-
- # TestCase.runModule(glist, expecting_stdout=True)
- # print glist.outputs.stdout.strip()
-
- filename = tempfile.TemporaryFile(mode='w+b',
- suffix='',
- prefix='tmp',
- dir=None)
- print "Filename:", filename
-
- corine_input = 'corine_land_cover_classes.ascii'
- suitability_map = 'suitability_scores_for_corine.ascii'
- suitability_rules = 'suitability_of_corine_land_cover_classes.scores'
-
- @classmethod
- def setUpClass(cls):
- """
- """
-
- try:
- print "Trying to open file and write content"
- ascii_file = open(cls.filename, "w")
- ascii_file.write("Purchase Amount")
- except IOError as e:
- print "IOError:", e
- return
- finally:
- print "Success -- Closing file"
- ascii_file.close()
-
- # use a temporary region
- print "Use a temporary region"
- cls.use_temp_region()
-
- # # create input raster maps
- print "Import CORINE land cover class nomenclature"
- print "Input map name:", cls.corine_input
- cls.runModule('r.in.ascii',
- input=cls.corine_input,
- output=corine_input,
- overwrite=True,
- verbose=True)
-
- print "Import suitability scores map"
- cls.runModule('r.in.ascii',
- input=cls.suitability_map,
- output=suitability_map,
- overwrite=True,
- verbose=True)
-
- # append them in list "to_remove"
- print "Add imported maps in list to remove"
- cls.to_remove.append(corine_input)
- cls.to_remove.append(suitability_map)
-
- # set region to map(s)
- cls.runModule('g.region', raster=corine_input, flags='p')
-
- def test_recode_map(self):
- """
- """
- restimap.recode_map(raster=corine_input,
- rules=cls.suitability_rules,
- output=corine_recoded)
-
- @classmethod
- def tearDownClass(cls):
-
- """
- Remove temporary region and test raster maps
- """
- cls.del_temp_region()
- print
- print "Removing test raster maps:\n"
- print ', '.join(cls.to_remove)
- if cls.to_remove:
- cls.runModule('g.remove', flags='f', type='raster',
- name=','.join(cls.to_remove), verbose=True)
-
- def tearDown(self):
- """
- ...
- """
- pass
-
- def test_corine_range(self):
- """
- Test for range of Hue, Intensity and Saturation
- """
- self.assertRasterMinMax(map=corine,
- refmin=CORINE_MINIMUM,
- refmax=CORINE_MAXIMUM,
- msg=None)
-
- def test_difference(self):
- """
- Test for no or minimal differences between
- """
- # assertRastersNoDifference(actual, reference, precision, statistics=None, msg=None)
-
- self.assertRastersNoDifference(actual=corine_recoded,
- reference=corine_input,
- precision=precision)
-
- info = SimpleModule('r.info', flags='r', map=corine_input)
- TestCase.runModule(info, expecting_stdout=True)
- corine_input_line = [corine_input] + info.outputs.stdout.splitlines()
-
- info = SimpleModule('r.info', flags='r', map=corine_recoded)
- TestCase.runModule(info, expecting_stdout=True)
- corine_recoded_line = [corine_recoded] + info.outputs.stdout.splitlines()
-
- # inform
-
- for row in corine_input_line, corine_recoded_line:
- print("{: >20} {: >25} {: >20}".format(*row))
-
- print
-
-if __name__ == '__main__':
- from grass.gunittest.main import test
- test()
Added: grass-addons/grass7/raster/r.estimap.recreation/test_integration.sh
===================================================================
--- grass-addons/grass7/raster/r.estimap.recreation/test_integration.sh (rev 0)
+++ grass-addons/grass7/raster/r.estimap.recreation/test_integration.sh 2019-03-01 11:47:49 UTC (rev 74143)
@@ -0,0 +1,97 @@
+#!/bin/bash -
+#===============================================================================
+#
+# FILE: test_integration_x.sh
+#
+# USAGE: ./test_integration_x.sh
+#
+# DESCRIPTION:
+#
+# OPTIONS: ---
+# REQUIREMENTS: ---
+# BUGS: ---
+# NOTES: First implementation by pmav99
+# AUTHOR: Nikos Alexandris (), nik at nikosalexandris.net
+# ORGANIZATION:
+# CREATED: 02/08/2019 12:48
+# REVISION: ---
+#===============================================================================
+
+# set -o nounset # Treat unset variables as an error
+set -xeuo pipefail
+
+# Map and file names of interest
+map_names=( demand flow spectrum unmet_demand potential opportunity flow_corine_land_cover_2006 maes_ecosystem_types maes_ecosystem_types_flow )
+csv_names=( supply.csv use.csv )
+
+# ------------------- FIXME: check if unnecessarily querying any input maps ---
+# # Query existing maps
+# for name in "${map_names[@]}" ;do
+# mv -f master."${name}" /tmp
+# r.univar "${name}" > master."${name}"
+# done
+
+# csv_names=( supply.csv use.csv )
+# for name in "${csv_names[@]}" ;do
+# echo "${name}"
+# mv -f master."${name}" /tmp
+# cp "${name}" master."${name}"
+# done
+# -----------------------------------------------------------------------------
+
+# First grassy things first
+g.region raster=area_of_interest -p
+
+# Clean output maps from previous run(s)
+g.remove \
+ -f -b \
+ type=raster \
+ name=demand,flow,maes_ecosystem_types,maes_ecosystem_types_flow,flow_corine_land_cover_2006,opportunity,potential,potential_1,potential_2,potential_3,potential_4,recreation_opportunity,spectrum,highest_recreation_spectrum,demand,unmet,unmet_demand,mobility,crossmap
+
+# Re-run the module
+$GRASS_PYTHON r.estimap.recreation/r.estimap.recreation.py \
+ --verbose \
+ --overwrite \
+ mask=area_of_interest \
+ land=land_suitability \
+ water=water_resources,bathing_water_quality \
+ natural=protected_areas \
+ infrastructure=distance_to_infrastructure \
+ potential=potential \
+ opportunity=opportunity \
+ spectrum=spectrum \
+ demand=demand \
+ unmet=unmet_demand \
+ flow=flow \
+ population=population_2015 \
+ base=local_administrative_units \
+ landcover=corine_land_cover_2006 \
+ aggregation=regions \
+ land_classes=corine_accounting_to_maes_land_classes.rules \
+ supply=supply \
+ use=use
+
+# compare 'master' (old) with 'current' (new) maps
+for name in "${map_names[@]}" ;do
+ # remove 'old'
+ touch current."${name}"
+ mv -f current."${name}" /tmp
+ # create 'new'
+ echo "${name}"
+ r.univar "${name}" > current."${name}"
+ # compare
+ diff master."${name}" current."${name}"
+ echo
+done
+
+for name in "${csv_names[@]}" ;do
+ # remove 'old'
+ touch current."${name}"
+ mv -f current."${name}" /tmp
+ # create 'new' from the module's last run
+ echo "${name}"
+ mv "${name}" current."${name}"
+ # compare
+ diff master."${name}" current."${name}"
+ echo
+done
Property changes on: grass-addons/grass7/raster/r.estimap.recreation/test_integration.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Deleted: grass-addons/grass7/raster/r.estimap.recreation/unmet_demand.png
===================================================================
(Binary files differ)
Deleted: grass-addons/grass7/raster/r.estimap.recreation/water_resources.png
===================================================================
(Binary files differ)
More information about the grass-commit
mailing list