Skip to content

Commit 358db88

Browse files
committed
Time series tutorials: Adding part 7 - Subset, import & export
1 parent 37a4448 commit 358db88

File tree

1 file changed

+279
-0
lines changed

1 file changed

+279
-0
lines changed
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
---
2+
title: "Time series: Subset, import and export"
3+
author: "Veronica Andreo"
4+
date: 2024-08-19
5+
date-modified: today
6+
lightbox: true
7+
format:
8+
ipynb: default
9+
html:
10+
toc: true
11+
code-tools: true
12+
code-copy: true
13+
code-fold: false
14+
categories: [time series, raster, intermediate, Python]
15+
description: Tutorial on time series subsetting, import and export.
16+
engine: jupyter
17+
execute:
18+
eval: false
19+
jupyter: python3
20+
---
21+
22+
In this seventh time series tutorial, we will go through time
23+
series subset, import and export.
24+
25+
::: {.callout-note title="Setup"}
26+
This tutorial can be run locally or in Google Colab. However, make sure you
27+
install GRASS 8.4+, download the
28+
[LST sample dataset](https://zenodo.org/doi/10.5281/zenodo.3564514)
29+
and set up your project as explained in the
30+
[first](time_series_management_and_visualization.qmd) time
31+
series tutorial.
32+
:::
33+
34+
```{python}
35+
#| echo: false
36+
37+
import os
38+
import sys
39+
import subprocess
40+
41+
# Ask GRASS where its Python packages are
42+
sys.path.append(
43+
subprocess.check_output(["grass", "--config", "python_path"], text=True).strip()
44+
)
45+
# Import the GRASS packages we need
46+
import grass.script as gs
47+
import grass.jupyter as gj
48+
49+
path_to_project = "italy_eu_laea/italy_LST_daily"
50+
51+
# Start the GRASS Session
52+
session = gj.init(path_to_project)
53+
```
54+
55+
## Subset
56+
57+
For extracting a subset from a STRDS, we use
58+
[t.rast.extract](https://grass.osgeo.org/grass-stable/manuals/t.rast.extract.html).
59+
The subset is based on temporal variables like `start_time`, `start_doy`,
60+
`end_week`, etc.
61+
This tool outputs a new STRDS and offers the possibility to apply a
62+
mapcalc operation on the fly. If no *r.mapcalc* expression is defined,
63+
the selected maps are simply registered in the newly created output STRDS
64+
to avoid data duplication.
65+
66+
Let's see a couple of examples. Suppose we are only interested in northern summer
67+
months, i.e., June, July, August. The maps matching the where condition will be
68+
registered in the new output STRDS.
69+
70+
```{python}
71+
gs.run_command("t.rast.extract",
72+
input="lst_daily",
73+
output="lst_daily_summer",
74+
where="strftime('%m',start_time)='06' or strftime('%m',start_time)='07' or strftime('%m', start_time)='08'")
75+
```
76+
77+
If you remember, we went through several listing examples in the
78+
[Time series management and visualization](time_series_management_and_visualization.qmd) tutorial.
79+
To check the subset will actually give us what we want, we can run
80+
[t.rast.list](https://grass.osgeo.org/grass-stable/manuals/t.rast.list.html)
81+
with the same `where` condition as above.
82+
83+
```{python}
84+
#| scrolled: true
85+
gs.run_command("t.rast.list",
86+
input="lst_daily_summer",
87+
columns="name,min,max")
88+
```
89+
90+
To check whether a map is registered in different time series objects, we can use
91+
[t.info](https://grass.osgeo.org/grass-stable/manuals/t.info.html).
92+
93+
```{python}
94+
gs.run_command("t.info",
95+
input="lst_2018.243_avg",
96+
type="raster")
97+
```
98+
99+
Let's see now an example including a mapcalc operation. We still want the daily
100+
maps of summer, but we are only interested in areas where LST was higher than
101+
25 degrees.
102+
Note that in this second case, we are creating a new STRDS, i.e., we modify the
103+
original with the mapcalc expression, so we need to provide `basename` and `suffix`
104+
for the newly created maps.
105+
106+
```{python}
107+
gs.run_command("t.rast.extract",
108+
input="lst_daily",
109+
output="lst_daily_summer_higher_25",
110+
basename="lst_daily",
111+
suffix="gran",
112+
where="strftime('%m',start_time)='06' or strftime('%m',start_time)='07' or strftime('%m', start_time)='08'",
113+
expression="if(lst_daily < 25.0, null(), lst_daily)")
114+
```
115+
116+
Check that the minimum value of all extracted maps are actually above 25 degrees.
117+
118+
```{python}
119+
#| scrolled: true
120+
gs.run_command("t.rast.list",
121+
input="lst_daily_summer_higher_25",
122+
columns="name,min,max")
123+
```
124+
125+
What tools would you use now if you wanted to know how many summer days had
126+
temperatures above 25 degrees each year and how does the maximum number of days
127+
with LST > 25 varies regionally?
128+
129+
**Small hint?** Go back to the time series
130+
[aggregation](time_series_aggregations.qmd) tutorial.
131+
132+
```{python}
133+
# Get number of summer days with LST > 25 per year
134+
gs.run_command("t.rast.aggregate",
135+
input="lst_daily_summer_higher_25",
136+
output="count_lst_daily_summer_higher_25",
137+
basename="count_lst_daily_summer_higher_25",
138+
suffix="gran",
139+
method="count",
140+
granularity="1 year")
141+
```
142+
143+
```{python}
144+
# Get maximum number of days with LST > 25
145+
gs.run_command("t.rast.series",
146+
input="count_lst_daily_summer_higher_25",
147+
output="max_count_summer_days_lst_higher_25",
148+
method="maximum")
149+
```
150+
151+
```{python}
152+
# Mask zero values
153+
gs.run_command("r.mask",
154+
raster="max_count_summer_days_lst_higher_25",
155+
maskcats=0,
156+
flags="i")
157+
```
158+
159+
```{python}
160+
# Visualize the result
161+
max_count = gj.InteractiveMap(tiles="CartoDB.DarkMatter")
162+
max_count.add_raster("max_count_summer_days_lst_higher_25")
163+
max_count.show()
164+
```
165+
166+
## Export
167+
168+
There are three tools to export raster time series in different formats.
169+
170+
* [t.rast.export](https://grass.osgeo.org/grass-stable/manuals/t.rast.export.html) exports a strds as a tar archive containing raster maps either as GeoTIFF or GRASS binary files and several metadata files such as: timestamps, CRS info, strds and raster info. The archive can be compressed with gzip or bzip2. The output of *t.rast.export* can then be imported with [t.rast.import](https://grass.osgeo.org/grass-stable/manuals/t.rast.import.html).
171+
* [t.rast.out.vtk](https://grass.osgeo.org/grass-stable/manuals/t.rast.out.vtk.html) exports a strds as a VTK file to be visualized with any VTK visualizer.
172+
* [t.rast.out.xyz](https://grass.osgeo.org/grass-stable/manuals/addons/t.rast.out.xyz.html) exports a strds to a CSV file of the form x coord, y coord, value.
173+
174+
Let's see some examples.
175+
176+
```{python}
177+
# Export strds as an archive
178+
gs.run_command("t.rast.export",
179+
input="lst_daily_summer",
180+
output="lst_daily_summer_2014.tar.bzip2",
181+
where="start_time < '2015-01-01'")
182+
```
183+
184+
```{python}
185+
!tar tjf lst_daily_summer_2014.tar.bzip2
186+
```
187+
188+
```
189+
lst_2014.152_avg.tif
190+
lst_2014.152_avg.color
191+
...
192+
lst_2014.243_avg.tif
193+
lst_2014.243_avg.color
194+
list.txt
195+
proj.txt
196+
init.txt
197+
readme.txt
198+
metadata.txt
199+
```
200+
201+
```{python}
202+
# Export strds as VTK
203+
gs.run_command("t.rast.out.vtk",
204+
input="count_lst_daily_summer_higher_25",
205+
directory="/tmp",
206+
elevation="elevation")
207+
```
208+
209+
The tool *t.rast.out.xyz* is an addon, so we first need to install it with *g.extension*.
210+
211+
```{python}
212+
# Install extension
213+
gs.run_command("g.extension", extension="t.rast.out.xyz")
214+
```
215+
216+
```{python}
217+
# Export strds as xyz CSV file
218+
gs.run_command("t.rast.out.xyz",
219+
strds="count_lst_daily_summer_higher_25",
220+
output="count_lst_daily_summer_higher_25.csv")
221+
```
222+
223+
```{python}
224+
!head count_lst_daily_summer_higher_25.csv
225+
```
226+
227+
## Import
228+
229+
There are two tools to import raster time series into GRASS GIS:
230+
231+
* [t.rast.import](https://grass.osgeo.org/grass-stable/manuals/t.rast.import.html) imports strds that were exported with *t.rast.export*. It allows to create a new GRASS project with the imported data CRS and set the computational region to the raster maps imported.
232+
* [t.rast.import.netcdf](https://grass.osgeo.org/grass-stable/manuals/addons/t.rast.import.netcdf.html) imports the content of one or more netCDF files that adhere to the CF convention into a strds. Data can be imported or linked via [r.external](https://grass.osgeo.org/grass-stable/manuals/r.external.html).
233+
234+
Let's see an example with *t.rast.import*.
235+
236+
```{python}
237+
# Import the exported strds into a new GRASS project
238+
gs.run_command("t.rast.import",
239+
input="lst_daily_summer_2014.tar.bzip2",
240+
output="lst_daily_summer_new",
241+
title="Daily summer LST",
242+
description="Daily summer LST for 2014")
243+
```
244+
245+
```{python}
246+
# Check the new strds was created
247+
gs.run_command("t.list", where="NAME LIKE '%summer%'")
248+
```
249+
250+
:::{.callout-note title="What about vector time series?"}
251+
While not covered in this tutorial, there are also dedicated tools for subsetting, importing and exporting vector time series objects. These are:
252+
253+
* [t.vect.extract](https://grass.osgeo.org/grass-stable/manuals/t.vect.extract.html)
254+
* [t.vect.export](https://grass.osgeo.org/grass-stable/manuals/t.vect.export.html)
255+
* [t.vect.import](https://grass.osgeo.org/grass-stable/manuals/t.vect.import.html)
256+
:::
257+
258+
259+
## References
260+
261+
- Gebbert, S., Pebesma, E. 2014.
262+
_TGRASS: A temporal GIS for field based environmental modeling._
263+
Environmental Modelling & Software 53, 1-12.
264+
[DOI](http://dx.doi.org/10.1016/j.envsoft.2013.11.001).
265+
- Gebbert, S., Pebesma, E. 2017. _The GRASS GIS temporal framework._
266+
International Journal of Geographical Information Science 31, 1273-1292.
267+
[DOI](http://dx.doi.org/10.1080/13658816.2017.1306862).
268+
- [Temporal data processing](https://grasswiki.osgeo.org/wiki/Temporal_data_processing) wiki page.
269+
270+
271+
***
272+
273+
:::{.smaller}
274+
The development of this tutorial was funded by the US
275+
[National Science Foundation (NSF)](https://www.nsf.gov/),
276+
award [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).
277+
:::
278+
279+

0 commit comments

Comments
 (0)