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