Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Inputs as args #255

Closed
wants to merge 12 commits into from
19 changes: 8 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,19 @@ itself.

.. code-block:: python

def execute(mp, resampling="nearest"):
def execute(mp, dem, land_polygons, resampling="nearest"):

# Open elevation model.
with mp.open("dem") as src:
# Skip tile if there is no data available or read data into a NumPy array.
if src.is_empty(1):
return "empty"
else:
dem = src.read(1, resampling=resampling)
# Skip tile if there is no data available or read data into a NumPy array.
if dem.is_empty(1):
return "empty"
else:
dem_data = dem.read(1, resampling=resampling)

# Create hillshade using a built-in hillshade function.
hillshade = mp.hillshade(dem)
hillshade = mp.hillshade(dem_data)

# Clip with polygons from vector file and return result.
with mp.open("land_polygons") as land_file:
return mp.clip(hillshade, land_file.read())
return mp.clip(hillshade, land_polygons.read())


You can then interactively inspect the process output directly on a map in a
Expand Down
19 changes: 8 additions & 11 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,19 @@ vector dataset could look like this:

# content of hillshade.py

def execute(mp, resampling="nearest"):
def execute(mp, dem, land_polygons, resampling="nearest"):

# Open elevation model.
with mp.open("dem") as src:
# Skip tile if there is no data available or read data into a NumPy array.
if src.is_empty(1):
return "empty"
else:
dem = src.read(1, resampling=resampling)
# Skip tile if there is no data available or read data into a NumPy array.
if dem.is_empty(1):
return "empty"
else:
dem_data = dem.read(1, resampling=resampling)

# Create hillshade using a built-in hillshade function.
hillshade = mp.hillshade(dem)
hillshade = mp.hillshade(dem_data)

# Clip with polygons from vector file and return result.
with mp.open("land_polygons") as land_file:
return mp.clip(hillshade, land_file.read())
return mp.clip(hillshade, land_polygons.read())


