From 4be38f3c031d610824c847b34bc1a31838669ecd Mon Sep 17 00:00:00 2001 From: James Oluwadare Date: Sat, 26 Jul 2025 22:28:51 +0100 Subject: [PATCH 1/3] updated the intro notebook, and created a new example notebook for harmonic regression and updated the timeseries and usage documentation --- README.md | 2 +- docs/examples/harmonic_regression.ipynb | 172 ++++++++++++++++++++++++ docs/examples/intro.ipynb | 94 ++++++++++++- docs/timeseries.md | 58 +++++++- docs/usage.md | 68 +++++++++- 5 files changed, 389 insertions(+), 5 deletions(-) create mode 100644 docs/examples/harmonic_regression.ipynb diff --git a/README.md b/README.md index c7ddff3..cbc9cd9 100644 --- a/README.md +++ b/README.md @@ -45,4 +45,4 @@ For a complete list of examples and use cases, visit the [notebooks](https://git - Extracting long-term time series data from GEE for both point and polygon geometries. - Easy implementation of Harmonic Regression on vegetation or climate indices. ---- \ No newline at end of file +--- diff --git a/docs/examples/harmonic_regression.ipynb b/docs/examples/harmonic_regression.ipynb new file mode 100644 index 0000000..f2642fc --- /dev/null +++ b/docs/examples/harmonic_regression.ipynb @@ -0,0 +1,172 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a216a3e7", + "metadata": {}, + "source": [ + "# Harmonic Regression Analysis with geeagri\n", + "\n", + "This notebook demonstrates how to use the `HarmonicRegression` class in geeagri to analyze time series data from satellite imagery using Google Earth Engine." + ] + }, + { + "cell_type": "markdown", + "id": "b296e5fd", + "metadata": {}, + "source": [ + "## Setup and Imports\n", + "Install geeagri if needed and import required libraries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79451c17", + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install geeagri\n", + "import ee\n", + "import geeagri\n", + "from geeagri.timeseries import HarmonicRegression\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "859cd383", + "metadata": {}, + "outputs": [], + "source": [ + "ee.Authenticate()\n", + "ee.Initialize()" + ] + }, + { + "cell_type": "markdown", + "id": "de03bed4", + "metadata": {}, + "source": [ + "## Select Region and Data\n", + "Define a point of interest and select an image collection and band for analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fea86aad", + "metadata": {}, + "outputs": [], + "source": [ + "lat, lon = 37.0510, -120.3022 # Example: Central California\n", + "point = ee.Geometry.Point([lon, lat])\n", + "\n", + "collection = ee.ImageCollection('MODIS/061/MOD13Q1')\n", + "band = 'NDVI'\n", + "start_date = '2015-01-01'\n", + "end_date = '2017-01-01'\n", + "scale = 250" + ] + }, + { + "cell_type": "markdown", + "id": "872404d3", + "metadata": {}, + "source": [ + "## Extract Time Series\n", + "Extract the NDVI time series for the selected point." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31e1252b", + "metadata": {}, + "outputs": [], + "source": [ + "df = geeagri.extract_timeseries_to_point(\n", + " lat, lon, collection, start_date, end_date, band_names=[band], scale=scale\n", + ")\n", + "df['NDVI'] = df['NDVI'] * 0.0001 # Apply scale factor for MODIS NDVI\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "2f1d5d98", + "metadata": {}, + "source": [ + "## Fit Harmonic Regression\n", + "Create a HarmonicRegression object and fit the model to the NDVI time series." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5cadce5", + "metadata": {}, + "outputs": [], + "source": [ + "ref_date = start_date\n", + "order = 2 # Number of harmonics\n", + "hr = HarmonicRegression(collection, ref_date, band, order=order)\n", + "harmonic_coeffs = hr.get_harmonic_coeffs()" + ] + }, + { + "cell_type": "markdown", + "id": "d39fa8a3", + "metadata": {}, + "source": [ + "## Visualize Fitted Harmonics\n", + "Compute and plot the fitted harmonic time series alongside the original NDVI data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f766f8f", + "metadata": {}, + "outputs": [], + "source": [ + "fitted_coll = hr.get_fitted_harmonics(harmonic_coeffs)\n", + "# Extract fitted values at the point\n", + "fitted_list = fitted_coll.getRegion(point, scale=scale).getInfo()\n", + "fitted_df = pd.DataFrame(fitted_list[1:], columns=fitted_list[0])\n", + "fitted_df['time'] = pd.to_datetime(fitted_df['time'], unit='ms')\n", + "fitted_df = fitted_df[['time', 'fitted']].dropna()\n", + "# Merge with original NDVI\n", + "merged = pd.merge(df, fitted_df, on='time', how='inner')\n", + "plt.figure(figsize=(10,5))\n", + "plt.plot(merged['time'], merged['NDVI'], label='Observed NDVI', marker='o')\n", + "plt.plot(merged['time'], merged['fitted'], label='Fitted Harmonic', linestyle='--')\n", + "plt.xlabel('Date')\n", + "plt.ylabel('NDVI')\n", + "plt.title('Harmonic Regression Fit to NDVI Time Series')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "69e3fac8", + "metadata": {}, + "source": [ + "## Next Steps\n", + "- Try different harmonic orders for more/less complex fits.\n", + "- Use other bands or regions.\n", + "- Explore phase and amplitude extraction for phenology analysis." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/intro.ipynb b/docs/examples/intro.ipynb index bfccccb..3d66a0c 100644 --- a/docs/examples/intro.ipynb +++ b/docs/examples/intro.ipynb @@ -1,12 +1,104 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction to geeagri\n", + "geeagri is a Python package for agricultural monitoring and analysis using Google Earth Engine (GEE). It provides utilities for extracting, analyzing, and visualizing time series data from satellite imagery.\n", + "\n", + "## Features\n", + "- Extract time series data for points and polygons\n", + "- Perform harmonic regression on time series\n", + "- Visualize and export results\n", + "- Built on Google Earth Engine and pandas\n", + "\n", + "## Installation\n", + "Install the latest release from PyPI:\n", + "```bash\n", + "pip install geeagri\n", + "```\n", + "Or install the development version:\n", + "```bash\n", + "pip install git+https://github.com/geonextgis/geeagri\n", + "```\n", + "\n", + "## Getting Started\n", + "Below is a basic example of how to use geeagri to extract a time series from a point." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Import geeagri\n", + "import geeagri\n", + "\n", + "# Import Earth Engine\n", + "import ee\n", + "\n", + "# Authenticate and initialize Earth Engine\n", + "# This step is necessary to access Earth Engine's functionalities.\n", + "# \n", + "ee.Authenticate()\n", + "ee.Initialize(project='your-project-id') # Replace 'your-project-id' with your actual project ID\n", + "# ee.Initialize() # Uncomment this line if you want to initialize without specifying a project ID" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extracting a Time Series for a Point\n", + "You can extract a time series of a specific band (e.g., NDVI) at a given latitude and longitude using the `extract_timeseries_to_point` function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Extract NDVI time series at a point\n", + "lat = 6.5244 # Example: Lagos, Nigeria\n", + "lon = 3.3792\n", + "\n", + "collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')\n", + "band = 'NDVI'\n", + "start_date = '2020-01-01'\n", + "end_date = '2020-12-31'\n", + "scale = 30\n", + "\n", + "df = geeagri.extract_timeseries_to_point(\n", + " lat, lon, collection, start_date, end_date, band_names=[band], scale=scale)\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The above code returns a pandas DataFrame with the NDVI values at the specified point for each date in the selected period.\n", + "\n", + "You can now visualize or analyze the time series as needed." + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "print(\"Hello World!\")" + "# Plot the NDVI time series using matplotlib\n", + "import matplotlib.pyplot as plt\n", + "\n", + "df.plot(x='time', y='NDVI', marker='o', linestyle='-')\n", + "plt.title('NDVI Time Series at Point')\n", + "plt.xlabel('Date')\n", + "plt.ylabel('NDVI')\n", + "plt.show()" ] } ], diff --git a/docs/timeseries.md b/docs/timeseries.md index d97d923..014ef94 100644 --- a/docs/timeseries.md +++ b/docs/timeseries.md @@ -1,4 +1,60 @@ # timeseries module -::: geeagri.timeseries \ No newline at end of file +geeagri.timeseries provides tools for extracting and analyzing time series data from Google Earth Engine. Below are the main functions and classes: + +## extract_timeseries_to_point + +Extracts pixel time series from an ee.ImageCollection at a point. + +**Example:** + +```python +import geeagri +import ee +ee.Authenticate() +ee.Initialize() + +lat, lon = 6.5244, 3.3792 +collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') +df = geeagri.extract_timeseries_to_point( + lat, lon, collection, start_date='2020-01-01', end_date='2020-12-31', band_names=['NDVI'], scale=30 +) +print(df.head()) +``` + +## extract_timeseries_to_polygon + +Extracts time series statistics over a polygon from an ee.ImageCollection. + + +**Example:** + +```python +polygon = ee.Geometry.Polygon([ + [[3.37, 6.52], [3.38, 6.52], [3.38, 6.53], [3.37, 6.53], [3.37, 6.52]] +]) +df_poly = geeagri.extract_timeseries_to_polygon( + polygon, collection, start_date='2020-01-01', end_date='2020-12-31', band_names=['NDVI'], scale=30, reducer="MEAN" +) +print(df_poly.head()) +``` + +## HarmonicRegression + +Class for performing harmonic regression on an Earth Engine ImageCollection. + + +**Example:** + +```python +from geeagri.timeseries import HarmonicRegression + +ref_date = '2020-01-01' +order = 2 +hr = HarmonicRegression(collection, ref_date, 'NDVI', order=order) +harmonic_coeffs = hr.get_harmonic_coeffs() +fitted = hr.get_fitted_harmonics(harmonic_coeffs) +``` + +See the example notebooks for more advanced workflows and visualizations. diff --git a/docs/usage.md b/docs/usage.md index 729b9f7..96f4479 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,7 +1,71 @@ + # Usage -To use geeagri in a project: +geeagri provides utilities for extracting, analyzing, and visualizing time series data from Google Earth Engine. Below are some common usage examples. -``` + +## 1. Importing geeagri + +```python import geeagri ``` + +ee.Initialize() +df = geeagri.extract_timeseries_to_point( + +## 2. Extracting a Time Series at a Point + +```python +import ee +ee.Authenticate() +ee.Initialize() + +lat, lon = 6.5244, 3.3792 # Example: Lagos, Nigeria +collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') +band = 'NDVI' +start_date = '2020-01-01' +end_date = '2020-12-31' +scale = 30 +df = geeagri.extract_timeseries_to_point( + lat, lon, collection, start_date, end_date, band_names=[band], scale=scale +) +print(df.head()) +``` + +df_poly = geeagri.extract_timeseries_to_polygon( + +## 3. Extracting a Time Series for a Polygon + +```python +polygon = ee.Geometry.Polygon([ + [[3.37, 6.52], [3.38, 6.52], [3.38, 6.53], [3.37, 6.53], [3.37, 6.52]] +]) +df_poly = geeagri.extract_timeseries_to_polygon( + polygon, collection, start_date, end_date, band_names=[band], scale=scale, reducer="MEAN" +) +print(df_poly.head()) +``` + + +## 4. Harmonic Regression Example + +```python +from geeagri.timeseries import HarmonicRegression + +ref_date = start_date +order = 2 +hr = HarmonicRegression(collection, ref_date, band, order=order) +harmonic_coeffs = hr.get_harmonic_coeffs() +# You can now use hr.get_fitted_harmonics(harmonic_coeffs) for fitted values +``` + +df.plot(x='time', y=band, marker='o') + +## 5. Plotting the Results + +```python +import matplotlib.pyplot as plt +df.plot(x='time', y=band, marker='o') +plt.title('Time Series at Point') +plt.show() +``` From 78a85e4b900d89197b6d4fe4d17290cb3a369ff9 Mon Sep 17 00:00:00 2001 From: James Oluwadare Date: Wed, 30 Jul 2025 20:50:30 +0100 Subject: [PATCH 2/3] updated docstring of the preprocessing module --- geeagri/preprocessing.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/geeagri/preprocessing.py b/geeagri/preprocessing.py index 09b8830..54b9aae 100644 --- a/geeagri/preprocessing.py +++ b/geeagri/preprocessing.py @@ -1,4 +1,27 @@ -"""Module for preprocessing Earth Observation data using Google Earth Engine.""" + +""" +geeagri.preprocessing +===================== + +This module provides preprocessing utilities for Earth Observation data using Google Earth Engine (GEE). +It includes classes for band-wise normalization and scaling of multi-band images, enabling standardized analysis and machine learning workflows. + +Available scalers: + +- MeanCentering: Subtracts the mean of each band over a region. +- StandardScaler: Applies z-score normalization (zero mean, unit variance). +- MinMaxScaler: Scales each band to [0, 1] using min and max values. +- RobustScaler: Scales each band to [0, 1] using percentiles, reducing the influence of outliers. + +Each scaler operates on an ee.Image and a region (ee.Geometry), and supports custom scale and pixel limits. + +Example usage: + from geeagri.preprocessing import StandardScaler + scaler = StandardScaler(image, region) + standardized = scaler.transform() + +These tools are useful for preparing satellite imagery for further analysis, feature extraction, or machine learning tasks. +""" import ee From e679ee10063b7b5a5e08a7bc6a959a5821864026 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 31 Jul 2025 13:36:09 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/examples/harmonic_regression.ipynb | 54 ++++++++++++------------- geeagri/preprocessing.py | 1 - 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/docs/examples/harmonic_regression.ipynb b/docs/examples/harmonic_regression.ipynb index f2642fc..ad3c30b 100644 --- a/docs/examples/harmonic_regression.ipynb +++ b/docs/examples/harmonic_regression.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "a216a3e7", + "id": "0", "metadata": {}, "source": [ "# Harmonic Regression Analysis with geeagri\n", @@ -12,7 +12,7 @@ }, { "cell_type": "markdown", - "id": "b296e5fd", + "id": "1", "metadata": {}, "source": [ "## Setup and Imports\n", @@ -22,7 +22,7 @@ { "cell_type": "code", "execution_count": null, - "id": "79451c17", + "id": "2", "metadata": {}, "outputs": [], "source": [ @@ -37,7 +37,7 @@ { "cell_type": "code", "execution_count": null, - "id": "859cd383", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -47,7 +47,7 @@ }, { "cell_type": "markdown", - "id": "de03bed4", + "id": "4", "metadata": {}, "source": [ "## Select Region and Data\n", @@ -57,23 +57,23 @@ { "cell_type": "code", "execution_count": null, - "id": "fea86aad", + "id": "5", "metadata": {}, "outputs": [], "source": [ "lat, lon = 37.0510, -120.3022 # Example: Central California\n", "point = ee.Geometry.Point([lon, lat])\n", "\n", - "collection = ee.ImageCollection('MODIS/061/MOD13Q1')\n", - "band = 'NDVI'\n", - "start_date = '2015-01-01'\n", - "end_date = '2017-01-01'\n", + "collection = ee.ImageCollection(\"MODIS/061/MOD13Q1\")\n", + "band = \"NDVI\"\n", + "start_date = \"2015-01-01\"\n", + "end_date = \"2017-01-01\"\n", "scale = 250" ] }, { "cell_type": "markdown", - "id": "872404d3", + "id": "6", "metadata": {}, "source": [ "## Extract Time Series\n", @@ -83,20 +83,20 @@ { "cell_type": "code", "execution_count": null, - "id": "31e1252b", + "id": "7", "metadata": {}, "outputs": [], "source": [ "df = geeagri.extract_timeseries_to_point(\n", " lat, lon, collection, start_date, end_date, band_names=[band], scale=scale\n", ")\n", - "df['NDVI'] = df['NDVI'] * 0.0001 # Apply scale factor for MODIS NDVI\n", + "df[\"NDVI\"] = df[\"NDVI\"] * 0.0001 # Apply scale factor for MODIS NDVI\n", "df.head()" ] }, { "cell_type": "markdown", - "id": "2f1d5d98", + "id": "8", "metadata": {}, "source": [ "## Fit Harmonic Regression\n", @@ -106,7 +106,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b5cadce5", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -118,7 +118,7 @@ }, { "cell_type": "markdown", - "id": "d39fa8a3", + "id": "10", "metadata": {}, "source": [ "## Visualize Fitted Harmonics\n", @@ -128,7 +128,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8f766f8f", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -136,23 +136,23 @@ "# Extract fitted values at the point\n", "fitted_list = fitted_coll.getRegion(point, scale=scale).getInfo()\n", "fitted_df = pd.DataFrame(fitted_list[1:], columns=fitted_list[0])\n", - "fitted_df['time'] = pd.to_datetime(fitted_df['time'], unit='ms')\n", - "fitted_df = fitted_df[['time', 'fitted']].dropna()\n", + "fitted_df[\"time\"] = pd.to_datetime(fitted_df[\"time\"], unit=\"ms\")\n", + "fitted_df = fitted_df[[\"time\", \"fitted\"]].dropna()\n", "# Merge with original NDVI\n", - "merged = pd.merge(df, fitted_df, on='time', how='inner')\n", - "plt.figure(figsize=(10,5))\n", - "plt.plot(merged['time'], merged['NDVI'], label='Observed NDVI', marker='o')\n", - "plt.plot(merged['time'], merged['fitted'], label='Fitted Harmonic', linestyle='--')\n", - "plt.xlabel('Date')\n", - "plt.ylabel('NDVI')\n", - "plt.title('Harmonic Regression Fit to NDVI Time Series')\n", + "merged = pd.merge(df, fitted_df, on=\"time\", how=\"inner\")\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(merged[\"time\"], merged[\"NDVI\"], label=\"Observed NDVI\", marker=\"o\")\n", + "plt.plot(merged[\"time\"], merged[\"fitted\"], label=\"Fitted Harmonic\", linestyle=\"--\")\n", + "plt.xlabel(\"Date\")\n", + "plt.ylabel(\"NDVI\")\n", + "plt.title(\"Harmonic Regression Fit to NDVI Time Series\")\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", - "id": "69e3fac8", + "id": "12", "metadata": {}, "source": [ "## Next Steps\n", diff --git a/geeagri/preprocessing.py b/geeagri/preprocessing.py index d9a6782..49cee76 100644 --- a/geeagri/preprocessing.py +++ b/geeagri/preprocessing.py @@ -1,4 +1,3 @@ - """ geeagri.preprocessing =====================