Skip to content

Commit b3a2e9f

Browse files
authored
Merge branch 'master' into pyupgrade-py39-plus
2 parents 5c4812d + 6dab1fe commit b3a2e9f

5 files changed

Lines changed: 333 additions & 1 deletion

File tree

.github/workflows/docs-build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ jobs:
2020
with:
2121
fetch-depth: 0
2222

23+
- name: Install GDAL system dependencies
24+
run: sudo apt-get update && sudo apt-get install -y gdal-bin libgdal-dev
25+
2326
- name: Install uv
2427
uses: astral-sh/setup-uv@v6
2528
with:
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "0",
6+
"metadata": {},
7+
"source": [
8+
"<a href=\"https://githubtocolab.com/gee-community/geemap/blob/master/docs/notebooks/152_extract_timeseries_to_points.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open in Colab\"/></a>\n",
9+
"\n",
10+
"Uncomment the following line to install [geemap](https://geemap.org) if needed."
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"id": "1",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"# %pip install -U geemap"
21+
]
22+
},
23+
{
24+
"cell_type": "markdown",
25+
"id": "2",
26+
"metadata": {},
27+
"source": [
28+
"## Import libraries"
29+
]
30+
},
31+
{
32+
"cell_type": "code",
33+
"execution_count": null,
34+
"id": "3",
35+
"metadata": {},
36+
"outputs": [],
37+
"source": [
38+
"import matplotlib.pyplot as plt\n",
39+
"import ee\n",
40+
"import geemap"
41+
]
42+
},
43+
{
44+
"cell_type": "code",
45+
"execution_count": null,
46+
"id": "4",
47+
"metadata": {},
48+
"outputs": [],
49+
"source": [
50+
"Map = geemap.Map()\n",
51+
"Map"
52+
]
53+
},
54+
{
55+
"cell_type": "markdown",
56+
"id": "5",
57+
"metadata": {},
58+
"source": [
59+
"## Specify Latitude, Longitude, & Date"
60+
]
61+
},
62+
{
63+
"cell_type": "code",
64+
"execution_count": null,
65+
"id": "6",
66+
"metadata": {},
67+
"outputs": [],
68+
"source": [
69+
"# Define the latitude and longitude\n",
70+
"lat = 28.60\n",
71+
"lon = 77.22\n",
72+
"\n",
73+
"# Define time range\n",
74+
"start_date = \"2000-01-01\"\n",
75+
"end_date = \"2015-12-31\""
76+
]
77+
},
78+
{
79+
"cell_type": "markdown",
80+
"id": "7",
81+
"metadata": {},
82+
"source": [
83+
"## Extract ERA5-Land Daily Timeseries"
84+
]
85+
},
86+
{
87+
"cell_type": "code",
88+
"execution_count": null,
89+
"id": "8",
90+
"metadata": {},
91+
"outputs": [],
92+
"source": [
93+
"# Initialize image collection\n",
94+
"image_collection = ee.ImageCollection(\"ECMWF/ERA5_LAND/DAILY_AGGR\")\n",
95+
"\n",
96+
"# Define bands of interest (must match available band names exactly)\n",
97+
"band_names = [\"temperature_2m_min\", \"temperature_2m_max\", \"total_precipitation_sum\"]\n",
98+
"\n",
99+
"# Define the scale\n",
100+
"scale = 11132\n",
101+
"\n",
102+
"# Extract time series at specified latitude and longitude\n",
103+
"result = geemap.extract_timeseries_to_point(\n",
104+
" lat=lat,\n",
105+
" lon=lon,\n",
106+
" image_collection=image_collection,\n",
107+
" band_names=band_names,\n",
108+
" start_date=start_date,\n",
109+
" end_date=end_date,\n",
110+
" scale=scale,\n",
111+
")\n",
112+
"\n",
113+
"# Preview results\n",
114+
"print(result.shape)\n",
115+
"result.head()"
116+
]
117+
},
118+
{
119+
"cell_type": "markdown",
120+
"id": "9",
121+
"metadata": {},
122+
"source": [
123+
"## Extract CHIRPS Daily Precipitation Timeseries"
124+
]
125+
},
126+
{
127+
"cell_type": "code",
128+
"execution_count": null,
129+
"id": "10",
130+
"metadata": {},
131+
"outputs": [],
132+
"source": [
133+
"# Initialize image collection\n",
134+
"image_collection = ee.ImageCollection(\"UCSB-CHG/CHIRPS/DAILY\")\n",
135+
"\n",
136+
"# Define the band name\n",
137+
"band_names = [\"precipitation\"]\n",
138+
"\n",
139+
"# Define the scale\n",
140+
"scale = 5566\n",
141+
"\n",
142+
"# Extract time series at specified latitude and longitude\n",
143+
"result = geemap.extract_timeseries_to_point(\n",
144+
" lat=lat,\n",
145+
" lon=lon,\n",
146+
" image_collection=image_collection,\n",
147+
" band_names=band_names,\n",
148+
" start_date=start_date,\n",
149+
" end_date=end_date,\n",
150+
" scale=scale,\n",
151+
")\n",
152+
"\n",
153+
"# Preview results\n",
154+
"print(result.shape)\n",
155+
"result.head()"
156+
]
157+
},
158+
{
159+
"cell_type": "markdown",
160+
"id": "11",
161+
"metadata": {},
162+
"source": [
163+
"## Extract MODIS Terra Vegetation Indices Timeseries"
164+
]
165+
},
166+
{
167+
"cell_type": "code",
168+
"execution_count": null,
169+
"id": "12",
170+
"metadata": {},
171+
"outputs": [],
172+
"source": [
173+
"# Initialize image collection\n",
174+
"image_collection = ee.ImageCollection(\"MODIS/061/MOD13Q1\")\n",
175+
"\n",
176+
"# Define the band names\n",
177+
"band_names = [\"NDVI\", \"EVI\"]\n",
178+
"\n",
179+
"# Define the scale\n",
180+
"scale = 250\n",
181+
"\n",
182+
"# Extract time series at specified latitude and longitude\n",
183+
"result = geemap.extract_timeseries_to_point(\n",
184+
" lat=28.60,\n",
185+
" lon=77.22,\n",
186+
" image_collection=image_collection,\n",
187+
" band_names=band_names,\n",
188+
" start_date=start_date,\n",
189+
" end_date=end_date,\n",
190+
" scale=scale,\n",
191+
")\n",
192+
"\n",
193+
"# Preview results\n",
194+
"print(result.shape)\n",
195+
"result.head()"
196+
]
197+
},
198+
{
199+
"cell_type": "markdown",
200+
"id": "13",
201+
"metadata": {},
202+
"source": [
203+
"## Plot the Timeseries"
204+
]
205+
},
206+
{
207+
"cell_type": "code",
208+
"execution_count": null,
209+
"id": "14",
210+
"metadata": {},
211+
"outputs": [],
212+
"source": [
213+
"# Simple plot\n",
214+
"plt.figure(figsize=(12, 5))\n",
215+
"\n",
216+
"for band in [\"NDVI\", \"EVI\"]:\n",
217+
" plt.plot(\n",
218+
" result[\"time\"], result[band] * 0.0001, label=band\n",
219+
" ) # apply scale factor of 0.0001\n",
220+
"\n",
221+
"plt.title(f\"NDVI & EVI Time Series at {lat, lon}\")\n",
222+
"plt.xlabel(\"Date\")\n",
223+
"plt.ylabel(\"Value\")\n",
224+
"plt.legend()\n",
225+
"plt.tight_layout()\n",
226+
"plt.show()"
227+
]
228+
}
229+
],
230+
"metadata": {
231+
"kernelspec": {
232+
"display_name": "geo",
233+
"language": "python",
234+
"name": "geo"
235+
},
236+
"language_info": {
237+
"codemirror_mode": {
238+
"name": "ipython",
239+
"version": 3
240+
},
241+
"file_extension": ".py",
242+
"mimetype": "text/x-python",
243+
"name": "python",
244+
"nbconvert_exporter": "python",
245+
"pygments_lexer": "ipython3",
246+
"version": "3.12.11"
247+
}
248+
},
249+
"nbformat": 4,
250+
"nbformat_minor": 5
251+
}

