Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 62 additions & 16 deletions python/grass/temporal/univar_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from multiprocessing import Pool
from subprocess import PIPE
import json

import grass.script as gs
from grass.pygrass.modules import Module
Expand All @@ -35,7 +36,11 @@


def compute_univar_stats(
registered_map_info, stats_module, fs, rast_region: bool = False
registered_map_info,
stats_module,
fs,
rast_region: bool = False,
output_format: str | None = None,
):
"""Compute univariate statistics for a map of a space time raster or raster3d
dataset
Expand All @@ -47,6 +52,7 @@ def compute_univar_stats(
:param rast_region: If set True ignore the current region settings
and use the raster map regions for univar statistical calculation.
Only available for strds.
:param output_format: Output format specification
"""
string = ""
id = registered_map_info["id"]
Expand All @@ -72,6 +78,34 @@ def compute_univar_stats(
else _("Unable to get statistics for 3d raster map <%s>") % id
)
return None

if output_format == "json":
try:
stats = json.loads(univar_stats)
except ValueError:
gs.warning(_("Unable to parse JSON output for map <%s>") % id)
return None

if isinstance(stats, dict):
stats = [stats]

processed_stats = []
for s in stats:
new_s = {
"id": id,
"semantic_label": semantic_label
if stats_module.name == "r.univar" and semantic_label
else None,
"start": str(start) if start else None,
"end": str(end) if end else None,
}

new_s.update(s)

processed_stats.append(new_s)

return processed_stats

eol = ""

