Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
griembauer committed Jan 24, 2022
0 parents commit c7db573
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[flake8]

# E501 line too long (83 > 79 characters)
# F821 undefined name '_'

exclude = .git
max-line-length = 88
per-file-ignores =
./v.disaggregate.population.py: F821, E501, E722
25 changes: 25 additions & 0 deletions .github/workflows/flake8.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Python Flake8 Code Quality

on:
- push
- pull_request

jobs:
flake8:
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install
run: |
python -m pip install --upgrade pip
pip install flake8==3.8.4
- name: Run Flake8
run: |
flake8 --config=.flake8 --count --statistics --show-source --jobs=$(nproc) .
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
MODULE_TOPDIR = ../..

PGM = v.disaggregate.population

include $(MODULE_TOPDIR)/include/Make/Script.make

default: script
26 changes: 26 additions & 0 deletions v.disaggregate.population.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<h2>DESCRIPTION</h2>

<em>v.disaggregate.population</em> disaggregates population data from a administrative
boundary vector with population information onto a high-res raster with
estimated local population. A urban area vector is used to close small gaps in
the population raster in high density urban areas.

<h2>EXAMPLE</h2>

<div class="code"><pre>
v.disaggregate.population population_vector=admin_areas population_column=POP_2020 population_raster=pop_raster_2020 urban_vector=urban_areas output=pop_raster_2020_disaggregated
</pre></div>

<h2>SEE ALSO</h2>
<em>
<a href="r.grow.html">r.grow</a>,
<a href="v.area.weigh.html">v.area.weigh</a>,
</em>

<h2>AUTHOR</h2>

Guido Riembauer, mundialis

<!--
<p><i>Last changed: $Date$</i>
-->
141 changes: 141 additions & 0 deletions v.disaggregate.population.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/env python3
#
############################################################################
#
# MODULE: v.disaggregate.population
# AUTHOR(S): Guido Riembauer, mundialis GmbH & Co. KG
#
# PURPOSE: Disaggregates population based on vector admin areas, vector
# urban areas and a high resolution population raster
#
# COPYRIGHT: (C) 2020-2022 by mundialis
# This program is free software under the GNU General Public
# License (>=v2). Read the file COPYING that comes with GRASS
# for details.
#
#############################################################################
# %Module
# % description: Disaggregates population based on vector admin areas, vector urban areas and a high resolution population raster data.
# % keyword: vector
# % keyword: raster
# % keyword: disaggregation
# %End

# %option G_OPT_V_INPUT
# % key: population_vector
# % type: string
# % required: yes
# % multiple: no
# % label: Vector map containing population to be disaggregated in a column
# %end

# %option
# % key: population_column
# % type: string
# % required: no
# % multiple: no
# % label: Column of input vector map with population information
# %end

# %option G_OPT_R_INPUT
# % key: population_raster
# % type: string
# % required: yes
# % multiple: no
# % label: High resolution population raster map
# %end

# %option G_OPT_R_OUTPUT
# % key: output
# % type: string
# % required: yes
# % multiple: no
# % label: Name of output raster map
# %end

# %option G_OPT_V_INPUT
# % key: urban_vector
# % type: string
# % required: yes
# % multiple: no
# % label: Vector containing urban areas (all other areas must be nodata)
# %end

import atexit
import grass.script as grass
import os

rm_rasters = []


def cleanup():
nuldev = open(os.devnull, "w")
kwargs = {"flags": "f", "quiet": True, "stderr": nuldev}
for rmrast in rm_rasters:
if grass.find_file(name=rmrast, element="raster")["file"]:
grass.run_command("g.remove", type="raster", name=rmrast, **kwargs)
if grass.find_file(name="MASK", element="raster")["file"]:
try:
grass.run_command("r.mask", flags="r")
except:
pass


def main():
global rm_rasters

admin_vector = options["population_vector"]
column = options["population_column"]
population_raster = options["population_raster"]
dense = options["urban_vector"]
output = options["output"]

pid = os.getpid()

# check that v.area.weigh is installed
if not grass.find_program("v.area.weigh", "--help"):
grass.fatal(
_("The 'v.area.weigh' module was not found, install it first:")
+ "\n"
+ "g.extension v.area.weigh"
)

# limit calculation to dense urban areas and close small gaps between buildings
grass.run_command("r.mask", vector=dense)

temp_grow1 = "%s_grownbyone_%s" % (population_raster, pid)
rm_rasters.append(temp_grow1)
temp_grow2 = "%s_shrunkbyone_%s" % (population_raster, pid)
rm_rasters.append(temp_grow2)
grass.run_command(
"r.grow", input=population_raster, output=temp_grow1, radius=1.01
)
grass.run_command(
"r.grow", input=temp_grow1, output=temp_grow2, radius=-1.01
)
grass.run_command("r.mask", flags="r")

# put together areas from inside and outside cities
pop_raster_new = "pop_raster_temp_%s" % pid
rm_rasters.append(pop_raster_new)
grass.run_command(
"r.mapcalc",
expression="%s =if(isnull(%s), %s,%s)"
% (pop_raster_new, population_raster, temp_grow2, population_raster),
)

grass.run_command(
"v.area.weigh",
vector=admin_vector,
column=column,
weight=pop_raster_new,
output=output,
)

grass.message(_("Generated raster <%s>" % output))


if __name__ == "__main__":
options, flags = grass.parser()
atexit.register(cleanup)
main()

0 comments on commit c7db573

Please sign in to comment.