# sits lens

Learn satellite image time series analysis, the gentle way

An interactive platform for learning time series analysis workflows using the sits R package and friends. We guide you one step at a time.

## The tour

Animation: the 24 monthly images stack into a data cube, one pixel through the cube becomes a time series of NIR08, and a dashed outline marks where the land use map will lie.

### How it was made

1. Cut out the study window: The pipeline finds the window in its tile of a regular cube and cuts it out of every band and month. It keeps the stored values and marks the months a pixel has none.
2. Fill the missing months: Where a pixel has no value in a month, sits fills one in on a straight line between the months around it. At either end of the series it repeats the nearest value.
3. Prepare the pictures: The pipeline picks the brightness drawn black and white, the same for every date, so the dates can be compared. Values are packed into one byte each.
4. Write the files: The pipeline writes the files the website reads, each with a record of its sources and of how closely a rerun repeats it.

### Reproducibility details

- A rerun on aarch64-apple-darwin23 gave the same files, byte for byte.

Every step of the pipeline:

1. Lists the band files of the regular Landsat cube on Hugging Face, at a fixed commit. `hf_cube_files("e-sensing/cerrado_cube_reg_2018", "af1d4f67fee0fcaba35941f4ac5d7d9e87d4fa85")`
2. The study window, chosen as pipeline/legacy/R/01_window.R describes. `list(tile = "009010", col_off = 2208L, row_off = 1536L, size = 256L, resolution = 30L, source = "BDC", collection = "LANDSAT-OLI-16D")`
3. Reads the grid of the window's tile from a band file. `grid_read_tile(hf_resolve_url("e-sensing/cerrado_cube_reg_2018", "af1d4f67fee0fcaba35941f4ac5d7d9e87d4fa85", cube_files$file[cube_files$tile == study_window$tile][[1L]]))`
4. Places the window in the tile's grid. `window_place(tile_grid, study_window)`
5. Crops the window out of the cube's band files by georeference, keeping crops already made. `window_crop_files("cache/windows/window_009010_c2208_r1536/reg", hf_resolve_url("e-sensing/cerrado_cube_reg_2018", "af1d4f67fee0fcaba35941f4ac5d7d9e87d4fa85", hf_tile_files(cube_files, study_window$tile, c("2017-01-01", "2017-02-01", "2017-03-01", "2017-04-01", "2017-05-01", "2017-06-01", "2017-07-01", "2017-08-01", "2017-09-01", "2017-10-01", "2017-11-01", "2017-12-01", "2018-01-01", "2018-02-01", "2018-03-01", "2018-04-01", "2018-05-01", "2018-06-01", "2018-07-01", "2018-08-01", "2018-09-01", "2018-10-01", "2018-11-01", "2018-12-01"))), window_grid, "e-sensing/cerrado_cube_reg_2018", "af1d4f67fee0fcaba35941f4ac5d7d9e87d4fa85", 8L, crop = window_crop_http_files)`
6. Names the bands and months of the crops. `window_crop_layers(window_crops, study_window$source, study_window$collection, c("2017-01-01", "2017-02-01", "2017-03-01", "2017-04-01", "2017-05-01", "2017-06-01", "2017-07-01", "2017-08-01", "2017-09-01", "2017-10-01", "2017-11-01", "2017-12-01", "2018-01-01", "2018-02-01", "2018-03-01", "2018-04-01", "2018-05-01", "2018-06-01", "2018-07-01", "2018-08-01", "2018-09-01", "2018-10-01", "2018-11-01", "2018-12-01"))`
7. Reads how sits scales the bands and marks missing values. `collection_band_values(study_window$source, study_window$collection, window_layers$bands)`
8. Reads the stored values of the crops, missing ones as NA. `window_read_raw(window_crops, window_layers$bands, window_layers$dates, band_scale, study_window$size)`
9. Marks the months each pixel was observed in. `window_observed_mask(window_raw)`
10. Fills the missing months along time with sits::impute_linear(), as sits does before the encoder. `window_fill_series(window_raw, band_scale)`
11. Stores every other pixel's series in one byte per value, each band between two quantiles. `window_export_series(window_series, c(0.001, 0.999 ), 2L)`
12. Picks the reflectance drawn black and white in each colour, the same for every month. `window_export_sprite_stretch(window_series, window_layers$bands, list(red = "SWIR16", green = "NIR08", blue = "RED"), c(0.02, 0.98))`
13. Writes which months of the window were observed, for the website. `site_write_bin(window_export_row_major(window_export_mask(window_mask, 2L)), "../web/public/data/series-mask.bin", "uint8")`
14. Writes the monthly series of the window for the website. `site_write_bin(window_export_row_major(series_quantised$q), "../web/public/data/series.bin", "uint8")`
15. Draws the same sheet of months at a smaller size, for the home page. `site_write_png(window_export_sprite(window_series, window_layers$bands, list(red = "SWIR16", green = "NIR08", blue = "RED"), series_stretch, 32L, 6L, 220L), "../web/public/data/rgb-months-small.png")`

