diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml
index 15c2d6f..e579a8b 100644
--- a/.github/workflows/black.yml
+++ b/.github/workflows/black.yml
@@ -1,3 +1,4 @@
+---
name: Python code style check with black
on: [push]
@@ -8,13 +9,13 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
- - name: Install apt dependencies
- run: |
- sudo apt-get update && sudo apt-get install python3 python3-pip -y
- - name: Install pip dependencies
- run: |
- pip3 install black==23.1.0
- - name: Check code style with Black
- run: |
- black --check --diff --line-length 79 .
+ - uses: actions/checkout@v4
+ - name: Install apt dependencies
+ run: |
+ sudo apt-get update && sudo apt-get install python3 python3-pip -y
+ - name: Install pip dependencies
+ run: |
+ pip3 install black==23.12.0
+ - name: Check code style with Black
+ run: |
+ black --check --diff --line-length 79 .
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index b518e99..8975c57 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -1,3 +1,4 @@
+---
name: Python Flake8 Code Quality
on: [push]
@@ -8,17 +9,20 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
- - name: Install apt dependencies
- run: |
- sudo apt-get update && sudo apt-get install python3 python3-pip -y
- - name: Install pip dependencies
- run: |
- pip3 install flake8 pylint
- - name: Lint with Flake8
- run: |
- # E402: module level import not at top of file
- flake8 --ignore=E265,F821,E501,W503,E203,E402 --max-line-length=80 --count --statistics --show-source .
- # - name: Lint with Pylint
- # run: |
- # pylint --disable=R,bad-continuation,fixme,import-error --additional-builtins=_ --reports=n --score=n -j0 ${{ github.event.repository.name }}.py
+ - uses: actions/checkout@v4
+ - name: Install apt dependencies
+ run: |
+ sudo apt-get update && sudo apt-get install python3 python3-pip -y
+ - name: Install pip dependencies
+ run: |
+ pip3 install flake8 pylint
+ - name: Lint with Flake8
+ run: |
+ # E402: module level import not at top of file
+ flake8 --ignore=E265,F821,E501,W503,E203,E402 --max-line-length=80 \
+ --count --statistics --show-source .
+ # - name: Lint with Pylint
+ # run: |
+ # pylint --disable=R,bad-continuation,fixme,import-error \
+ # --additional-builtins=_ --reports=n --score=n \
+ # -j0 ${{ github.event.repository.name }}.py
diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml
index 6f4fa3e..9587cce 100644
--- a/.github/workflows/super-linter.yml
+++ b/.github/workflows/super-linter.yml
@@ -1,8 +1,8 @@
+---
name: General linting
on:
- push
- - pull_request
jobs:
super-linter:
diff --git a/Dockerfile b/Dockerfile
index ce02cee..5c45750 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@ ENV GRASS_ADDON_BASE=/usr/local/grass84
# install external dependencies
# RUN apt install musl-dev ??
-RUN pip3 install py7zr tqdm requests psutil scikit-learn pyproj
+RUN pip3 install py7zr tqdm requests psutil scikit-learn pyproj pandas
# install official addons
RUN grass --tmp-location EPSG:4326 --exec g.extension r.mapcalc.tiled -s
diff --git a/README.md b/README.md
index d143d4c..2fb22d1 100644
--- a/README.md
+++ b/README.md
@@ -1,72 +1,75 @@
# rvr_interface
+
Repo for code and script transfer between mundialis and RVR - GRASS GIS addons:
- **m.import.rvr** imports data for the processing of gebaeudedetektion,
-dachbegruenung and/or einzelbaumerkennung.
+ dachbegruenung and/or einzelbaumerkennung.
- **r.import.dtm_nrw** downloads and imports the NRW digital terrain model
-(DTM) 1m into the current mapset. Only the extent of the current region is
-downloaded and imported with a 1m resolution.
+ (DTM) 1m into the current mapset. Only the extent of the current region is
+ downloaded and imported with a 1m resolution.
- **r.import.ndsm_nrw** calculates an nDSM by subtracting input digital terrain
-model (DTM) data (defined by the dtm parameter) from an input DSM
-indicated by the dsm parameter. If no DTM is defined, NRW DTM data
-is automatically imported using r.import.dtm_nrw.
+ model (DTM) data (defined by the dtm parameter) from an input DSM
+ indicated by the dsm parameter. If no DTM is defined, NRW DTM data
+ is automatically imported using r.import.dtm_nrw.
- **r.in.pdal.worker** is a worker addon for r.in.pdal and is used in
-m.import.rvr.
-
+ m.import.rvr.
- **m.analyse.buildings**
+
- **r.extract.buildings** extracts buildings as vectors and calculates height
- statistics (minimum, maximum, average, standard deviation, median,
- percentile) and presumable number of stories using an nDSM-raster,
- NDVI-raster, and FNK-vector (Flaechennutzungskatalog).
+ statistics (minimum, maximum, average, standard deviation, median,
+ percentile) and presumable number of stories using an nDSM-raster,
+ NDVI-raster, and FNK-vector (Flaechennutzungskatalog).
- **r.extract.buildings.worker** is a worker module that is started by
-r.extract.buildings.
+ r.extract.buildings.
- **v.cd.areas** calculates differences between two vector layers
-(e.g. classification and reference) by making use of v.overlay with operator
-"xor". Only differences with a defined minimum size are extracted.
+ (e.g. classification and reference) by making use of v.overlay with operator
+ "xor". Only differences with a defined minimum size are extracted.
- **v.cd.areas.worker** is a worker module that is started by
-v.cd.areas.
+ v.cd.areas.
- **r.extract.greenroofs** extracts vegetated roofs from aerial photographs,
- an nDSM, a building vector layer and optionally an FNK
- (Flaechennutzungskatalog) and tree vector layer.
+ an nDSM, a building vector layer and optionally an FNK
+ (Flaechennutzungskatalog) and tree vector layer.
- **r.extract.greenroofs.worker** is a worker module that is started by
-r.extract.greenroofs.
-
+ r.extract.greenroofs.
- **m.analyse.trees**
+
- **r.trees.peaks** assigns pixels to nearest peak (tree crown).
- **r.trees.mltrain** generates training data for a machine learning (ML)
- model to detect trees and trains the model with these training data.
+ model to detect trees and trains the model with these training data.
- **r.trees.mlapply** applies the tree classification model
-in parallel to the area of interest (current region).
+ in parallel to the area of interest (current region).
- **r.trees.mlapply.worker** applies classification model for a region
-defined by a vector. This module should not be called directly, instead
-it is called in parallel by r.trees.mlapply.
+ defined by a vector. This module should not be called directly, instead
+ it is called in parallel by r.trees.mlapply.
- **r.trees.postprocess** generates single tree delineations from tree pixels
- and geomorphological peaks.
+ and geomorphological peaks.
- **v.trees.param** calculates various tree parameters for tree crowns given
- as input vector map treecrowns.
+ as input vector map treecrowns.
- **v.trees.param.worker** is used within v.trees.param to calculate various tree parameters
- for tree crowns in parallel.
+ for tree crowns in parallel.
- **v.trees.species** classifies trees in deciduous and coniferous trees.
- **v.trees.cd** calculates the change between two given treecrown vector
- maps (inp_t1 and inp_t2 for time t1 and t2, respectively).
+ maps (inp_t1 and inp_t2 for time t1 and t2, respectively).
- **v.trees.cd.worker** is a worker module that is started by
- v.trees.cd.
+ v.trees.cd.
## Building and running a docker image
In the folder with the Dockerfile, run
+
```bash
docker build -t rvr_interface:latest .
```
Instead of "latest", a version number can be used. This should create a local
docker image with all needed addons and dependencies. Once the docker image
-has been created locally, it can be started with e.g.
+has been created locally, it can be started on Linux with e.g.
+
```bash
xhost local:*
docker run -it --privileged --rm --ipc host \
@@ -77,3 +80,31 @@ docker run -it --privileged --rm --ipc host \
--device="/dev/dri/card0:/dev/dri/card0" \
rvr_interface:latest bash
```
+
+On Windows you need to do the following before starting the docker container:
+
+1. Install Docker Desktop
+2. Download and install [VcXsrv Windows X Server](https://sourceforge.net/projects/vcxsrv/)
+3. Start **Xlaunch** and configure it (see [here](https://dev.to/darksmile92/run-gui-app-in-linux-docker-container-on-windows-host-4kde)):
+ - in the "Extra Settings" window enable "Disable access control"
+ - in the "Finish Configuration" window click "Save configuration" and save it e.g. on the desktop
+
+Now you can run the docker:
+
+```bash
+# get own IP adress (take the value of IPAdress e.g. 10.211.55.10 and not 127.0.0.1)
+Get-NetIPAddress
+# or
+ipconfig
+
+# set DISPLAY variable (set )
+set-variable -name DISPLAY -value :0.0
+
+# start Docker
+docker run -it --privileged --rm --ipc host \
+ -v C:/Users/path/to/grassdata:/grassdb \
+ -v C:/Users/path/to/rvr_daten:/mnt/data \
+ --env DISPLAY=$DISPLAY \
+ --device="/dev/dri/card0:/dev/dri/card0" \
+ rvr_interface:latest bash
+```
diff --git a/grass-gis-addons/m.analyse.buildings/r.extract.buildings.worker/r.extract.buildings.worker.py b/grass-gis-addons/m.analyse.buildings/r.extract.buildings.worker/r.extract.buildings.worker.py
index 9171d8c..ec9eb7f 100644
--- a/grass-gis-addons/m.analyse.buildings/r.extract.buildings.worker/r.extract.buildings.worker.py
+++ b/grass-gis-addons/m.analyse.buildings/r.extract.buildings.worker/r.extract.buildings.worker.py
@@ -453,21 +453,21 @@ def main():
except Exception:
grass.fatal("m.analyse.buildings library is not installed")
- ndsm = options["ndsm"]
- ndvi = options["ndvi_raster"]
+ ndsm = options["ndsm"].split("@")[0]
+ ndvi = options["ndvi_raster"].split("@")[0]
min_size = options["min_size"]
max_fd = options["max_fd"]
ndvi_thresh = options["ndvi_thresh"]
memory = options["memory"]
output = options["output"]
new_mapset = options["new_mapset"]
- area = options["area"]
+ area = options["area"].split("@")[0]
if options["fnk_vector"]:
- fnk_vect = options["fnk_vector"]
+ fnk_vect = options["fnk_vector"].split("@")[0]
fnk_column = options["fnk_column"]
elif options["fnk_raster"]:
- fnk_rast = options["fnk_raster"]
+ fnk_rast = options["fnk_raster"].split("@")[0]
grass.message(_(f"Applying building extraction to region {area}..."))
@@ -478,8 +478,10 @@ def main():
ndsm += f"@{old_mapset}"
ndvi += f"@{old_mapset}"
if options["fnk_vector"]:
+ fnk_name = fnk_vect
fnk_vect += f"@{old_mapset}"
if options["fnk_raster"]:
+ fnk_name = fnk_rast
fnk_rast += f"@{old_mapset}"
grass.run_command(
@@ -511,13 +513,13 @@ def main():
# copy FNK to temporary mapset
if options["fnk_vector"]:
- fnk_vect_tmp = f'{options["fnk_vector"]}_{os.getpid()}'
+ fnk_vect_tmp = f"{fnk_name}_{os.getpid()}"
rm_vectors.append(fnk_vect_tmp)
grass.run_command(
"g.copy", vector=f"{fnk_vect},{fnk_vect_tmp}", quiet=True
)
elif options["fnk_raster"]:
- fnk_rast_tmp = f'{options["fnk_raster"]}_{os.getpid()}'
+ fnk_rast_tmp = f"{fnk_name}_{os.getpid()}"
rm_rasters.append(fnk_rast_tmp)
grass.run_command(
"g.copy", raster=f"{fnk_rast},{fnk_rast_tmp}", quiet=True
diff --git a/grass-gis-addons/m.analyse.buildings/r.extract.buildings/r.extract.buildings.py b/grass-gis-addons/m.analyse.buildings/r.extract.buildings/r.extract.buildings.py
index 6890e32..f0d9973 100644
--- a/grass-gis-addons/m.analyse.buildings/r.extract.buildings/r.extract.buildings.py
+++ b/grass-gis-addons/m.analyse.buildings/r.extract.buildings/r.extract.buildings.py
@@ -330,10 +330,18 @@ def main():
msg = proc.outputs["stderr"].value.strip()
grass.message(_(f"\nLog of {proc.get_bash()}:"))
for msg_part in msg.split("\n"):
- grass.message(_(msg_part))
+ if msg_part != "":
+ grass.message(_(msg_part))
# create mapset dict based on Log, so that only those with output are listed
if "Skipping..." not in msg:
- tile_output = re.search(r"Output is:\n<(.*?)>", msg).groups()[0]
+ try:
+ # for execution in terminal
+ tile_output = re.search(r"Output is:\n<(.*?)>", msg).groups()[
+ 0
+ ]
+ except Exception:
+ # for execution in GUI
+ tile_output = re.search(r"Output is: <(.*?)>", msg).groups()[0]
output_list.append(tile_output)
# verify that switching back to original mapset worked
diff --git a/grass-gis-addons/m.analyse.buildings/r.extract.greenroofs.worker/r.extract.greenroofs.worker.py b/grass-gis-addons/m.analyse.buildings/r.extract.greenroofs.worker/r.extract.greenroofs.worker.py
index 474d4e6..4a1fc85 100644
--- a/grass-gis-addons/m.analyse.buildings/r.extract.greenroofs.worker/r.extract.greenroofs.worker.py
+++ b/grass-gis-addons/m.analyse.buildings/r.extract.greenroofs.worker/r.extract.greenroofs.worker.py
@@ -237,15 +237,43 @@ def main():
new_mapset = options["new_mapset"]
gisrc, newgisrc, old_mapset = switch_to_new_mapset(new_mapset)
- area = f"{options['area']}@{old_mapset}"
+ area = (
+ f"{options['area']}@{old_mapset}"
+ if "@" not in options["area"]
+ else options["area"]
+ )
num = options["area"].rsplit("_", 1)[1]
- building_outlines = f"{options['building_outlines']}@{old_mapset}"
+ building_outlines = (
+ f"{options['building_outlines']}@{old_mapset}"
+ if "@" not in options["building_outlines"]
+ else options["building_outlines"]
+ )
buildings = f"{options['buildings']}@{old_mapset}"
- ndsm = f"{options['ndsm']}@{old_mapset}"
- ndvi = f"{options['ndvi']}@{old_mapset}"
- green_blue_ratio = f"{options['gb_ratio']}@{old_mapset}"
- red_green_ratio = f"{options['rg_ratio']}@{old_mapset}"
- brightness = f"{options['brightness']}@{old_mapset}"
+ ndsm = (
+ f"{options['ndsm']}@{old_mapset}"
+ if "@" not in options["ndsm"]
+ else options["ndsm"]
+ )
+ ndvi = (
+ f"{options['ndvi']}@{old_mapset}"
+ if "@" not in options["ndvi"]
+ else options["ndvi"]
+ )
+ green_blue_ratio = (
+ f"{options['gb_ratio']}@{old_mapset}"
+ if "@" not in options["gb_ratio"]
+ else options["gb_ratio"]
+ )
+ red_green_ratio = (
+ f"{options['rg_ratio']}@{old_mapset}"
+ if "@" not in options["rg_ratio"]
+ else options["rg_ratio"]
+ )
+ brightness = (
+ f"{options['brightness']}@{old_mapset}"
+ if "@" not in options["brightness"]
+ else options["brightness"]
+ )
min_veg_size = float(options["min_veg_size"])
min_veg_proportion = int(options["min_veg_proportion"])
output_vegetation = options["output_vegetation"]
diff --git a/grass-gis-addons/m.analyse.buildings/v.cd.areas/v.cd.areas.py b/grass-gis-addons/m.analyse.buildings/v.cd.areas/v.cd.areas.py
index d1a6fb7..5cfa186 100644
--- a/grass-gis-addons/m.analyse.buildings/v.cd.areas/v.cd.areas.py
+++ b/grass-gis-addons/m.analyse.buildings/v.cd.areas/v.cd.areas.py
@@ -322,10 +322,18 @@ def main():
msg = proc.outputs["stderr"].value.strip()
grass.message(_(f"\nLog of {proc.get_bash()}:"))
for msg_part in msg.split("\n"):
- grass.message(_(msg_part))
+ if msg_part != "":
+ grass.message(_(msg_part))
# create mapset dict based on Log, so that only those with output are listed
if "Skipping..." not in msg:
- tile_output = re.search(r"Output is:\n<(.*?)>", msg).groups()[0]
+ try:
+ # for execution in terminal
+ tile_output = re.search(r"Output is:\n<(.*?)>", msg).groups()[
+ 0
+ ]
+ except Exception:
+ # for execution in GUI
+ tile_output = re.search(r"Output is: <(.*?)>", msg).groups()[0]
output_list.append(tile_output)
if flags["q"]:
area_identified = re.search(
diff --git a/grass-gis-addons/m.analyse.trees/r.trees.mlapply.worker/r.trees.mlapply.worker.py b/grass-gis-addons/m.analyse.trees/r.trees.mlapply.worker/r.trees.mlapply.worker.py
index 0dd22c2..6af1ed7 100644
--- a/grass-gis-addons/m.analyse.trees/r.trees.mlapply.worker/r.trees.mlapply.worker.py
+++ b/grass-gis-addons/m.analyse.trees/r.trees.mlapply.worker/r.trees.mlapply.worker.py
@@ -81,8 +81,8 @@ def main():
except Exception:
grass.fatal("m.analyse.trees library is not installed")
- area = options["area"]
- group = options["group"]
+ area = options["area"].split("@")[0]
+ group = options["group"].split("@")[0]
output = options["output"]
model = options["model"]
new_mapset = options["new_mapset"]
diff --git a/grass-gis-addons/m.analyse.trees/r.trees.mltrain/r.trees.mltrain.py b/grass-gis-addons/m.analyse.trees/r.trees.mltrain/r.trees.mltrain.py
index 5eb470b..2bc2655 100644
--- a/grass-gis-addons/m.analyse.trees/r.trees.mltrain/r.trees.mltrain.py
+++ b/grass-gis-addons/m.analyse.trees/r.trees.mltrain/r.trees.mltrain.py
@@ -229,6 +229,7 @@ def main():
blue = options["blue_raster"]
nir = options["nir_raster"]
ndvi = options["ndvi_raster"]
+ ndvi_split = ndvi.split("@")[0]
ndwi = options["ndwi_raster"]
ndgb = options["ndgb_raster"]
ndsm = options["ndsm"]
@@ -280,7 +281,7 @@ def main():
grass.run_command(
"r.neighbors",
input=ndvi,
- output=f"{ndvi}_min1",
+ output=f"{ndvi_split}_min1",
size=3,
method="minimum",
nprocs=nprocs,
@@ -288,8 +289,8 @@ def main():
)
grass.run_command(
"r.neighbors",
- input=f"{ndvi}_min1",
- output=f"{ndvi}_min2",
+ input=f"{ndvi_split}_min1",
+ output=f"{ndvi_split}_min2",
size=3,
method="minimum",
nprocs=nprocs,
@@ -297,8 +298,8 @@ def main():
)
grass.run_command(
"r.neighbors",
- input=f"{ndvi}_min2",
- output=f"{ndvi}_max1",
+ input=f"{ndvi_split}_min2",
+ output=f"{ndvi_split}_max1",
size=3,
method="maximum",
nprocs=nprocs,
@@ -306,20 +307,20 @@ def main():
)
grass.run_command(
"r.neighbors",
- input=f"{ndvi}_max1",
- output=f"{ndvi}_max2",
+ input=f"{ndvi_split}_max1",
+ output=f"{ndvi_split}_max2",
size=3,
method="maximum",
nprocs=nprocs,
memory=memory_max100mb,
)
- rm_rasters.append(f"{ndvi}_min1")
- rm_rasters.append(f"{ndvi}_min2")
- rm_rasters.append(f"{ndvi}_max1")
- rm_rasters.append(f"{ndvi}_max2")
+ rm_rasters.append(f"{ndvi_split}_min1")
+ rm_rasters.append(f"{ndvi_split}_min2")
+ rm_rasters.append(f"{ndvi_split}_max1")
+ rm_rasters.append(f"{ndvi_split}_max2")
grass.mapcalc(
- f"trees_pixel_ndvi = if({ndvi}_max2 < {ndvi_threshold}, null(), {nearest})"
+ f"trees_pixel_ndvi = if({ndvi_split}_max2 < {ndvi_threshold}, null(), {nearest})"
)
rm_rasters.append("trees_pixel_ndvi")
diff --git a/grass-gis-addons/m.analyse.trees/r.trees.peaks/r.trees.peaks.py b/grass-gis-addons/m.analyse.trees/r.trees.peaks/r.trees.peaks.py
index c4609d2..bfca2ba 100644
--- a/grass-gis-addons/m.analyse.trees/r.trees.peaks/r.trees.peaks.py
+++ b/grass-gis-addons/m.analyse.trees/r.trees.peaks/r.trees.peaks.py
@@ -57,7 +57,7 @@
# % required: yes
# % multiple: no
# % label: Output raster map with ID of nearest tree
-# % answer: trees_nearest
+# % answer: nearest_tree
# % guisection: Output
# %end
@@ -177,7 +177,7 @@ def main():
ndsm_resampled = ndsm
rinfo = grass.raster_info(ndsm)
if rinfo["nsres"] < forms_res:
- ndsm_resampled = f"{ndsm}_resampled"
+ ndsm_resampled = f"{ndsm.split('@')[0]}_resampled"
rm_rasters.append(ndsm_resampled)
grass.run_command(
"r.resamp.stats",
@@ -186,7 +186,7 @@ def main():
method="maximum",
)
elif rinfo["nsres"] > forms_res:
- ndsm_resampled = f"{ndsm}_resampled"
+ ndsm_resampled = f"{ndsm.split('@')[0]}_resampled"
rm_rasters.append(ndsm_resampled)
radius_gauss = rinfo["nsres"] * 1.5
radius_box = rinfo["nsres"] * 3
@@ -198,7 +198,7 @@ def main():
radius=f"{radius_gauss},{radius_box}",
)
- ndsm_forms = f"{ndsm}_forms"
+ ndsm_forms = f"{ndsm.split('@')[0]}_forms"
grass.run_command(
"r.geomorphon", elevation=ndsm_resampled, forms=ndsm_forms, search=7
)
diff --git a/grass-gis-addons/m.analyse.trees/r.trees.postprocess/r.trees.postprocess.py b/grass-gis-addons/m.analyse.trees/r.trees.postprocess/r.trees.postprocess.py
index a21fc2c..79be573 100644
--- a/grass-gis-addons/m.analyse.trees/r.trees.postprocess/r.trees.postprocess.py
+++ b/grass-gis-addons/m.analyse.trees/r.trees.postprocess/r.trees.postprocess.py
@@ -228,6 +228,7 @@ def main():
blue = options["blue_raster"]
nir = options["nir_raster"]
ndvi = options["ndvi_raster"]
+ ndvi_split = ndvi.split("@")[0]
ndwi = options["ndwi_raster"]
ndgb = options["ndgb_raster"]
ndsm = options["ndsm"]
@@ -284,7 +285,7 @@ def main():
grass.run_command(
"r.neighbors",
input=ndvi,
- output=f"{ndvi}_min1",
+ output=f"{ndvi_split}_min1",
size=3,
method="minimum",
nprocs=nprocs,
@@ -292,8 +293,8 @@ def main():
)
grass.run_command(
"r.neighbors",
- input=f"{ndvi}_min1",
- output=f"{ndvi}_min2",
+ input=f"{ndvi_split}_min1",
+ output=f"{ndvi_split}_min2",
size=3,
method="minimum",
nprocs=nprocs,
@@ -301,8 +302,8 @@ def main():
)
grass.run_command(
"r.neighbors",
- input=f"{ndvi}_min2",
- output=f"{ndvi}_max1",
+ input=f"{ndvi_split}_min2",
+ output=f"{ndvi_split}_max1",
size=3,
method="maximum",
nprocs=nprocs,
@@ -310,24 +311,24 @@ def main():
)
grass.run_command(
"r.neighbors",
- input=f"{ndvi}_max1",
- output=f"{ndvi}_max2",
+ input=f"{ndvi_split}_max1",
+ output=f"{ndvi_split}_max2",
size=3,
method="maximum",
nprocs=nprocs,
memory=memory_max100mb,
)
- rm_rasters.append(f"{ndvi}_min1")
- rm_rasters.append(f"{ndvi}_min2")
- rm_rasters.append(f"{ndvi}_max1")
- rm_rasters.append(f"{ndvi}_max2")
+ rm_rasters.append(f"{ndvi_split}_min1")
+ rm_rasters.append(f"{ndvi_split}_min2")
+ rm_rasters.append(f"{ndvi_split}_max1")
+ rm_rasters.append(f"{ndvi_split}_max2")
grass.mapcalc(
f"trees_ml_nearest = if({tree_pixels} == 2, {nearest}, null())"
)
rm_rasters.append("trees_ml_nearest")
grass.mapcalc(
- f"trees_ml_pixel_ndvi = if({ndvi}_max2 < {ndvi_threshold}, null(), trees_ml_nearest)"
+ f"trees_ml_pixel_ndvi = if({ndvi_split}_max2 < {ndvi_threshold}, null(), trees_ml_nearest)"
)
rm_rasters.append("trees_ml_pixel_ndvi")
@@ -441,7 +442,7 @@ def main():
grass.run_command(
"r.stats.zonal",
base="trees_ml_object_ndsm",
- cover=f"{ndvi}_max2",
+ cover=f"{ndvi_split}_max2",
method="average",
output="trees_ml_object_ndviavg",
)
diff --git a/grass-gis-addons/m.analyse.trees/v.trees.cd.worker/v.trees.cd.worker.py b/grass-gis-addons/m.analyse.trees/v.trees.cd.worker/v.trees.cd.worker.py
index a43ea95..7175f96 100644
--- a/grass-gis-addons/m.analyse.trees/v.trees.cd.worker/v.trees.cd.worker.py
+++ b/grass-gis-addons/m.analyse.trees/v.trees.cd.worker/v.trees.cd.worker.py
@@ -217,8 +217,12 @@ def main():
gisrc, newgisrc, old_mapset = switch_to_new_mapset(new_mapset)
area += f"@{old_mapset}"
- vec_inp_t1 += f"@{old_mapset}"
- vec_inp_t2 += f"@{old_mapset}"
+ vec_inp_t1 = (
+ f"{vec_inp_t1}@{old_mapset}" if "@" not in vec_inp_t1 else vec_inp_t1
+ )
+ vec_inp_t2 = (
+ f"{vec_inp_t2}@{old_mapset}" if "@" not in vec_inp_t2 else vec_inp_t2
+ )
# set region to current tile (area)
grass.run_command(
diff --git a/grass-gis-addons/m.analyse.trees/v.trees.cd/v.trees.cd.py b/grass-gis-addons/m.analyse.trees/v.trees.cd/v.trees.cd.py
index 0ff4748..7205868 100644
--- a/grass-gis-addons/m.analyse.trees/v.trees.cd/v.trees.cd.py
+++ b/grass-gis-addons/m.analyse.trees/v.trees.cd/v.trees.cd.py
@@ -288,7 +288,11 @@ def main():
queue = ParallelModuleQueue(nprocs=nprocs)
# prepare names for output maps
- output_suffix = ["congruent", f"only_{vec_inp_t1}", f"only_{vec_inp_t2}"]
+ output_suffix = [
+ "congruent",
+ f"only_{vec_inp_t1.split('@')[0]}",
+ f"only_{vec_inp_t2.split('@')[0]}",
+ ]
output_dict = {}
for el in output_suffix:
output_dict[el] = list()
@@ -349,12 +353,24 @@ def main():
msg = proc.outputs["stderr"].value.strip()
grass.message(_(f"\nLog of {proc.get_bash()}:"))
for msg_part in msg.split("\n"):
- grass.message(_(msg_part))
+ if msg_part != "":
+ grass.message(_(msg_part))
# create mapset dict based on Log
if "Skipping..." not in msg:
- tile_output = (
- re.search(r"Output is:\n<(.*?)>", msg).groups()[0].split(",")
- )
+ try:
+ # for execution in terminal
+ tile_output = (
+ re.search(r"Output is:\n<(.*?)>", msg)
+ .groups()[0]
+ .split(",")
+ )
+ except Exception:
+ # for execution in GUI
+ tile_output = (
+ re.search(r"Output is: <(.*?)>", msg)
+ .groups()[0]
+ .split(",")
+ )
for ind, el in enumerate(output_suffix):
if tile_output[ind]:
output_dict[el].append(tile_output[ind])
@@ -392,12 +408,14 @@ def main():
pid,
)
# remove unnecessary columns
- grass.run_command(
- "v.db.dropcolumn",
- map=cd_output_i,
- columns=rm_vec_columns,
- quiet=True,
- )
+ # only for non-empty vector (i.e. vector with attribute table)
+ if grass.vector_db(cd_output_i):
+ grass.run_command(
+ "v.db.dropcolumn",
+ map=cd_output_i,
+ columns=rm_vec_columns,
+ quiet=True,
+ )
areas_count.append(
grass.parse_command(
"v.info",
diff --git a/grass-gis-addons/m.analyse.trees/v.trees.param/v.trees.param.py b/grass-gis-addons/m.analyse.trees/v.trees.param/v.trees.param.py
index 6f01df4..656f4fc 100644
--- a/grass-gis-addons/m.analyse.trees/v.trees.param/v.trees.param.py
+++ b/grass-gis-addons/m.analyse.trees/v.trees.param/v.trees.param.py
@@ -37,7 +37,7 @@
# %option G_OPT_R_INPUT
# % key: ndom
-# % label: Raster map of nDOM
+# % label: Raster map of nDSM
# % required: no
# % guisection: Input
# %end
@@ -135,7 +135,7 @@ def main():
pid = os.getpid()
- treecrowns = options["treecrowns"]
+ treecrowns = options["treecrowns"].split("@")[0]
ndom = options["ndom"]
ndvi = options["ndvi"]
buildings = options["buildings"]
diff --git a/grass-gis-addons/m.analyse.trees/v.trees.species/v.trees.species.py b/grass-gis-addons/m.analyse.trees/v.trees.species/v.trees.species.py
index 65129fc..0e531f6 100644
--- a/grass-gis-addons/m.analyse.trees/v.trees.species/v.trees.species.py
+++ b/grass-gis-addons/m.analyse.trees/v.trees.species/v.trees.species.py
@@ -27,7 +27,7 @@
# %option G_OPT_R_INPUT
# % key: red_raster
# % required: yes
-# % label: Name of the NIR raster
+# % label: Name of the red band
# % guisection: Input
# %end
@@ -314,8 +314,9 @@ def main():
rm_dirs.append(sig_dir)
os.makedirs(sig_dir)
group_inp = (
- f"{ndvi} {red} {green} {blue} {nir} {ndwi} {brightness}"
- f" {ndsm_med_slope_n7}"
+ f"{ndvi.split('@')[0]} {red.split('@')[0]} {green.split('@')[0]}"
+ f" {blue.split('@')[0]} {nir.split('@')[0]} {ndwi.split('@')[0]}"
+ f" {brightness} {ndsm_med_slope_n7}"
)
g_version = tuple(
[
diff --git a/grass-gis-addons/m.import.rvr/m.import.rvr.py b/grass-gis-addons/m.import.rvr/m.import.rvr.py
index 817140b..e5c8fd3 100644
--- a/grass-gis-addons/m.import.rvr/m.import.rvr.py
+++ b/grass-gis-addons/m.import.rvr/m.import.rvr.py
@@ -68,7 +68,7 @@
# % key: dsm_tindex
# % required: no
# % multiple: no
-# % label: Name of the DSM tindex which should be used or created
+# % label: Name of the DSM tindex which should be used or created (optional)
# % description: If this is set the tindex needs a column with the absolute path to the DSM files
# % guisection: General input
# %end
@@ -86,7 +86,7 @@
# % key: dtm_tindex
# % required: no
# % multiple: no
-# % label: Name of the DTM tindex which should be used or created
+# % label: Name of the DTM tindex which should be used or created (optional)
# % description: If this is set the tindex needs a column with the absolute path to the DTM files
# % guisection: General input
# %end
@@ -149,7 +149,7 @@
# % key: dop_tindex
# % required: no
# % multiple: no
-# % label: Name of the DOP tindex which should be used or created
+# % label: Name of the DOP tindex which should be used or created (optional)
# % description: If this is set the tindex needs a column with the absolute path to the DOP files
# % guisection: Input buildings analysis
# %end
@@ -167,7 +167,7 @@
# % key: top_tindex
# % required: no
# % multiple: no
-# % label: Name of the TOP tindex which should be used or created
+# % label: Name of the TOP tindex which should be used or created (optional)
# % description: If this is set the tindex needs a column location with the absolute path to the TOP files
# % guisection: Input trees analysis
# %end