Skip to content

Commit b91f9cc

Browse files
authored
Time series tutorials: Adding part 7 - Subset, import & export (#64)
1 parent afe055c commit b91f9cc

File tree

2 files changed

+280
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)