Module rok4_tools.tmsizer_utils.processors.reduce
Provide processor combining data. Input data is transformed and accumulated and the result is yielded juste once, at the end.
The module contains the following classes:
CountProcessor
- Count the number of item read from the input processorHeatmapProcessor
- Generate an heat map with all point coordinate read from the input processor
Expand source code
"""Provide processor combining data. Input data is transformed and accumulated and the result is yielded juste once, at the end.
The module contains the following classes:
- `CountProcessor` - Count the number of item read from the input processor
- `HeatmapProcessor` - Generate an heat map with all point coordinate read from the input processor
"""
import sys
import numpy as np
from typing import Dict, List, Tuple, Union, Iterator
from math import floor
import rasterio
from rasterio.transform import from_origin
from rasterio.io import MemoryFile
from rasterio import logging
logging.getLogger().setLevel(logging.ERROR)
from rok4_tools.tmsizer_utils.processors.processor import Processor
class CountProcessor(Processor):
"""Processor counting the number of item read from the input processor
All input formats are allowed and output format is "COUNT"
Attributes:
__input (Processor): Processor from which data is read
"""
def __init__(self, input: Processor):
"""Constructor method
Args:
input (Processor): Processor from which data is read
"""
super().__init__("COUNT")
self.__input = input
def process(self) -> Iterator[int]:
"""Count number of input item
Yield count only once at the end
Examples:
Get input items count
from rok4_tools.tmsizer_utils.processors.reduce import CountProcessor
try:
# Creation of Processor source_processor
processor = CountProcessor(source_processor, level="15", format="GeoJSON" )
count = processor.process().__next__()
print(f"{count} items in source_processor")
except Exception as e:
print("{e}")
Yields:
Iterator[int]: the count of input items
"""
for item in self.__input.process():
self._processed += 1
yield self._processed
def __str__(self) -> str:
return f"CountProcessor : {self._processed} {self.__input.format} items counted"
class HeatmapProcessor(Processor):
"""Processor counting the number of item read from the input processor
Accepted input format is "POINT" and output format is "FILELIKE". Output file-like object is an in-memory GeoTIFF
Attributes:
__input (Processor): Processor from which data is read
__bbox (Tuple[float, float, float, float]): Bounding box of the heat map (xmin,ymin,xmax,ymax)
__dimensions (Tuple[int, int]): Pixel dimensions of the heat map (width, height)
__resolutions (Tuple[float, float]): Pixel resolution (x resolution, y resolution)
"""
input_formats_allowed = ["POINT"]
def __init__(self, input: Processor, **options):
"""Constructor method
Args:
input (Processor): Processor from which data is read
**bbox (str): Bounding box of the heat map. Format "<xmin>,<ymin>,<xmax>,<ymax>". Coordinates system have to be the pivot TMS' one
**dimensions (str): Pixel dimensions of the heat map.Format "<width>x<height>"
Raises:
ValueError: Input format is not allowed
KeyError: A mandatory option is missing
ValueError: A mandatory option is not valid
ValueError: Provided level is not in the pivot TMS
"""
if input.format not in self.input_formats_allowed:
raise Exception(f"Input format {input.format} is not handled for HeatmapProcessor : allowed formats are {self.input_formats_allowed}")
super().__init__("FILELIKE")
self.__input = input
try:
try:
self.__bbox = [float(c) for c in options["bbox"].split(",")]
self.__bbox = tuple(self.__bbox)
except ValueError as e:
raise ValueError(f"Option 'bbox' contains non float values : {e}")
if len(self.__bbox) != 4 or self.__bbox[0] >= self.__bbox[2] or self.__bbox[1] >= self.__bbox[3]:
raise ValueError(f"Option 'bbox' have to be provided with format <xmin>,<ymin>,<xmax>,<ymax> (floats, min < max)")
try:
self.__dimensions = [int(d) for d in options["dimensions"].split("x")]
self.__dimensions = tuple(self.__dimensions)
except ValueError as e:
raise ValueError(f"Option 'dimensions' contains non integer values : {e}")
if len(self.__dimensions) != 2 or self.__dimensions[0] <= 0 or self.__dimensions[1] <= 0:
raise ValueError(f"Option 'dimensions' have to be provided with format <width>x<height> (positive integers)")
self.__resolutions = (
(self.__bbox[2] - self.__bbox[0]) / self.__dimensions[0],
(self.__bbox[3] - self.__bbox[1]) / self.__dimensions[1]
)
except KeyError as e:
raise KeyError(f"Option {e} is required for a heatmap processing")
def process(self) -> Iterator[MemoryFile]:
"""Read point coordinates from the input processor and accumule them as a heat map
Points outsides the provided bounding box are ignored.
Examples:
Get intersecting tiles' indices
from rok4_tools.tmsizer_utils.processors.reduce import HeatmapProcessor
try:
# Creation of Processor source_processor with format POINT
processor = HeatmapProcessor(source_processor, bbox="65000,6100000,665000,6500000", dimensions="600x400" )
f = processor.process().__next__()
with open("hello.txt", "w") as my_file:
my_file.write(f.read())
except Exception as e:
print("{e}")
Yields:
Iterator[rasterio.io.MemoryFile]: In-memory GeoTIFF
"""
data = np.zeros((self.__dimensions[1], self.__dimensions[0]), dtype=np.uint32)
if self.__input.format == "POINT":
for item in self.__input.process():
self._processed += 1
(x_center, y_center) = item
if x_center > self.__bbox[2] or y_center > self.__bbox[3] or x_center < self.__bbox[0] or y_center < self.__bbox[1]:
continue
pcol = floor((x_center - self.__bbox[0]) / self.__resolutions[0])
prow = floor((self.__bbox[3] - y_center) / self.__resolutions[1])
data[prow][pcol] += 1
memfile = MemoryFile()
with memfile.open(
driver='GTiff',
height=data.shape[0],
width=data.shape[1],
count=1,
dtype=data.dtype,
crs=rasterio.CRS.from_string(self.tms.srs),
nodata=0,
transform=from_origin(self.__bbox[0], self.__bbox[3], self.__resolutions[0], self.__resolutions[1]),
) as dataset:
dataset.write(data, indexes=1)
yield memfile
def __str__(self) -> str:
return f"HeatmapProcessor : {self._processed} hits on image with dimensions {self.__dimensions} and bbox {self.__bbox}"
Classes
class CountProcessor (input: Processor)
-
Processor counting the number of item read from the input processor
All input formats are allowed and output format is "COUNT"
Attributes
__input
:Processor
- Processor from which data is read
Constructor method
Args
input
:Processor
- Processor from which data is read
Expand source code
class CountProcessor(Processor): """Processor counting the number of item read from the input processor All input formats are allowed and output format is "COUNT" Attributes: __input (Processor): Processor from which data is read """ def __init__(self, input: Processor): """Constructor method Args: input (Processor): Processor from which data is read """ super().__init__("COUNT") self.__input = input def process(self) -> Iterator[int]: """Count number of input item Yield count only once at the end Examples: Get input items count from rok4_tools.tmsizer_utils.processors.reduce import CountProcessor try: # Creation of Processor source_processor processor = CountProcessor(source_processor, level="15", format="GeoJSON" ) count = processor.process().__next__() print(f"{count} items in source_processor") except Exception as e: print("{e}") Yields: Iterator[int]: the count of input items """ for item in self.__input.process(): self._processed += 1 yield self._processed def __str__(self) -> str: return f"CountProcessor : {self._processed} {self.__input.format} items counted"
Ancestors
Methods
def process(self) ‑> Iterator[int]
-
Count number of input item
Yield count only once at the end
Examples
Get input items count
from rok4_tools.tmsizer_utils.processors.reduce import CountProcessor try: # Creation of Processor source_processor processor = CountProcessor(source_processor, level="15", format="GeoJSON" ) count = processor.process().__next__() print(f"{count} items in source_processor") except Exception as e: print("{e}")
Yields
Iterator[int]
- the count of input items
Expand source code
def process(self) -> Iterator[int]: """Count number of input item Yield count only once at the end Examples: Get input items count from rok4_tools.tmsizer_utils.processors.reduce import CountProcessor try: # Creation of Processor source_processor processor = CountProcessor(source_processor, level="15", format="GeoJSON" ) count = processor.process().__next__() print(f"{count} items in source_processor") except Exception as e: print("{e}") Yields: Iterator[int]: the count of input items """ for item in self.__input.process(): self._processed += 1 yield self._processed
Inherited members
class HeatmapProcessor (input: Processor, **options)
-
Processor counting the number of item read from the input processor
Accepted input format is "POINT" and output format is "FILELIKE". Output file-like object is an in-memory GeoTIFF
Attributes
__input
:Processor
- Processor from which data is read
__bbox
:Tuple[float, float, float, float]
- Bounding box of the heat map (xmin,ymin,xmax,ymax)
__dimensions
:Tuple[int, int]
- Pixel dimensions of the heat map (width, height)
__resolutions
:Tuple[float, float]
- Pixel resolution (x resolution, y resolution)
Constructor method
Args
input
:Processor
- Processor from which data is read
**bbox
:str
- Bounding box of the heat map. Format "
, , , ". Coordinates system have to be the pivot TMS' one **dimensions
:str
- Pixel dimensions of the heat map.Format "
x "
Raises
ValueError
- Input format is not allowed
KeyError
- A mandatory option is missing
ValueError
- A mandatory option is not valid
ValueError
- Provided level is not in the pivot TMS
Expand source code
class HeatmapProcessor(Processor): """Processor counting the number of item read from the input processor Accepted input format is "POINT" and output format is "FILELIKE". Output file-like object is an in-memory GeoTIFF Attributes: __input (Processor): Processor from which data is read __bbox (Tuple[float, float, float, float]): Bounding box of the heat map (xmin,ymin,xmax,ymax) __dimensions (Tuple[int, int]): Pixel dimensions of the heat map (width, height) __resolutions (Tuple[float, float]): Pixel resolution (x resolution, y resolution) """ input_formats_allowed = ["POINT"] def __init__(self, input: Processor, **options): """Constructor method Args: input (Processor): Processor from which data is read **bbox (str): Bounding box of the heat map. Format "<xmin>,<ymin>,<xmax>,<ymax>". Coordinates system have to be the pivot TMS' one **dimensions (str): Pixel dimensions of the heat map.Format "<width>x<height>" Raises: ValueError: Input format is not allowed KeyError: A mandatory option is missing ValueError: A mandatory option is not valid ValueError: Provided level is not in the pivot TMS """ if input.format not in self.input_formats_allowed: raise Exception(f"Input format {input.format} is not handled for HeatmapProcessor : allowed formats are {self.input_formats_allowed}") super().__init__("FILELIKE") self.__input = input try: try: self.__bbox = [float(c) for c in options["bbox"].split(",")] self.__bbox = tuple(self.__bbox) except ValueError as e: raise ValueError(f"Option 'bbox' contains non float values : {e}") if len(self.__bbox) != 4 or self.__bbox[0] >= self.__bbox[2] or self.__bbox[1] >= self.__bbox[3]: raise ValueError(f"Option 'bbox' have to be provided with format <xmin>,<ymin>,<xmax>,<ymax> (floats, min < max)") try: self.__dimensions = [int(d) for d in options["dimensions"].split("x")] self.__dimensions = tuple(self.__dimensions) except ValueError as e: raise ValueError(f"Option 'dimensions' contains non integer values : {e}") if len(self.__dimensions) != 2 or self.__dimensions[0] <= 0 or self.__dimensions[1] <= 0: raise ValueError(f"Option 'dimensions' have to be provided with format <width>x<height> (positive integers)") self.__resolutions = ( (self.__bbox[2] - self.__bbox[0]) / self.__dimensions[0], (self.__bbox[3] - self.__bbox[1]) / self.__dimensions[1] ) except KeyError as e: raise KeyError(f"Option {e} is required for a heatmap processing") def process(self) -> Iterator[MemoryFile]: """Read point coordinates from the input processor and accumule them as a heat map Points outsides the provided bounding box are ignored. Examples: Get intersecting tiles' indices from rok4_tools.tmsizer_utils.processors.reduce import HeatmapProcessor try: # Creation of Processor source_processor with format POINT processor = HeatmapProcessor(source_processor, bbox="65000,6100000,665000,6500000", dimensions="600x400" ) f = processor.process().__next__() with open("hello.txt", "w") as my_file: my_file.write(f.read()) except Exception as e: print("{e}") Yields: Iterator[rasterio.io.MemoryFile]: In-memory GeoTIFF """ data = np.zeros((self.__dimensions[1], self.__dimensions[0]), dtype=np.uint32) if self.__input.format == "POINT": for item in self.__input.process(): self._processed += 1 (x_center, y_center) = item if x_center > self.__bbox[2] or y_center > self.__bbox[3] or x_center < self.__bbox[0] or y_center < self.__bbox[1]: continue pcol = floor((x_center - self.__bbox[0]) / self.__resolutions[0]) prow = floor((self.__bbox[3] - y_center) / self.__resolutions[1]) data[prow][pcol] += 1 memfile = MemoryFile() with memfile.open( driver='GTiff', height=data.shape[0], width=data.shape[1], count=1, dtype=data.dtype, crs=rasterio.CRS.from_string(self.tms.srs), nodata=0, transform=from_origin(self.__bbox[0], self.__bbox[3], self.__resolutions[0], self.__resolutions[1]), ) as dataset: dataset.write(data, indexes=1) yield memfile def __str__(self) -> str: return f"HeatmapProcessor : {self._processed} hits on image with dimensions {self.__dimensions} and bbox {self.__bbox}"
Ancestors
Class variables
var input_formats_allowed
Methods
def process(self) ‑> Iterator[rasterio.io.MemoryFile]
-
Read point coordinates from the input processor and accumule them as a heat map
Points outsides the provided bounding box are ignored.
Examples
Get intersecting tiles' indices
from rok4_tools.tmsizer_utils.processors.reduce import HeatmapProcessor try: # Creation of Processor source_processor with format POINT processor = HeatmapProcessor(source_processor, bbox="65000,6100000,665000,6500000", dimensions="600x400" ) f = processor.process().__next__() with open("hello.txt", "w") as my_file: my_file.write(f.read()) except Exception as e: print("{e}")
Yields
Iterator[rasterio.io.MemoryFile]
- In-memory GeoTIFF
Expand source code
def process(self) -> Iterator[MemoryFile]: """Read point coordinates from the input processor and accumule them as a heat map Points outsides the provided bounding box are ignored. Examples: Get intersecting tiles' indices from rok4_tools.tmsizer_utils.processors.reduce import HeatmapProcessor try: # Creation of Processor source_processor with format POINT processor = HeatmapProcessor(source_processor, bbox="65000,6100000,665000,6500000", dimensions="600x400" ) f = processor.process().__next__() with open("hello.txt", "w") as my_file: my_file.write(f.read()) except Exception as e: print("{e}") Yields: Iterator[rasterio.io.MemoryFile]: In-memory GeoTIFF """ data = np.zeros((self.__dimensions[1], self.__dimensions[0]), dtype=np.uint32) if self.__input.format == "POINT": for item in self.__input.process(): self._processed += 1 (x_center, y_center) = item if x_center > self.__bbox[2] or y_center > self.__bbox[3] or x_center < self.__bbox[0] or y_center < self.__bbox[1]: continue pcol = floor((x_center - self.__bbox[0]) / self.__resolutions[0]) prow = floor((self.__bbox[3] - y_center) / self.__resolutions[1]) data[prow][pcol] += 1 memfile = MemoryFile() with memfile.open( driver='GTiff', height=data.shape[0], width=data.shape[1], count=1, dtype=data.dtype, crs=rasterio.CRS.from_string(self.tms.srs), nodata=0, transform=from_origin(self.__bbox[0], self.__bbox[3], self.__resolutions[0], self.__resolutions[1]), ) as dataset: dataset.write(data, indexes=1) yield memfile
Inherited members