Skip to content

Commit 07c0314

Browse files
committed
Update README.md
1 parent 72a390b commit 07c0314

File tree

4 files changed

+138
-14
lines changed

4 files changed

+138
-14
lines changed

README.md

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,123 @@ For a complete list of examples and use cases, visit the [notebooks](https://git
4242

4343
## Key Features
4444

45-
- Extracting long-term time series data from GEE for both point and polygon geometries.
46-
- Extract image patches from satellite imagery in GEE to support local-scale computer vision model training.
47-
- Quickly transform complex multivariate datasets into a few principal components while preserving critical information.
48-
- Easy implementation of Harmonic Regression on vegetation or climate indices.
45+
* **Long-term Time Series Extraction** — Retrieve satellite or climate time series from Google Earth Engine (GEE) for both point and polygon geometries.
46+
* **Image Patch Generation** — Extract image tiles or patches from satellite imagery in GEE to support local-scale computer vision or deep learning model training.
47+
* **Multivariate Dimensionality Reduction** — Transform complex multivariate datasets into a few principal components while preserving essential information using PCA.
48+
* **Harmonic Regression Analysis** — Easily perform harmonic regression on vegetation or climate indices to study seasonal and periodic trends.
49+
* **Cloud-free Time Series Creation** — Generate regular, gap-filled, and cloud-free time series from irregular satellite observations.
50+
* **Phenology and Smoothing Tools** — Apply smoothing algorithms and extract phenological metrics (Start of Season, Peak of Season, End of Season) from high-resolution satellite data.
51+
52+
---
53+
54+
## Installation
55+
```bash
56+
conda create -n geeagri python=3.10
57+
conda activate geeagri
58+
pip install geeagri
59+
# (Optional) Upgrade to the latest version if already installed
60+
pip install --upgrade geeagri
61+
```
62+
63+
---
64+
65+
## Example Usage
66+
67+
#### Example 1: Extract timeseries to point
68+
```python
69+
import ee
70+
import geeagri
71+
from geeagri.extract import extract_timeseries_to_point
72+
73+
# Authenticate and initialize the Earth Engine API
74+
ee.Authenticate()
75+
ee.Initialize()
76+
77+
# Define point location (longitude, latitude)
78+
lon, lat = -98.15, 30.50
79+
point = ee.Geometry.Point([lon, lat])
80+
81+
# Load ERA5-Land daily aggregated climate dataset
82+
era5_land = ee.ImageCollection("ECMWF/ERA5_LAND/DAILY_AGGR")
83+
84+
# Extract daily temperature, precipitation, and solar radiation time series
85+
era5_land_point_ts = extract_timeseries_to_point(
86+
lat=lat,
87+
lon=lon,
88+
image_collection=era5_land,
89+
start_date="2020-01-01",
90+
end_date="2021-01-01",
91+
band_names=[
92+
"temperature_2m_min",
93+
"temperature_2m_max",
94+
"total_precipitation_sum",
95+
"surface_solar_radiation_downwards_sum",
96+
],
97+
scale=11132, # spatial resolution in meters (~11 km)
98+
)
99+
```
100+
This example demonstrates how to use `geeagri` to extract daily climate variable time series (temperature, precipitation, and solar radiation) from the **ERA5-Land** dataset at a specific geographic point using the Google Earth Engine (GEE) Python API.
101+
102+
**Output Plot:**
103+
![ERA5-Land Temperature Time Series](paper/figure.png)
104+
105+
#### Example 2: Create regular satellite timeseries
106+
```python
107+
import ee
108+
from geeagri.preprocessing import Sentinel2CloudMask, RegularTimeseries
109+
110+
# Authenticate and initialize the Earth Engine API
111+
ee.Authenticate()
112+
ee.Initialize()
113+
114+
# Define the bounding box
115+
bbox = [-98.451233, 38.430732, -98.274765, 38.523996]
116+
region = ee.Geometry.BBox(*bbox)
117+
118+
# Get cloud masked Sentinel-2 image collection
119+
s2_cloud_masker = Sentinel2CloudMask(
120+
region=region,
121+
start_date="2020-01-01",
122+
end_date="2021-01-01",
123+
cloud_filter=60,
124+
cloud_prob_threshold=50,
125+
nir_dark_threshold=0.15,
126+
shadow_proj_dist=1,
127+
buffer=50
128+
)
129+
130+
s2_cloud_masked = s2_cloud_masker.get_cloudfree_collection()
131+
132+
# Calculate NDVI
133+
def calculateNDVI(image):
134+
ndvi = image.expression(
135+
"(NIR - Red) / (NIR + Red)",
136+
{"NIR": image.select("B8"), "Red": image.select("B4")},
137+
).copyProperties(image, ["system:time_start"])
138+
139+
ndvi = ee.Image(ndvi).rename("ndvi").clip(region)
140+
141+
return ndvi
142+
143+
144+
ndvi_col = s2_cloud_masked.map(calculateNDVI)
145+
146+
# Instantiate a 'RegularTimeseries' object
147+
reg_timeseries = RegularTimeseries(
148+
image_collection=ndvi_col,
149+
interval=5, # Interval (in days) between consecutive target dates
150+
window=45, # Temporal window in days
151+
)
152+
153+
# Get the regular timeseries
154+
ndvi_regular = reg_timeseries.get_regular_timeseries()
155+
```
156+
This example demonstrates how to extract a regular, gap-filled NDVI time series from Sentinel-2 imagery using `geeagri`. First, a `Sentinel2CloudMask` object is created to mask clouds and shadows over a defined bounding box using thresholds for cloud probability, dark NIR pixels, and shadow projection. The cloud-masked images are then processed with a custom function to calculate NDVI for each image. Finally, a `RegularTimeseries` object generates a temporally consistent NDVI time series at a specified interval and temporal window. This workflow allows users to efficiently obtain high-quality, regular NDVI time series from raw Sentinel-2 imagery while handling cloud and shadow contamination.
157+
158+
**Raw NDVI Time Series with Cloud Gaps:**
159+
![Raw Satellite Time Series with Cloud Gaps](docs/assets/ndvi_raw.gif)
160+
161+
**Regular Gap-filled NDVI Time Series:**
162+
![Regular Gap-filled NDVI Time Series](docs/assets/ndvi_regular.gif)
49163

50164
---

docs/assets/ndvi_raw.gif

9.32 MB
Loading

docs/assets/ndvi_regular.gif

10.4 MB
Loading

paper/paper.bib

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ @article{gorelick2017google
55
volume={202},
66
pages={18--27},
77
year={2017},
8-
publisher={Elsevier}
8+
publisher={Elsevier},
9+
doi={10.1016/j.rse.2017.06.031}
910
}
1011
1112
@article{wu2020geemap,
@@ -15,7 +16,8 @@ @article{wu2020geemap
1516
volume={5},
1617
number={51},
1718
pages={2305},
18-
year={2020}
19+
year={2020},
20+
doi={10.21105/joss.02305}
1921
}
2022
2123
@article{ines2013assimilation,
@@ -25,7 +27,8 @@ @article{ines2013assimilation
2527
volume={138},
2628
pages={149--164},
2729
year={2013},
28-
publisher={Elsevier}
30+
publisher={Elsevier},
31+
doi={10.1016/j.rse.2013.07.018}
2932
}
3033
3134
@article{zhu2017deep,
@@ -36,7 +39,8 @@ @article{zhu2017deep
3639
number={4},
3740
pages={8--36},
3841
year={2017},
39-
publisher={IEEE}
42+
publisher={IEEE},
43+
doi={10.1109/MGRS.2017.2762307}
4044
}
4145
4246
@article{beck2006improved,
@@ -47,7 +51,8 @@ @article{beck2006improved
4751
number={3},
4852
pages={321--334},
4953
year={2006},
50-
publisher={Elsevier}
54+
publisher={Elsevier},
55+
doi={10.1016/j.rse.2005.10.021}
5156
}
5257
5358
@article{drusch2012sentinel,
@@ -57,7 +62,8 @@ @article{drusch2012sentinel
5762
volume={120},
5863
pages={25--36},
5964
year={2012},
60-
publisher={Elsevier}
65+
publisher={Elsevier},
66+
doi={10.1016/j.rse.2011.11.026}
6167
}
6268
6369
@article{wulder2016global,
@@ -67,7 +73,8 @@ @article{wulder2016global
6773
volume={185},
6874
pages={271--283},
6975
year={2016},
70-
publisher={Elsevier}
76+
publisher={Elsevier},
77+
doi={10.1016/j.rse.2015.11.032}
7178
}
7279
7380
@article{chen2004simple,
@@ -78,7 +85,8 @@ @article{chen2004simple
7885
number={3-4},
7986
pages={332--344},
8087
year={2004},
81-
publisher={Elsevier}
88+
publisher={Elsevier},
89+
doi={10.1016/j.rse.2004.03.014}
8290
}
8391
8492
@article{jonsson2004timesat,
@@ -89,7 +97,8 @@ @article{jonsson2004timesat
8997
number={8},
9098
pages={833--845},
9199
year={2004},
92-
publisher={Elsevier}
100+
publisher={Elsevier},
101+
doi={10.1016/j.cageo.2004.05.006}
93102
}
94103
95104
@article{mckinney2010data,
@@ -99,5 +108,6 @@ @article{mckinney2010data
99108
volume={445},
100109
number={1},
101110
pages={51--56},
102-
year={2010}
111+
year={2010},
112+
doi={10.25080/Majora-92bf1922-00a}
103113
}

0 commit comments

Comments
 (0)