geemap/common.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7760,6 +7760,83 @@ def extract_values_to_points(
77607760
return result
77617761

77627762

7763+
def extract_timeseries_to_point(
7764+
lat,
7765+
lon,
7766+
image_collection,
7767+
start_date,
7768+
end_date,
7769+
band_names,
7770+
scale=None,
7771+
crs=None,
7772+
crsTransform=None,
7773+
out_df=None,
7774+
):
7775+
"""
7776+
Extracts pixel time series from an ee.ImageCollection at a point.
7777+
7778+
Args:
7779+
lat (float): Latitude of the point.
7780+
lon (float): Longitude of the point.
7781+
image_collection (ee.ImageCollection): Image collection to sample.
7782+
start_date (str): Start date (e.g., '2020-01-01').
7783+
end_date (str): End date (e.g., '2020-12-31').
7784+
band_names (list): List of bands to extract.
7785+
scale (float): Sampling scale in meters.
7786+
crs (str, optional): Projection CRS. Defaults to image CRS.
7787+
crsTransform (list, optional): CRS transform matrix (3x2 row-major). Overrides scale.
7788+
out_df (str, optional): File path to save CSV. If None, returns a DataFrame.
7789+
7790+
Returns:
7791+
pd.DataFrame or None: Time series data if not exporting to CSV.
7792+
"""
7793+
7794+
import pandas as pd
7795+
from datetime import datetime
7796+
7797+
if not isinstance(image_collection, ee.ImageCollection):
7798+
raise ValueError("image_collection must be an instance of ee.ImageCollection.")
7799+
7800+
property_names = image_collection.first().propertyNames().getInfo()
7801+
if "system:time_start" not in property_names:
7802+
raise ValueError("The image collection lacks the 'system:time_start' property.")
7803+
7804+
point = ee.Geometry.Point([lon, lat])
7805+
7806+
try:
7807+
image_collection = (
7808+
image_collection.filterBounds(point)
7809+
.filterDate(start_date, end_date)
7810+
.select(band_names)
7811+
)
7812+
except Exception as e:
7813+
raise RuntimeError(f"Error filtering image collection: {e}")
7814+
7815+
try:
7816+
result = image_collection.getRegion(
7817+
geometry=point, scale=scale, crs=crs, crsTransform=crsTransform
7818+
).getInfo()
7819+
7820+
result_df = pd.DataFrame(result[1:], columns=result[0])
7821+
7822+
if result_df.empty:
7823+
raise ValueError(
7824+
"Extraction returned an empty DataFrame. Check your point, date range, or selected bands."
7825+
)
7826+
7827+
result_df["time"] = result_df["time"].apply(
7828+
lambda t: datetime.utcfromtimestamp(t / 1000)
7829+
)
7830+
7831+
if out_df:
7832+
result_df.to_csv(out_df, index=False)
7833+
else:
7834+
return result_df
7835+
7836+
except Exception as e:
7837+
raise RuntimeError(f"Error extracting data: {e}.")
7838+
7839+
77637840
def image_reclassify(img, in_list, out_list):
77647841
"""Reclassify an image.
77657842

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ nav:
312312
- notebooks/149_gemini.ipynb
313313
- notebooks/150_maplibre.ipynb
314314
- notebooks/151_dataset_explorer.ipynb
315+
- notebooks/152_extract_timeseries_to_point.ipynb
315316
# - miscellaneous:
316317
# - notebooks/cartoee_colab.ipynb
317318
# - notebooks/cartoee_colorbar.ipynb

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ classifiers = [
2828
dependencies = [
2929
"anywidget",
3030
"bqplot",
31-
"earthengine-api>=1.0.0",
31+
"earthengine-api>=1.5.12",
3232
"eerepr>=0.1.0",
3333
"folium>=0.17.0",
3434
"geocoder",

0 commit comments

Comments
 (0)