From 26061de1b8ce86d77080785259c043a2cd6bc503 Mon Sep 17 00:00:00 2001 From: Sean Date: Thu, 24 Nov 2022 10:11:17 +1100 Subject: [PATCH] Time series web mapping with leaf map draft notebook --- .../Time_series_web_mapping.ipynb | 286 ++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 Frequently_used_code/Time_series_web_mapping.ipynb diff --git a/Frequently_used_code/Time_series_web_mapping.ipynb b/Frequently_used_code/Time_series_web_mapping.ipynb new file mode 100644 index 000000000..339549062 --- /dev/null +++ b/Frequently_used_code/Time_series_web_mapping.ipynb @@ -0,0 +1,286 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Interactive time-series geospatial data on a web map \n", + "\n", + "* [**Sign up to the DEA Sandbox**](https://docs.dea.ga.gov.au/setup/sandbox.html) to run this notebook interactively from a browser\n", + "* **Compatibility:** Notebook currently compatible with both the `NCI` and `DEA Sandbox` environments\n", + "* **Products used:** \n", + "[ga_ls_fc_3](https://explorer.sandbox.dea.ga.gov.au/products/ga_ls_fc_3)\n", + "\n", + "## Background\n", + "\n", + "[Leaflet](https://leafletjs.com/) is the leading open-source JavaScript library for mobile-friendly interactive maps.\n", + "This notebook additionally uses [Leafmap](leafmap.org) to expose this functionality within the jupyter environment\n", + "This library enables interactive maps in the Jupyter notebook/JupyterLab environment.\n", + "\n", + "## Description\n", + "\n", + "This notebook demonstrates how to visualise timeseries data in an interactive manner\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting started\n", + "To run this analysis, run all the cells in the notebook, starting with the \"Load packages\" cell." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load packages" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import numpy as np\n", + "from ipywidgets import widgets as w\n", + "from IPython.display import display\n", + "import leafmap\n", + "import datacube\n", + "import odc.ui\n", + "import pandas as pd\n", + "import odc.geo.xr\n", + "from ipyleaflet import ImageOverlay" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Connect to the datacube" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "dc = datacube.Datacube(app='Imagery_on_web_map')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "def da_to_timeseries_imageoverlay(data):\n", + " \"\"\"\n", + " Converts a xarray.DataArray into a dictionary with times as keys and ipyleaflet ImageOverlays as values.\n", + " \n", + " Parameters\n", + " ----------\n", + " da : xarray dataarray or a numpy ndarray \n", + " \n", + " Returns\n", + " -------\n", + " out : dictionary\n", + " bounds: bounds of input da\n", + " \n", + " \"\"\"\n", + " out = {}\n", + " for time in data.time.values:\n", + " date = str(pd.to_datetime(time).date())\n", + " print('\\r', 'Opening:', date, end='')\n", + " single = data.sel(time=time)\n", + " vmin, vmax = np.nanpercentile(data.data, [2, 98])\n", + " rgba = single.odc.colorize(vmin=vmin, vmax=vmax)\n", + " data_url = rgba.odc.compress(as_data_url=True)\n", + " (x1, y1), _, (x2, y2) = rgba.odc.geobox.extent.exterior.to_crs(\"epsg:4326\").points[:3]\n", + " bounds = [[y1, x1], [y2, x2]]\n", + " raster = ImageOverlay(url=data_url, bounds=bounds,opacity=0.7)\n", + " out[date] = raster\n", + " return out, bounds" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6afe49d7332941ce96ce20c301a8a516", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(Label(value=''), Label(value='')), layout=Layout(justify_content='space-between'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Set up a region to load data\n", + "query = {\n", + " 'y': (-34.06813, -34.22099),\n", + " 'x': (139.83315, 140.05151),\n", + " 'time': ('2000-08-31', '2000-10-31'),\n", + "}\n", + "\n", + "# Load DEA Fractional Cover data from the datacube\n", + "fc = dc.load(product='ga_ls_fc_3',\n", + " measurements=['pv'],\n", + " output_crs='EPSG:32754',\n", + " resolution=(-30, 30),\n", + " group_by='solar_day',\n", + " progress_cbk=odc.ui.with_ui_cbk(),\n", + " **query)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Opening: 2000-10-26" + ] + } + ], + "source": [ + "time_dict, bounds = da_to_timeseries_imageoverlay(fc['pv'])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# Create leafmap approximately centered using bounds\n", + "m = leafmap.Map(center = bounds[0],\n", + " zoom=11)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# Create dictionary of images for time slider\n", + "m.add_time_slider(time_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c087203d656f46bd869724c169545106", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Map(center=[-34.06619528124256, 139.83298969912786], controls=(ZoomControl(options=['position', 'zoom_in_text'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Display map\n", + "display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + "## Additional information\n", + "\n", + "**License:** The code in this notebook is licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). \n", + "Digital Earth Australia data is licensed under the [Creative Commons by Attribution 4.0](https://creativecommons.org/licenses/by/4.0/) license.\n", + "\n", + "**Contact:** If you need assistance, please post a question on the [Open Data Cube Slack channel](http://slack.opendatacube.org/) or on the [GIS Stack Exchange](https://gis.stackexchange.com/questions/ask?tags=open-data-cube) using the `open-data-cube` tag (you can view previously asked questions [here](https://gis.stackexchange.com/questions/tagged/open-data-cube)).\n", + "If you would like to report an issue with this notebook, you can file one on [Github](https://github.com/GeoscienceAustralia/dea-notebooks).\n", + "\n", + "**Last modified:** September 2021\n", + "\n", + "**Compatible datacube version:** " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(datacube.__version__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tags\n", + "Browse all available tags on the DEA User Guide's [Tags Index](https://docs.dea.ga.gov.au/genindex.html)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + "**Tags**: :index:`NCI compatible`, :index:`sandbox compatible`, :index:`sentinel 2`, :index:`widgets`, :index:`ipyleaflet`, :index:`interactive`" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.8.10" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}