{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\"Open\n", "\n", "**DataTable Charts**\n", "\n", "Uncomment the following line to install [geemap](https://geemap.org) if needed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# %pip install -U geemap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import libraries" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import ee\n", "import geemap\n", "from geemap import chart\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "geemap.ee_initialize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Manual DataTable chart" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = {\n", " \"State\": [\"CA\", \"NY\", \"IL\", \"MI\", \"OR\"],\n", " \"Population\": [37253956, 19378102, 12830632, 9883640, 3831074],\n", "}\n", "\n", "df = pd.DataFrame(data)\n", "df" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig = chart.Chart(\n", " df,\n", " x_cols=[\"State\"],\n", " y_cols=[\"Population\"],\n", " chart_type=\"ColumnChart\",\n", " colors=[\"#1d6b99\"],\n", " title=\"State Population (US census, 2010)\",\n", " x_label=\"State\",\n", " y_label=\"Population\",\n", ")\n", "fig" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://i.imgur.com/vuxNmuh.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computed DataTable chart" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Import the example feature collection and subset the forest feature.\n", "forest = ee.FeatureCollection(\"projects/google/charts_feature_example\").filter(\n", " ee.Filter.eq(\"label\", \"Forest\")\n", ")\n", "\n", "# Load MODIS vegetation indices data and subset a decade of images.\n", "veg_indices = (\n", " ee.ImageCollection(\"MODIS/061/MOD13A1\")\n", " .filter(ee.Filter.date(\"2010-01-01\", \"2020-01-01\"))\n", " .select([\"NDVI\", \"EVI\"])\n", ")\n", "\n", "# Build a feature collection where each feature has a property that represents\n", "# a DataFrame row.\n", "\n", "\n", "def aggregate(img):\n", " # Reduce the image to the mean of pixels intersecting the forest ecoregion.\n", " stat = img.reduceRegion(\n", " **{\"reducer\": ee.Reducer.mean(), \"geometry\": forest, \"scale\": 500}\n", " )\n", "\n", " # Extract the reduction results along with the image date.\n", " date = geemap.image_date(img)\n", " evi = stat.get(\"EVI\")\n", " ndvi = stat.get(\"NDVI\")\n", "\n", " # Make a list of observation attributes to define a row in the DataTable.\n", " row = ee.List([date, evi, ndvi])\n", "\n", " # Return the row as a property of an ee.Feature.\n", " return ee.Feature(None, {\"row\": row})\n", "\n", "\n", "reduction_table = veg_indices.map(aggregate)\n", "\n", "# Aggregate the 'row' property from all features in the new feature collection\n", "# to make a server-side 2-D list (DataTable).\n", "data_table_server = reduction_table.aggregate_array(\"row\")\n", "\n", "# Define column names and properties for the DataTable. The order should\n", "# correspond to the order in the construction of the 'row' property above.\n", "column_header = ee.List([[\"Date\", \"EVI\", \"NDVI\"]])\n", "\n", "# Concatenate the column header to the table.\n", "data_table_server = column_header.cat(data_table_server)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_table = chart.DataTable(data_table_server, date_column=\"Date\")\n", "data_table.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig = chart.Chart(\n", " data_table,\n", " chart_type=\"LineChart\",\n", " x_cols=\"Date\",\n", " y_cols=[\"EVI\", \"NDVI\"],\n", " colors=[\"#e37d05\", \"#1d6b99\"],\n", " title=\"Average Vegetation Index Value by Date for Forest\",\n", " x_label=\"Date\",\n", " y_label=\"Vegetation index (x1e4)\",\n", " stroke_width=3,\n", " legend_location=\"right\",\n", ")\n", "fig" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://i.imgur.com/PWei7QC.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interval chart" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Define a point to extract an NDVI time series for.\n", "geometry = ee.Geometry.Point([-121.679, 36.479])\n", "\n", "# Define a band of interest (NDVI), import the MODIS vegetation index dataset,\n", "# and select the band.\n", "band = \"NDVI\"\n", "ndvi_col = ee.ImageCollection(\"MODIS/061/MOD13Q1\").select(band)\n", "\n", "# Map over the collection to add a day of year (doy) property to each image.\n", "\n", "\n", "def set_doy(img):\n", " doy = ee.Date(img.get(\"system:time_start\")).getRelative(\"day\", \"year\")\n", " # Add 8 to day of year number so that the doy label represents the middle of\n", " # the 16-day MODIS NDVI composite.\n", " return img.set(\"doy\", ee.Number(doy).add(8))\n", "\n", "\n", "ndvi_col = ndvi_col.map(set_doy)\n", "\n", "# Join all coincident day of year observations into a set of image collections.\n", "distinct_doy = ndvi_col.filterDate(\"2013-01-01\", \"2014-01-01\")\n", "filter = ee.Filter.equals(**{\"leftField\": \"doy\", \"rightField\": \"doy\"})\n", "join = ee.Join.saveAll(\"doy_matches\")\n", "join_col = ee.ImageCollection(join.apply(distinct_doy, ndvi_col, filter))\n", "\n", "# Calculate the absolute range, interquartile range, and median for the set\n", "# of images composing each coincident doy observation group. The result is\n", "# an image collection with an image representative per unique doy observation\n", "# with bands that describe the 0, 25, 50, 75, 100 percentiles for the set of\n", "# coincident doy images.\n", "\n", "\n", "def cal_percentiles(img):\n", " doyCol = ee.ImageCollection.fromImages(img.get(\"doy_matches\"))\n", "\n", " return doyCol.reduce(\n", " ee.Reducer.percentile([0, 25, 50, 75, 100], [\"p0\", \"p25\", \"p50\", \"p75\", \"p100\"])\n", " ).set({\"doy\": img.get(\"doy\")})\n", "\n", "\n", "comp = ee.ImageCollection(join_col.map(cal_percentiles))\n", "\n", "# Extract the inter-annual NDVI doy percentile statistics for the\n", "# point of interest per unique doy representative. The result is\n", "# is a feature collection where each feature is a doy representative that\n", "# contains a property (row) describing the respective inter-annual NDVI\n", "# variance, formatted as a list of values.\n", "\n", "\n", "def order_percentiles(img):\n", " stats = ee.Dictionary(\n", " img.reduceRegion(\n", " **{\"reducer\": ee.Reducer.first(), \"geometry\": geometry, \"scale\": 250}\n", " )\n", " )\n", "\n", " # Order the percentile reduction elements according to how you want columns\n", " # in the DataTable arranged (x-axis values need to be first).\n", " row = ee.List(\n", " [\n", " img.get(\"doy\"),\n", " stats.get(band + \"_p50\"),\n", " stats.get(band + \"_p0\"),\n", " stats.get(band + \"_p25\"),\n", " stats.get(band + \"_p75\"),\n", " stats.get(band + \"_p100\"),\n", " ]\n", " )\n", "\n", " # Return the row as a property of an ee.Feature.\n", " return ee.Feature(None, {\"row\": row})\n", "\n", "\n", "reduction_table = comp.map(order_percentiles)\n", "\n", "# Aggregate the 'row' properties to make a server-side 2-D array (DataTable).\n", "data_table_server = reduction_table.aggregate_array(\"row\")\n", "\n", "# Define column names and properties for the DataTable. The order should\n", "# correspond to the order in the construction of the 'row' property above.\n", "column_header = ee.List([[\"DOY\", \"median\", \"p0\", \"p25\", \"p75\", \"p100\"]])\n", "\n", "# Concatenate the column header to the table.\n", "data_table_server = column_header.cat(data_table_server)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = chart.DataTable(data_table_server)\n", "df.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig = chart.Chart(\n", " df,\n", " chart_type=\"IntervalChart\",\n", " x_cols=\"DOY\",\n", " y_cols=[\"p0\", \"p25\", \"median\", \"p75\", \"p100\"],\n", " title=\"Annual NDVI Time Series with Inter-Annual Variance\",\n", " x_label=\"Day of Year\",\n", " y_label=\"Vegetation index (x1e4)\",\n", " stroke_width=1,\n", " fill=\"between\",\n", " fill_colors=[\"#b6d1c6\", \"#83b191\", \"#83b191\", \"#b6d1c6\"],\n", " fill_opacities=[0.6] * 4,\n", " labels=[\"p0\", \"p25\", \"median\", \"p75\", \"p100\"],\n", " display_legend=True,\n", " legend_location=\"top-right\",\n", " ylim=(0, 10000),\n", ")\n", "fig" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://i.imgur.com/i8ZrGPR.png)" ] } ], "metadata": { "kernelspec": { "display_name": "geo", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.8" } }, "nbformat": 4, "nbformat_minor": 2 }