for idx, stats_kv in enumerate(univar_stats.split(";")):
Expand Down Expand Up @@ -125,6 +159,7 @@ def print_gridded_dataset_univar_statistics(
zones=None,
percentile=None,
nprocs: int = 1,
format: str = "plain",
) -> None:
"""Print univariate statistics for a space time raster or raster3d dataset.

Expand All @@ -140,6 +175,7 @@ def print_gridded_dataset_univar_statistics(
:param no_header: Suppress the printing of column names
:param fs: Field separator
:param nprocs: Number of cores to use for processing
:param format: Output format ("plain", "csv", or "json"). Default is "plain".
:param rast_region: If set True ignore the current region settings
and use the raster map regions for univar statistical calculation.
:param region_relation: Process only maps with the given spatial relation
Expand Down Expand Up @@ -225,15 +261,17 @@ def print_gridded_dataset_univar_statistics(
for perc in percentile
]
)
string = fs.join(cols)

if output is None:
print(string)
else:
out_file.write(string + "\n")
if no_header is False and format != "json":
string = fs.join(cols)
if output is None:
print(string)
else:
out_file.write(string + "\n")

# Define flags
flag = "g"
flag = ""
if format != "json":
flag = "g"
if extended is True:
flag += "e"
if type == "strds" and rast_region is True and not zones:
Expand All @@ -246,29 +284,37 @@ def print_gridded_dataset_univar_statistics(
zones=zones,
percentile=percentile,
stdout_=PIPE,
format="json" if format == "json" else None,
run_=False,
)

nprocs = max(nprocs, 1)
if nprocs == 1:
strings = [
compute_univar_stats(
row,
univar_module,
fs,
)
compute_univar_stats(row, univar_module, fs, rast_region, format)
for row in rows
]
else:
with Pool(min(nprocs, len(rows))) as pool:
strings = pool.starmap(
compute_univar_stats, [(dict(row), univar_module, fs) for row in rows]
compute_univar_stats,
[(dict(row), univar_module, fs, rast_region, format) for row in rows],
)

if format == "json":
json_out = []

for block in filter(None, strings):
json_out.extend(block)

output_str = json.dumps(json_out, indent=4)
else:
output_str = "\n".join(filter(None, strings))

if output is None:
print("\n".join(filter(None, strings)))
print(output_str)
else:
out_file.write("\n".join(filter(None, strings)))
out_file.write(output_str + "\n")

dbif.close()

Expand Down
95 changes: 95 additions & 0 deletions temporal/t.rast.univar/t.rast.univar.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,101 @@ id|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|c
2012_12_tempmean@climate_2009_2012|2012-12-01 00:00:00|2013-01-01 00:00:00|8.71|1.76|11.98|8.71|1.72|2.95|19.74|4418403.77|503233|1010600|7.84|8.95|9.99|10.67
```

You can use format options as well to output the statistics in
JSON, CSV or Plain (default) formats. For example, to get JSON
output with extended statistics:

```sh
t.rast.univar -e input=nc_lst_daily format=json
```

```json
[
{
"id": "aqua_lst_day20020705@modis2002lst",
"semantic_label": null,
"start": "2002-07-05 00:00:00",
"end": "2002-07-06 00:00:00",
"n": 448428,
"null_cells": 390977,
"cells": 839405,
"min": 25.730000000000018,
"max": 45.77000000000004,
"range": 20.04000000000002,
"mean": 36.24265068193782,
"mean_of_abs": 36.24265068193782,
"stddev": 2.6171016196159838,
"variance": 6.849220887396605,
"coeff_var": 7.221054670044495,
"sum": 16252219.360000012,
"first_quartile": 34.49000000000001,
"median": 36.07000000000005,
"third_quartile": 37.83000000000004,
"percentiles": [
{
"percentile": 90,
"value": 40.01000000000005
}
]
},
{
"id": "aqua_lst_day20020706@modis2002lst",
"semantic_label": null,
"start": "2002-07-06 00:00:00",
"end": "2002-07-07 00:00:00",
"n": 246658,
"null_cells": 592747,
"cells": 839405,
"min": 25.630000000000052,
"max": 34.81,
"range": 9.17999999999995,
"mean": 28.219656852808374,
"mean_of_abs": 28.219656852808374,
"stddev": 1.6350578714604542,
"variance": 2.6734142430247916,
"coeff_var": 5.794038814819025,
"sum": 6960604.120000008,
"first_quartile": 27.110000000000014,
"median": 27.970000000000027,
"third_quartile": 28.970000000000027,
"percentiles": [
{
"percentile": 90,
"value": 30.450000000000045
}
]
},
{
"id": "aqua_lst_day20020707@modis2002lst",
"semantic_label": null,
"start": "2002-07-07 00:00:00",
"end": "2002-07-08 00:00:00",
"n": 714454,
"null_cells": 124951,
"cells": 839405,
"min": 25.630000000000052,
"max": 44.670000000000016,
"range": 19.039999999999964,
"mean": 32.642155464172674,
"mean_of_abs": 32.642155464172674,
"stddev": 3.1874224286049917,
"variance": 10.159661738374142,
"coeff_var": 9.764742503305083,
"sum": 23321318.54000002,
"first_quartile": 30.350000000000023,
"median": 32.450000000000045,
"third_quartile": 34.77000000000004,
"percentiles": [
{
"percentile": 90,
"value": 36.950000000000045
}
]
},
...
]
```

## SEE ALSO

*[t.create](t.create.md), [t.info](t.info.md) [t.create](r.univar.md),*
Expand Down
33 changes: 30 additions & 3 deletions temporal/t.rast.univar/t.rast.univar.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@

# %option G_OPT_F_SEP
# % label: Field separator character between the output columns
# % answer:
# % guisection: Formatting
# %end

# %option G_OPT_F_FORMAT
# % options: plain,json,csv
# % descriptions: plain;Plain text output;json;JSON (JavaScript Object Notation);csv;CSV (Comma Separated Values)
# % guisection: Formatting
# %end

Expand Down Expand Up @@ -102,9 +109,6 @@ def main():
# Get the options and flags
options, flags = gs.parser()

# lazy imports
import grass.temporal as tgis

# Define variables
input = options["input"]
zones = options["zones"]
Expand All @@ -116,6 +120,28 @@ def main():
no_header = flags["u"]
rast_region = bool(flags["r"])
separator = gs.separator(options["separator"])
output_format = options.get("format", "plain")

if output_format == "csv":
if not separator:
separator = ","
elif len(separator) > 1:
gs.fatal(
_("A standard CSV separator (delimiter) is only one character long")
)

elif output_format == "json":
if no_header:
gs.fatal(_("Column names are always included in JSON output"))
if separator:
gs.fatal(_("Separator option is not allowed with JSON format"))

elif not separator:
separator = "|"

# lazy imports
import grass.temporal as tgis

percentile = None
if options["percentile"]:
try:
Expand Down Expand Up @@ -150,6 +176,7 @@ def main():
rast_region=rast_region,
region_relation=region_relation,
nprocs=nprocs,
format=output_format,
)


Expand Down
Loading
Loading