The files:

- `rgb-months-small.png`: SHA-256 `bd5c0bbfc99c92c4c466a12fe81ff5f94b767e310458c27dbeb6b011cb88b2c7`. A rerun on aarch64-apple-darwin23 gave the same file, byte for byte.
- `series.bin`: SHA-256 `0a5dacbfea580c475943a977d3d2fc693788a2449acac1be59416a5b743de112`. A rerun on aarch64-apple-darwin23 gave the same file, byte for byte.
- `series-mask.bin`: SHA-256 `b6c4d861d4986323aa8937eb7efb59cb6cac8e4c8075f41162e82de1babdeecd`. A rerun on aarch64-apple-darwin23 gave the same file, byte for byte.

To make them again: `cd pipeline && Rscript make.R`.

## Journeys with sits

Follow the sits book, one workflow step at a time.

### Representing the data

- [Building data cubes from image collections](/regular-cubes.md): How do the images a provider hands over become a regular data cube? In the sits book: [Analysis-ready image collections](https://e-sensing.github.io/sitsbook/dc_ardcollections.html) and [Building regular data cubes](https://e-sensing.github.io/sitsbook/dc_regularize.html).
- [From series to embeddings](/embeddings.md): How does the time series of a place become a few numbers that say what it is? In the sits book: [Foundational Models and Embeddings](https://e-sensing.github.io/sitsbook/embeddings.html), [Embedding Methods in SITS](https://e-sensing.github.io/sitsbook/emb_methods.html) and [Building regional embeddings: a full example](https://e-sensing.github.io/sitsbook/emb_example.html).
- [From a cube to labelled samples](/time-series.md): How does a place in a cube become a sample whose label we know? In the sits book: [Basic operations on image time series](https://e-sensing.github.io/sitsbook/ts_basics.html) and [Building regional embeddings: a full example](https://e-sensing.github.io/sitsbook/emb_example.html). Picture: Recorded book sample at -57.794, -9.7573, valid 2006-09-14 to 2007-08-29, with supplied label Pasture. The dated row opens beside the NDVI median of 344 samples carrying that label, aligned by day within their reference period.

### Using the data

- [From samples to a land use map](/classification.md): How do labelled samples become a map of land use? In the sits book: [Machine learning algorithms for image time series](https://e-sensing.github.io/sitsbook/cl_machinelearning.html), [Map accuracy assessment](https://e-sensing.github.io/sitsbook/val_map.html) and [Building regional embeddings: a full example](https://e-sensing.github.io/sitsbook/emb_example.html). Picture: Three beats. 1. The samples train the model. 5 labelled time series samples, one per class (Annual crop, Cerradão, Pasture, Sugarcane and Water), each a curve of NIR08 over 24 dates, go into a model. 2. The cube goes into the trained model. A stack of 4 monthly images of the window stands for it. 3. The model labels every pixel: the map. The land use map of the window, classified from time series.

## Beyond sits

Space-time operations with other R packages.

- [From time series to a map of temporal variability](/temporal-variability.md): How does variation through time become a spatial pattern? With stars. Picture: Animation: 8 of the 24 months of the window's NIR08 cube values, gaps left empty, gather into a stack and merge into one map of the temporal standard deviation of 2017–2018.

Every page of the site as text: [/llms.txt](/llms.txt).