Examine the result in your browser by serving the process by pointing it to
Expand Down
25 changes: 16 additions & 9 deletions mapchete/_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,25 @@ def _execute(self):
process_func = get_process_func(
process_path=self.process_path, config_dir=self.config_dir
)
mp_obj = MapcheteProcess(
tile=self.tile,
params=self.process_func_params,
input=self.input,
output_params=self.output_params
)
try:
with Timer() as t:
params = [
# magic mp object
mp_obj if name == "mp"
# process input
else mp_obj.input[name] if name in mp_obj.input
# process parameter
else value
for name, value in self.process_func_params.items()
]
# Actually run process.
process_data = process_func(
MapcheteProcess(
tile=self.tile,
params=self.process_func_params,
input=self.input,
output_params=self.output_params
),
**self.process_func_params
)
process_data = process_func(*params)
except MapcheteNodataTile:
raise
except Exception as e:
Expand Down
54 changes: 49 additions & 5 deletions mapchete/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ def input(self):
for k, v in raw_inputs.items():
# for files and tile directories
if isinstance(v, str):
logger.debug("load input reader for simple input %s", v)
logger.debug("load input reader for simple input %s", v)
try:
reader = load_input_reader(
dict(
Expand Down Expand Up @@ -481,10 +481,54 @@ def process_func(self):
)

def get_process_func_params(self, zoom):
return {
k: v for k, v in self.params_at_zoom(zoom).items()
if k in inspect.signature(self.process_func).parameters
}
"""
Return process function parameters for zoom.

The dictionary returned is a snapshot for given zoom which combines custom process
parameters and input datasets.

This function also checks whether parameter names are also used as input names and
raises a MapcheteConfigError if this is the case.

Parameters
----------
zoom : int
zoom level

Returns
-------
parameter map : dictionary
"""
if zoom not in self.init_zoom_levels:
raise ValueError("zoom level not available with current configuration")
process_func_params = inspect.signature(self.process_func).parameters
all_config_params = self.params_at_zoom(zoom)

# look for config parameters which map on process function parameters
inputs = set(all_config_params["input"].keys()) & set(process_func_params)
custom_params = set(all_config_params.keys()) & set(process_func_params)

# verify no parameter name intersection is configured
intersecting = custom_params & inputs
if intersecting:
raise MapcheteConfigError(
"custom parameters and inputs cannot have the same key: %s" % intersecting
)

# bring all together
return OrderedDict([
# set mp value
(k, None) if k == "mp"
# input values from configuration
else (k, all_config_params["input"][k]) if k in all_config_params["input"]
# custom values from configuration
else (k, all_config_params[k]) if k in all_config_params
# default values from process function
else (k, v.default)
for k, v in process_func_params.items()
# excludes **kwargs from process function
if v.kind != v.VAR_KEYWORD
])

def get_inputs_for_tile(self, tile):

Expand Down
42 changes: 20 additions & 22 deletions mapchete/processes/contours.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

def execute(
mp,
dem=None,
clip=None,
resampling="nearest",
interval=100,
field='elev',
Expand All @@ -19,17 +21,14 @@ def execute(
**kwargs
):
"""
Generate hillshade from DEM.
Generate contours from DEM.

Inputs
------
Parameters
----------
dem
Input DEM.
clip (optional)
Vector data used to clip output.

Parameters
----------
resampling : str (default: 'nearest')
Resampling used when reading from TileDirectory.
interval : integer
Expand Down Expand Up @@ -64,26 +63,25 @@ def execute(
list of GeoJSON-like features
"""
# read clip geometry
if "clip" in mp.params["input"]:
clip_geom = mp.open("clip").read()
if clip is None:
clip_geom = []
else:
clip_geom = clip.read()
if not clip_geom:
logger.debug("no clip data over tile")
return "empty"
else:
clip_geom = []

with mp.open("dem",) as dem:
logger.debug("reading input raster")
dem_data = dem.read(
resampling=resampling,
matching_method=td_matching_method,
matching_max_zoom=td_matching_max_zoom,
matching_precision=td_matching_precision,
fallback_to_higher_zoom=td_fallback_to_higher_zoom
)
if dem_data.mask.all():
logger.debug("raster empty")
return "empty"
logger.debug("reading input raster")
dem_data = dem.read(
resampling=resampling,
matching_method=td_matching_method,
matching_max_zoom=td_matching_max_zoom,
matching_precision=td_matching_precision,
fallback_to_higher_zoom=td_fallback_to_higher_zoom
)
if dem_data.mask.all():
logger.debug("raster empty")
return "empty"

logger.debug("calculate hillshade")
contours = mp.contours(
Expand Down
42 changes: 20 additions & 22 deletions mapchete/processes/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

def execute(
mp,
raster=None,
clip=None,
resampling="nearest",
band_indexes=None,
td_matching_method="gdal",
Expand All @@ -21,15 +23,12 @@ def execute(
"""
Convert and optionally clip input raster data.

Inputs
------
Parameters
----------
raster
Singleband or multiband data input.
clip (optional)
Vector data used to clip output.

Parameters
----------
resampling : str (default: 'nearest')
Resampling used when reading from TileDirectory.
band_indexes : list
Expand Down Expand Up @@ -66,27 +65,26 @@ def execute(
np.ndarray
"""
# read clip geometry
if "clip" in mp.params["input"]:
clip_geom = mp.open("clip").read()
if clip is None:
clip_geom = []
else:
clip_geom = clip.read()
if not clip_geom:
logger.debug("no clip data over tile")
return "empty"
else:
clip_geom = []

with mp.open("raster",) as raster:
logger.debug("reading input raster")
raster_data = raster.read(
indexes=band_indexes,
resampling=resampling,
matching_method=td_matching_method,
matching_max_zoom=td_matching_max_zoom,
matching_precision=td_matching_precision,
fallback_to_higher_zoom=td_fallback_to_higher_zoom
)
if raster_data.mask.all():
logger.debug("raster empty")
return "empty"
logger.debug("reading input raster")
raster_data = raster.read(
indexes=band_indexes,
resampling=resampling,
matching_method=td_matching_method,
matching_max_zoom=td_matching_max_zoom,
matching_precision=td_matching_precision,
fallback_to_higher_zoom=td_fallback_to_higher_zoom
)
if raster_data.mask.all():
logger.debug("raster empty")
return "empty"

if scale_offset != 0.:
logger.debug("apply scale offset %s", scale_offset)
Expand Down
42 changes: 20 additions & 22 deletions mapchete/processes/hillshade.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

def execute(
mp,
dem=None,
clip=None,
resampling="nearest",
azimuth=315.0,
altitude=45.0,
Expand All @@ -18,17 +20,14 @@ def execute(
**kwargs
):
"""
Extract contour lines from DEM.
Calculate hillshade from DEM.

Inputs
------
Parameters
----------
dem
Input DEM.
clip (optional)
Vector data used to clip output.

Parameters
----------
resampling : str (default: 'nearest')
Resampling used when reading from TileDirectory.
azimuth : float
Expand Down Expand Up @@ -66,26 +65,25 @@ def execute(
np.ndarray
"""
# read clip geometry
if "clip" in mp.params["input"]:
clip_geom = mp.open("clip").read()
if clip is None:
clip_geom = []
else:
clip_geom = clip.read()
if not clip_geom:
logger.debug("no clip data over tile")
return "empty"
else:
clip_geom = []

with mp.open("dem",) as dem:
logger.debug("reading input raster")
dem_data = dem.read(
resampling=resampling,
matching_method=td_matching_method,
matching_max_zoom=td_matching_max_zoom,
matching_precision=td_matching_precision,
fallback_to_higher_zoom=td_fallback_to_higher_zoom
)
if dem_data.mask.all():
logger.debug("raster empty")
return "empty"
logger.debug("reading input DEM")
dem_data = dem.read(
resampling=resampling,
matching_method=td_matching_method,
matching_max_zoom=td_matching_max_zoom,
matching_precision=td_matching_precision,
fallback_to_higher_zoom=td_fallback_to_higher_zoom
)
if dem_data.mask.all():
logger.debug("raster empty")
return "empty"

logger.debug("calculate hillshade")
hillshade = mp.hillshade(
Expand Down
Loading