From 0b9d30b6ed03af30acc044fd0cc16cb2282d9383 Mon Sep 17 00:00:00 2001 From: "m11keluis@gmail.com" Date: Mon, 10 Jun 2024 14:48:45 -0600 Subject: [PATCH 1/4] quick path fix --- notebooks/water_quality/lesson1_waterFind.ipynb | 3 +-- notebooks/water_quality/lesson2_EMITnECO.ipynb | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/notebooks/water_quality/lesson1_waterFind.ipynb b/notebooks/water_quality/lesson1_waterFind.ipynb index e9d4913..f0445d8 100644 --- a/notebooks/water_quality/lesson1_waterFind.ipynb +++ b/notebooks/water_quality/lesson1_waterFind.ipynb @@ -205,8 +205,7 @@ "source": [ "# Load Geopandas File with Lakes and Reservoirs\n", "lr_filename = os.path.join(data_store_path, 'co_lr/co_lr.shp')\n", - "lr_gdf = gpd.read_file('data/co_lr/co_lr.shp')\n", - "print(len(lr_gdf))\n", + "lr_gdf = gpd.read_file(lr_filename)\n", "\n", "# Visualize First 5 Entries\n", "lr_gdf.head()" diff --git a/notebooks/water_quality/lesson2_EMITnECO.ipynb b/notebooks/water_quality/lesson2_EMITnECO.ipynb index 303510e..971487d 100644 --- a/notebooks/water_quality/lesson2_EMITnECO.ipynb +++ b/notebooks/water_quality/lesson2_EMITnECO.ipynb @@ -1489,11 +1489,9 @@ " row = [i, x, y] + list(spectra)\n", " rows.append(row)\n", "\n", - "\n", - "\n", - "with open('data/emit_click_data.csv', 'w', newline='') as f:\n", - " writer = csv.writer(f)\n", - " writer.writerows(rows)" + "#with open('data/emit_click_data.csv', 'w', newline='') as f:\n", + "# writer = csv.writer(f)\n", + "# writer.writerows(rows)" ] }, { From beab909682d683a13c6e61fd8f313ff89b741666 Mon Sep 17 00:00:00 2001 From: "m11keluis@gmail.com" Date: Wed, 12 Jun 2024 09:04:55 -0600 Subject: [PATCH 2/4] update notebooks --- .../lesson2_EMITnECO-fillIn.ipynb | 3412 +++++++++++++++++ .../water_quality/lesson2_EMITnECO.ipynb | 1054 ++--- 2 files changed, 3693 insertions(+), 773 deletions(-) create mode 100644 notebooks/water_quality/lesson2_EMITnECO-fillIn.ipynb diff --git a/notebooks/water_quality/lesson2_EMITnECO-fillIn.ipynb b/notebooks/water_quality/lesson2_EMITnECO-fillIn.ipynb new file mode 100644 index 0000000..dac355b --- /dev/null +++ b/notebooks/water_quality/lesson2_EMITnECO-fillIn.ipynb @@ -0,0 +1,3412 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a584baff", + "metadata": {}, + "source": [ + "# Water Quality Lesson 2: Visualize EMIT and ECOSTRESS Water Quality (Fill in the Blanks!!!)\n", + "\n", + "**Summary:** In this notebook, we will find EMIT imagery that overlaps with our waterbody of interest, visualize differences in aquatic visible to shortwave infrared spectra, and generate water quality maps. BUT, this is a fill in a blank notebook. You will notice that some chunks have *___*, modify the code to get it to work! \n", + "\n", + "**Objectives:**\n", + "\n", + "1) Identify differences in spectra\n", + " \n", + "2) Apply water quality algorithm to EMIT image\n", + "\n", + "3) Learn how to interpolate EMIT images to match ECOSTRESS\n", + "\n", + "**Sections of Notebook**\n", + "- Part 1: Data Preparation\n", + "- Part 2: Visuzalize EMIT Spectra\n", + "- Part 3: Apply Water Quality Algorithms\n", + "\n", + "Written By: Kelly Luis, JPL (kelly.m.luis@jpl.nasa.gov)\n", + "\n", + "**Code adapted from the [EMIT Github repo](https://github.com/nasa/EMIT-Data-Resources) and the [VITALS Github repo](https://github.com/nasa/VITALS/). Many thanks to the LP.DAAC team!**\n", + "\n", + "#### TO DO:\n", + "1. Adjust Data Path for HYR-SENSE " + ] + }, + { + "cell_type": "markdown", + "id": "fb4af057-63dc-48a1-8d6e-63b1994d01f5", + "metadata": {}, + "source": [ + "## Part 1: Data Preparation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b702352e", + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " var force = true;\n", + " var py_version = '3.4.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " var reloading = false;\n", + " var Bokeh = root.Bokeh;\n", + "\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " }\n", + " if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + " if (!reloading) {\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error() {\n", + " console.error(\"failed to load \" + url);\n", + " }\n", + "\n", + " var skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", + " root._bokeh_is_loading = css_urls.length + 0;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " var existing_stylesheets = []\n", + " var links = document.getElementsByTagName('link')\n", + " for (var i = 0; i < links.length; i++) {\n", + " var link = links[i]\n", + " if (link.href != null) {\n", + "\texisting_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (var i = 0; i < css_urls.length; i++) {\n", + " var url = css_urls[i];\n", + " if (existing_stylesheets.indexOf(url) !== -1) {\n", + "\ton_load()\n", + "\tcontinue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } var existing_scripts = []\n", + " var scripts = document.getElementsByTagName('script')\n", + " for (var i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + "\texisting_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (var i = 0; i < js_urls.length; i++) {\n", + " var url = js_urls[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (var i = 0; i < js_modules.length; i++) {\n", + " var url = js_modules[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " var url = js_exports[name];\n", + " if (skip.indexOf(url) >= 0 || root[name] != null) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.1.min.js\", \"https://cdn.holoviz.org/panel/1.4.4/dist/panel.min.js\"];\n", + " var js_modules = [];\n", + " var js_exports = {};\n", + " var css_urls = [];\n", + " var inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (var i = 0; i < inline_js.length; i++) {\n", + "\ttry {\n", + " inline_js[i].call(root, root.Bokeh);\n", + "\t} catch(e) {\n", + "\t if (!reloading) {\n", + "\t throw e;\n", + "\t }\n", + "\t}\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + "\tvar NewBokeh = root.Bokeh;\n", + "\tif (Bokeh.versions === undefined) {\n", + "\t Bokeh.versions = new Map();\n", + "\t}\n", + "\tif (NewBokeh.version !== Bokeh.version) {\n", + "\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + "\t}\n", + "\troot.Bokeh = Bokeh;\n", + " }} else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + "\troot.Bokeh = undefined;\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + "\trun_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.1.min.js\", \"https://cdn.holoviz.org/panel/1.4.4/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " }) \n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1002" + } + }, + "output_type": "display_data" + }, + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'emit_tools'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[1], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01msys\u001b[39;00m\n\u001b[1;32m 21\u001b[0m sys\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mappend(os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mjoin(os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mexpanduser(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m~\u001b[39m\u001b[38;5;124m\"\u001b[39m),\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHYR-SENSE\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtools\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124memit\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpython\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmodules\u001b[39m\u001b[38;5;124m\"\u001b[39m))\n\u001b[0;32m---> 22\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01memit_tools\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m emit_xarray\n\u001b[1;32m 23\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mmodules\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01memit_aqua\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m mask_aqua, rho2Rrs, ndci, ndti\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'emit_tools'" + ] + } + ], + "source": [ + "# Load Modules\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt # Plotting Function\n", + "import numpy as np\n", + "import requests\n", + "import os\n", + "from osgeo import gdal\n", + "import earthaccess\n", + "from modules.emit_aqua import mask_aqua, rho2Rrs, ndci, ndti\n", + "import math\n", + "import hvplot.xarray\n", + "import hvplot.pandas\n", + "import holoviews as hv\n", + "import rioxarray as rxr\n", + "import geopandas as gp\n", + "from modules.spectral_index import normalized_diff\n", + "import csv\n", + "import xarray as xr\n", + "from scipy.stats import linregress\n", + "import sys\n", + "sys.path.append(os.path.join(os.path.expanduser(\"~\"),\"HYR-SENSE\",\"tools\",\"emit\",\"python\",\"modules\"))\n", + "from emit_tools import emit_xarray\n", + "from modules.emit_aqua import mask_aqua, rho2Rrs, ndci, ndti" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "107e18d9", + "metadata": {}, + "outputs": [], + "source": [ + "# Set Variable for Data Store Path\n", + "data_store_path = '/data-store/iplant/home/shared/esiil/HYR_SENSE/data/water_quality'\n", + "\n", + "# Load EMIT File\n", + "___ = os.path.join(data_store_path,\"EMIT_L2A_RFL_001_20230403T190544_2309313_020.nc\")\n", + "___ = emit_xarray(___, ortho=___)\n", + "___['reflectance'].data[:,:,___['good_wavelengths'].data==0] = np.nan\n", + "___['reflectance'].data[___['reflectance'].data == -9999] = np.nan" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ae041c95-3007-4194-b6f5-8f4559d863a1", + "metadata": {}, + "outputs": [], + "source": [ + "# Crop for Neenoshe Reservoir via Bounding Box \n", + "N = 38.362006\n", + "W = -102.720106\n", + "S = 38.314948\n", + "E = -102.654359\n", + "\n", + "___ = ___.sel(longitude=slice(W, E), latitude=slice(N, S))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f34d9bf1-a6bd-4c35-9db4-c28e5051a48e", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":RGB [longitude,latitude] (R,G,B)" + ] + }, + "execution_count": 4, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1004" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "# Visualize EMIT RGB \n", + "emit_rgb = ___.sel(wavelengths=[650, 560, 470], method='nearest')\n", + "\n", + "# RGB Plotting Funciton\n", + "def gamma_adjust(rgb_ds, bright=0.2, white_background=False):\n", + " array = rgb_ds.reflectance.data\n", + " gamma = math.log(bright)/math.log(np.nanmean(array)) # Create exponent for gamma scaling - can be adjusted by changing 0.2 \n", + " scaled = np.power(np.nan_to_num(array,nan=1),np.nan_to_num(gamma,nan=1)).clip(0,1) # Apply scaling and clip to 0-1 range\n", + " if white_background == True:\n", + " scaled = np.nan_to_num(scaled, nan = 1) # Assign NA's to 1 so they appear white in plots\n", + " rgb_ds.reflectance.data = scaled\n", + " return rgb_ds\n", + "\n", + "emit_rgb = gamma_adjust(emit_rgb,white_background=True)\n", + "map = emit_rgb.hvplot.rgb(fontscale=1.5, xlabel='Longitude',ylabel='Latitude',frame_width=480, frame_height=480)\n", + "map" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "93096248-4e18-46fb-89c3-8ecd52868369", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (y: 1568, x: 1568)> Size: 10MB\n",
+       "[2458624 values with dtype=float32]\n",
+       "Coordinates:\n",
+       "  * x            (x) float64 13kB 7e+05 7.001e+05 ... 8.096e+05 8.097e+05\n",
+       "  * y            (y) float64 13kB 4.3e+06 4.3e+06 4.3e+06 ... 4.19e+06 4.19e+06\n",
+       "    spatial_ref  int64 8B 0\n",
+       "Attributes:\n",
+       "    AREA_OR_POINT:  Area\n",
+       "    _FillValue:     nan\n",
+       "    scale_factor:   1.0\n",
+       "    add_offset:     0.0
" + ], + "text/plain": [ + " Size: 10MB\n", + "[2458624 values with dtype=float32]\n", + "Coordinates:\n", + " * x (x) float64 13kB 7e+05 7.001e+05 ... 8.096e+05 8.097e+05\n", + " * y (y) float64 13kB 4.3e+06 4.3e+06 4.3e+06 ... 4.19e+06 4.19e+06\n", + " spatial_ref int64 8B 0\n", + "Attributes:\n", + " AREA_OR_POINT: Area\n", + " _FillValue: nan\n", + " scale_factor: 1.0\n", + " add_offset: 0.0" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Load ECOSTRESS \n", + "___ = os.path.join(data_store_path, \"ECOv002_L2T_LSTE_26890_005_13SGC_20230403T190528_0710_01_LST.tif\")\n", + "___ = rxr.open_rasterio(___).squeeze('band', drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "a2659b34-1fae-4361-a039-736c68a3ed49", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":Overlay\n", + " .WMTS.I :WMTS [Longitude,Latitude]\n", + " .Image.I :Image [longitude,latitude] (value)\n", + " .Polygons.I :Polygons [Longitude,Latitude]" + ] + }, + "execution_count": 74, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p3015" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "# Visualize Shapefile\n", + "colorado_file = os.path.join(data_store_path,\"co_lr/co_lr.shp\")\n", + "polygon = gdf[gdf['NAME'] == 'Neenoshe Reservoir']\n", + "polygon.hvplot(tiles='ESRI', color='#d95f02',alpha=0.6, crs='EPSG:4326', frame_height=405, frame_width=720, fontscale=2) \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fb4cb1f-b256-4790-a808-589f5c1590ba", + "metadata": {}, + "outputs": [], + "source": [ + "# ECOSTRESS Visualization\n", + "size_opts = dict(frame_height=405, frame_width=720, fontscale=2)\n", + "___ = ___.rio.reproject(\"EPSG:4326\")\n", + "___ = ___.sel(x=slice(W, E), y=slice(N,S))\n", + "___ = ___.rename({'x': 'longitude','y': 'latitude'})\n", + "___.hvplot.image(x='longitude', y='latitude', **size_opts, \n", + " cmap='inferno', tiles='ESRI', xlabel='Longitude', \n", + " ylabel='Latitude', title='ECOSTRESS LST (K)', \n", + " crs='EPSG:4326')*polygon.hvplot(color=___,alpha=0.5, crs='EPSG:4326') " + ] + }, + { + "cell_type": "markdown", + "id": "d8794250-4f13-462b-9cfb-7955169840e8", + "metadata": {}, + "source": [ + "## Part 2: Visualize EMIT Spectra" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "13386023-7e9a-40ec-9c1b-866b797c268d", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'emit_rgb' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[2], line 7\u001b[0m\n\u001b[1;32m 4\u001b[0m color_cycle \u001b[38;5;241m=\u001b[39m hv\u001b[38;5;241m.\u001b[39mCycle(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCategory20\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# Create RGB Map\u001b[39;00m\n\u001b[0;32m----> 7\u001b[0m \u001b[38;5;28mmap\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43memit_rgb\u001b[49m\u001b[38;5;241m.\u001b[39mhvplot\u001b[38;5;241m.\u001b[39mrgb(fontscale\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1.5\u001b[39m, xlabel\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mLongitude\u001b[39m\u001b[38;5;124m'\u001b[39m,ylabel\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mLatitude\u001b[39m\u001b[38;5;124m'\u001b[39m,frame_width\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m480\u001b[39m, frame_height\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m480\u001b[39m)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# Set up a holoviews points array to enable plotting of the clicked points\u001b[39;00m\n\u001b[1;32m 10\u001b[0m xmid \u001b[38;5;241m=\u001b[39m emit_ds\u001b[38;5;241m.\u001b[39mlongitude\u001b[38;5;241m.\u001b[39mvalues[\u001b[38;5;28mint\u001b[39m(\u001b[38;5;28mlen\u001b[39m(emit_ds\u001b[38;5;241m.\u001b[39mlongitude) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m)]\n", + "\u001b[0;31mNameError\u001b[0m: name 'emit_rgb' is not defined" + ] + } + ], + "source": [ + "# Interactive Points Plotting\n", + "# Modified from https://github.com/auspatious/hyperspectral-notebooks/blob/main/03_EMIT_Interactive_Points.ipynb\n", + "POINT_LIMIT = 5\n", + "color_cycle = hv.Cycle('Category20')\n", + "\n", + "# Create RGB Map\n", + "map = emit_rgb.hvplot.rgb(fontscale=1.5, xlabel='Longitude',ylabel='Latitude',frame_width=480, frame_height=480)\n", + "\n", + "# Set up a holoviews points array to enable plotting of the clicked points\n", + "xmid = emit_ds.longitude.values[int(len(emit_ds.longitude) / 2)]\n", + "ymid = emit_ds.latitude.values[int(len(emit_ds.latitude) / 2)]\n", + "\n", + "first_point = ([xmid], [ymid], [0])\n", + "points = hv.Points(first_point, vdims='id')\n", + "points_stream = hv.streams.PointDraw(\n", + " data=points.columns(),\n", + " source=points,\n", + " drag=True,\n", + " num_objects=POINT_LIMIT,\n", + " styles={'fill_color': color_cycle.values[1:POINT_LIMIT+1], 'line_color': 'gray'}\n", + ")\n", + "\n", + "posxy = hv.streams.PointerXY(source=map, x=xmid, y=ymid)\n", + "clickxy = hv.streams.Tap(source=map, x=xmid, y=ymid)\n", + "\n", + "# Function to build spectral plot of clicked location to show on hover stream plot\n", + "def click_spectra(data):\n", + " coordinates = []\n", + " if data is None or not any(len(d) for d in data.values()):\n", + " coordinates.append(clicked_points[0][0], clicked_points[1][0])\n", + " else:\n", + " coordinates = [c for c in zip(data['x'], data['y'])]\n", + " \n", + " plots = []\n", + " for i, coords in enumerate(coordinates):\n", + " x, y = coords\n", + " data = emit_ds.sel(longitude=x, latitude=y, method=\"nearest\")\n", + " plots.append(\n", + " data.hvplot.line(\n", + " y=\"reflectance\",\n", + " x=\"wavelengths\",\n", + " color=color_cycle,\n", + " label=f\"{i}\"\n", + " )\n", + " )\n", + " points_stream.data[\"id\"][i] = i\n", + " return hv.Overlay(plots)\n", + "\n", + "def hover_spectra(x,y):\n", + " return emit_ds.sel(longitude=x,latitude=y,method='nearest').hvplot.line(y='reflectance',x='wavelengths',\n", + " color='black', frame_width=400)\n", + "# Define the Dynamic Maps\n", + "click_dmap = hv.DynamicMap(click_spectra, streams=[points_stream])\n", + "\n", + "hover_dmap = hv.DynamicMap(hover_spectra, streams=[posxy])\n", + "\n", + "# Plot the Map and Dynamic Map side by side\n", + "hv.Layout(hover_dmap*click_dmap + map * points).cols(2).opts(\n", + " hv.opts.Points(active_tools=['point_draw'], size=10, tools=['hover'], color='white', line_color='gray'),\n", + " hv.opts.Overlay(show_legend=False, show_title=False, fontscale=1.5, frame_height=480)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "2f8213e6-c097-44da-8d61-86ad0772968b", + "metadata": {}, + "outputs": [], + "source": [ + "# Save Spectra to CSV\n", + "data = points_stream.data\n", + "wavelengths = emit_ds.wavelengths.values\n", + "\n", + "rows = [[\"id\", \"x\", \"y\"] + [str(i) for i in wavelengths]]\n", + " \n", + "for p in zip(data['x'], data['y'], data['id']):\n", + " x, y, i = p\n", + " spectra = emit_ds.sel(longitude=x, latitude=y, method=\"nearest\").reflectance.values\n", + " row = [i, x, y] + list(spectra)\n", + " rows.append(row)\n", + "\n", + "#with open('data/emit_click_data.csv', 'w', newline='') as f:\n", + "# writer = csv.writer(f)\n", + "# writer.writerows(rows)" + ] + }, + { + "cell_type": "markdown", + "id": "e38980c6-4411-4dc9-9197-21b944cdac56", + "metadata": {}, + "source": [ + "## Part 2: Apply Water Quality Algorithms\n", + "\n", + "We will apply two spectral indices: Normalized Difference Turbidity Index and Normalized Difference Chlorophyll Index.\n", + "\n", + "### Normalized Difference Chlorophyll Index from Mishra and Mishra, 2012\n", + "$$ NDCI=\\frac{(R_{rs}(708) - R_{rs}(665))}{(R_{rs}(708) + R_{rs}(665)} $$ \n", + "$$ R_{rs}=Remote \\ sensing \\ reflectance $$\n", + "\n", + "### Normalized Difference Turbidity Index from Lacaux et al. 2007\n", + "$$ NDTI=\\frac{(\\rho_{Red} - \\rho_{Green})}{(\\rho_{Red} + \\rho_{Green}} $$ \n", + "$$ \\rho = surface \\ reflectance $$ \n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "e056b1c6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset> Size: 25MB\n",
+       "Dimensions:           (latitude: 87, longitude: 122, wavelengths: 285)\n",
+       "Coordinates:\n",
+       "  * wavelengths       (wavelengths) float32 1kB 381.0 388.4 ... 2.493e+03\n",
+       "    fwhm              (wavelengths) float32 1kB ...\n",
+       "    good_wavelengths  (wavelengths) float32 1kB 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0\n",
+       "  * latitude          (latitude) float64 696B 38.36 38.36 38.36 ... 38.32 38.32\n",
+       "  * longitude         (longitude) float64 976B -102.7 -102.7 ... -102.7 -102.7\n",
+       "    elev              (latitude, longitude) float32 42kB 1.181e+03 ... 1.169e+03\n",
+       "    spatial_ref       int64 8B 0\n",
+       "    cirrus_mask       (latitude, longitude) int64 85kB 0 0 0 0 0 0 ... 0 0 0 0 0\n",
+       "    land_mask         (latitude, longitude) int64 85kB 0 0 0 0 0 0 ... 0 0 0 0 0\n",
+       "    cloud_mask        (latitude, longitude) int64 85kB 0 0 0 0 0 0 ... 0 0 0 0 0\n",
+       "Data variables:\n",
+       "    reflectance       (latitude, longitude, wavelengths) float32 12MB 0.04834...\n",
+       "    Rrs               (latitude, longitude, wavelengths) float32 12MB 0.01539...\n",
+       "    NDCI              (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n",
+       "    NDTI              (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n",
+       "Attributes: (12/40)\n",
+       "    ncei_template_version:             NCEI_NetCDF_Swath_Template_v2.0\n",
+       "    summary:                           The Earth Surface Mineral Dust Source ...\n",
+       "    keywords:                          Imaging Spectroscopy, minerals, EMIT, ...\n",
+       "    Conventions:                       CF-1.63\n",
+       "    sensor:                            EMIT (Earth Surface Mineral Dust Sourc...\n",
+       "    instrument:                        EMIT\n",
+       "    ...                                ...\n",
+       "    spatial_ref:                       GEOGCS["WGS 84",DATUM["WGS_1984",SPHER...\n",
+       "    geotransform:                      [-1.03613320e+02  5.42232520e-04 -0.00...\n",
+       "    day_night_flag:                    Day\n",
+       "    title:                             EMIT L2A Estimated Surface Reflectance...\n",
+       "    granule_id:                        EMIT_L2A_RFL_001_20230403T190544_23093...\n",
+       "    Orthorectified:                    True
" + ], + "text/plain": [ + " Size: 25MB\n", + "Dimensions: (latitude: 87, longitude: 122, wavelengths: 285)\n", + "Coordinates:\n", + " * wavelengths (wavelengths) float32 1kB 381.0 388.4 ... 2.493e+03\n", + " fwhm (wavelengths) float32 1kB ...\n", + " good_wavelengths (wavelengths) float32 1kB 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0\n", + " * latitude (latitude) float64 696B 38.36 38.36 38.36 ... 38.32 38.32\n", + " * longitude (longitude) float64 976B -102.7 -102.7 ... -102.7 -102.7\n", + " elev (latitude, longitude) float32 42kB 1.181e+03 ... 1.169e+03\n", + " spatial_ref int64 8B 0\n", + " cirrus_mask (latitude, longitude) int64 85kB 0 0 0 0 0 0 ... 0 0 0 0 0\n", + " land_mask (latitude, longitude) int64 85kB 0 0 0 0 0 0 ... 0 0 0 0 0\n", + " cloud_mask (latitude, longitude) int64 85kB 0 0 0 0 0 0 ... 0 0 0 0 0\n", + "Data variables:\n", + " reflectance (latitude, longitude, wavelengths) float32 12MB 0.04834...\n", + " Rrs (latitude, longitude, wavelengths) float32 12MB 0.01539...\n", + " NDCI (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n", + " NDTI (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n", + "Attributes: (12/40)\n", + " ncei_template_version: NCEI_NetCDF_Swath_Template_v2.0\n", + " summary: The Earth Surface Mineral Dust Source ...\n", + " keywords: Imaging Spectroscopy, minerals, EMIT, ...\n", + " Conventions: CF-1.63\n", + " sensor: EMIT (Earth Surface Mineral Dust Sourc...\n", + " instrument: EMIT\n", + " ... ...\n", + " spatial_ref: GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHER...\n", + " geotransform: [-1.03613320e+02 5.42232520e-04 -0.00...\n", + " day_night_flag: Day\n", + " title: EMIT L2A Estimated Surface Reflectance...\n", + " granule_id: EMIT_L2A_RFL_001_20230403T190544_23093...\n", + " Orthorectified: True" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Pre-processing\n", + "___ = mask_aqua(___) # Cloud and Land Mask\n", + "___['Rrs'] = rho2Rrs(___) # Calculate Remote Sensing Reflectance\n", + "___['NDCI'] = ndci(___)\n", + "___" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "a39aa077-bb76-4d56-b91b-c984f97fa292", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":Image [longitude,latitude] (NDCI)" + ] + }, + "execution_count": 60, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p2693" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "# Normalized Difference Turbidity Index\n", + "red = ___.Rrs.sel(wavelengths=665, method='nearest')\n", + "nir = ___.Rrs.sel(wavelengths=708, method='nearest')\n", + "___['NDCI'] = (nir - red)/(nir + red)\n", + "___['NDCI'].where(___.land_mask==1).hvplot(x='longitude', y='latitude', aspect = 'equal', frame_width=400, cmap='Viridis')" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "bf000575-96aa-4f16-b381-b9bed4a6105d", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":Image [longitude,latitude] (NDTI)" + ] + }, + "execution_count": 59, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p2623" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "# Normalized Difference Turbidity Index\n", + "green = ___.Rrs.sel(wavelengths=561, method='nearest')\n", + "red = ___.Rrs.sel(wavelengths=655, method='nearest')\n", + "___['NDTI'] = (red - green)/(red + green)\n", + "___['NDTI'].where(___.land_mask==1).hvplot(x='longitude', y='latitude', aspect = 'equal', frame_width=400, cmap='Viridis')" + ] + }, + { + "cell_type": "markdown", + "id": "b84bcf9f", + "metadata": {}, + "source": [ + "
\n", + " Exercises \n", + "\n", + "1. You can vary the colorbar range by adjusting *clim* values (20-50). When you adjust the ranges, what are the differences that occur between the two waterbodies? \n", + "\n", + "2. What aquatic processes could contribute to the large chlorophyll range (e.g., phytoplankton bloom, other types of aquatic biomass present?)\n", + "\n", + "3. Try out different algorithms and water qualtiy products! Across algorithms, what differences are you observing? What algorithms seem like a reasonable range?\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "5d2d737c-0708-4d70-b8ea-ca21cc84ad2b", + "metadata": {}, + "source": [ + "## Part 3: Compare ECOSTRESS and EMIT\n", + "\n", + "The spatial resolution of EMIT is 60x60m while the ECOSTRESS resolution is 70x70m. We need to coarsen the EMIT pixels to match the ECOSTRESS spatial resolution. Xarray has a very handy function (interp_like) to do this calculation very quickly. " + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "98ce79c7-d861-47f0-919e-fa2a1875595f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset> Size: 28MB\n",
+       "Dimensions:           (latitude: 66, longitude: 91, wavelengths: 285)\n",
+       "Coordinates:\n",
+       "  * wavelengths       (wavelengths) float32 1kB 381.0 388.4 ... 2.493e+03\n",
+       "    fwhm              (wavelengths) float32 1kB 8.415 8.415 ... 8.807 8.809\n",
+       "    good_wavelengths  (wavelengths) float32 1kB 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0\n",
+       "    elev              (latitude, longitude) float64 48kB nan nan ... 1.169e+03\n",
+       "    spatial_ref       int64 8B 0\n",
+       "    cirrus_mask       (latitude, longitude) float64 48kB nan nan nan ... 0.0 0.0\n",
+       "    land_mask         (latitude, longitude) float64 48kB nan nan nan ... 0.0 0.0\n",
+       "    cloud_mask        (latitude, longitude) float64 48kB nan nan nan ... 0.0 0.0\n",
+       "  * latitude          (latitude) float64 528B 38.36 38.36 38.36 ... 38.32 38.32\n",
+       "  * longitude         (longitude) float64 728B -102.7 -102.7 ... -102.7 -102.7\n",
+       "Data variables:\n",
+       "    reflectance       (latitude, longitude, wavelengths) float64 14MB nan ......\n",
+       "    Rrs               (latitude, longitude, wavelengths) float64 14MB nan ......\n",
+       "    NDCI              (latitude, longitude) float64 48kB nan nan ... 0.04753\n",
+       "    NDTI              (latitude, longitude) float64 48kB nan nan ... 0.1322\n",
+       "Attributes: (12/40)\n",
+       "    ncei_template_version:             NCEI_NetCDF_Swath_Template_v2.0\n",
+       "    summary:                           The Earth Surface Mineral Dust Source ...\n",
+       "    keywords:                          Imaging Spectroscopy, minerals, EMIT, ...\n",
+       "    Conventions:                       CF-1.63\n",
+       "    sensor:                            EMIT (Earth Surface Mineral Dust Sourc...\n",
+       "    instrument:                        EMIT\n",
+       "    ...                                ...\n",
+       "    spatial_ref:                       GEOGCS["WGS 84",DATUM["WGS_1984",SPHER...\n",
+       "    geotransform:                      [-1.03613320e+02  5.42232520e-04 -0.00...\n",
+       "    day_night_flag:                    Day\n",
+       "    title:                             EMIT L2A Estimated Surface Reflectance...\n",
+       "    granule_id:                        EMIT_L2A_RFL_001_20230403T190544_23093...\n",
+       "    Orthorectified:                    True
" + ], + "text/plain": [ + " Size: 28MB\n", + "Dimensions: (latitude: 66, longitude: 91, wavelengths: 285)\n", + "Coordinates:\n", + " * wavelengths (wavelengths) float32 1kB 381.0 388.4 ... 2.493e+03\n", + " fwhm (wavelengths) float32 1kB 8.415 8.415 ... 8.807 8.809\n", + " good_wavelengths (wavelengths) float32 1kB 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0\n", + " elev (latitude, longitude) float64 48kB nan nan ... 1.169e+03\n", + " spatial_ref int64 8B 0\n", + " cirrus_mask (latitude, longitude) float64 48kB nan nan nan ... 0.0 0.0\n", + " land_mask (latitude, longitude) float64 48kB nan nan nan ... 0.0 0.0\n", + " cloud_mask (latitude, longitude) float64 48kB nan nan nan ... 0.0 0.0\n", + " * latitude (latitude) float64 528B 38.36 38.36 38.36 ... 38.32 38.32\n", + " * longitude (longitude) float64 728B -102.7 -102.7 ... -102.7 -102.7\n", + "Data variables:\n", + " reflectance (latitude, longitude, wavelengths) float64 14MB nan ......\n", + " Rrs (latitude, longitude, wavelengths) float64 14MB nan ......\n", + " NDCI (latitude, longitude) float64 48kB nan nan ... 0.04753\n", + " NDTI (latitude, longitude) float64 48kB nan nan ... 0.1322\n", + "Attributes: (12/40)\n", + " ncei_template_version: NCEI_NetCDF_Swath_Template_v2.0\n", + " summary: The Earth Surface Mineral Dust Source ...\n", + " keywords: Imaging Spectroscopy, minerals, EMIT, ...\n", + " Conventions: CF-1.63\n", + " sensor: EMIT (Earth Surface Mineral Dust Sourc...\n", + " instrument: EMIT\n", + " ... ...\n", + " spatial_ref: GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHER...\n", + " geotransform: [-1.03613320e+02 5.42232520e-04 -0.00...\n", + " day_night_flag: Day\n", + " title: EMIT L2A Estimated Surface Reflectance...\n", + " granule_id: EMIT_L2A_RFL_001_20230403T190544_23093...\n", + " Orthorectified: True" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Coasrsen EMIT like ECOSTRESS\n", + "emit_coarse = ___.interp_like(___)" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "86a2ce55-d889-435e-9685-48056879c53b", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":Image [longitude,latitude] (NDCI)" + ] + }, + "execution_count": 93, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p3205" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "# Quick Visualization of EMIT Coarsened to ECOSTRESS resolution\n", + "emit_coarse['NDCI'].where(emit_coarse.land_mask==1).hvplot(x='longitude', y='latitude', aspect = 'equal', frame_width=400, cmap='Viridis')" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "id": "827883e5-78a9-4020-bade-12c556b632d7", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":Image [longitude,latitude] (value)" + ] + }, + "execution_count": 100, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p3625" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "# Quick Visualization of ECOSTRESS with EMIT's land mask\n", + "___.where(emit_coarse.land_mask == 1).hvplot(x='longitude', y='latitude', aspect = 'equal', frame_width=400, cmap='Magma')" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "1e9e1d8b-63dd-4f32-972d-623ed8389484", + "metadata": {}, + "outputs": [], + "source": [ + "# Quick and Dirty Regression \n", + "x = emit_coarse.NDTI.where(emit_coarse.land_mask == 1).values.flatten()\n", + "y = ___.where(emit_coarse.land_mask == 1).values.flatten()\n", + "df = pd.DataFrame(data={'x':x, 'y':y}).dropna()\n", + "slope, intercept, r, p, se = linregress(df.x.values, df.y.values)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "id": "2820c019-ad70-4984-909e-fbda00cd7b5b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.0, 'EMIT NDCI vs. ECOSTRESS LST')" + ] + }, + "execution_count": 101, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA38AAAHFCAYAAABCeUC1AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAACuFElEQVR4nOzdeVhUZfsH8O+AgICAICCgbJm4r0iIGrmSZBlq5fLmUmqaS/lar4Jmapmg9fNtMU0tt3pdMjUt9zJFIg23xN0QBXVQcRlcCBTO749xxlnODDPDDDPDfD/XRVczc+ac5xxmZO65n+e+JYIgCCAiIiIiIqJqzcnaAyAiIiIiIiLLY/BHRERERETkABj8EREREREROQAGf0RERERERA6AwR8REREREZEDYPBHRERERETkABj8EREREREROQAGf0RERERERA6AwR8REREREZEDYPBHpMfy5cshkUh0/uzZs0e5bUREBCQSCTp37iy6r5UrV4o+b8aMGZBIJCgsLMSePXv0Hk/1R5cLFy4ot1mzZo3W46rHUxg2bJjavj09PREREYHevXtj2bJlKCkpET1WeXk5vv32W3Tv3h3+/v5wcXFBYGAgnn/+efz0008oLy9XG9Mnn3yi52pbj+J3J/Yj9vs8duwYXnvtNURGRqJmzZqoVasW2rZti7lz5+LmzZtq2z548AALFy5EXFwcfHx84O7ujiZNmiA5ORk3btzQ2veDBw+waNEixMTEwM/PDx4eHggPD8eLL76IjRs3AgA6d+5s0GtkxowZoufn6emJtm3bYv78+RAEQe34Fb0Gly9fbtRYFfLz8zFmzBhERUXB3d0dfn5+aNGiBUaOHIn8/Hy9vx/FmH744Qe92924cQMpKSlo2rQpPD094ePjg8aNG2Pw4ME4duwYABj8/lJ9jxIREVUXNaw9ACJ7sGzZMjRu3Fjr/qZNm6rd9vLyQnp6OnJyctCgQQO1x5YuXQpvb28UFRXpPE7btm3xxx9/qN3Xp08fNGjQwKTAaerUqejXrx9cXFwq3Nbd3R27d+8GABQXFyM/Px/btm3DyJEj8X//93/Yvn076tevr9z+n3/+QVJSEnbu3IkBAwZg4cKFCAoKwvXr17F9+3a8/PLLWLt2LV588UWjx20NHTt2FL3G3t7eareXLFmCMWPGoFGjRvjPf/6Dpk2b4sGDBzh48CC++uor/PHHH8rA5/79+3juueeQkZGBN954A9OmTYO7uzv++OMPfPLJJ1i1ahV27dqFRo0aKfc/ePBgbNiwARMmTMDMmTPh5uaG8+fPY/v27dixYwf69OmDBQsWqL2OtmzZglmzZmm9TlV/X6rnd+XKFcybNw/jx49HUVERpkyZonXes2fPRpcuXbTuV31dGzJWALh06RLatm2L2rVr45133kGjRo0gk8lw8uRJfP/99zh//jxCQ0P1/4IqcPfuXbRv3x53797Ff/7zH7Rq1QrFxcU4e/YsNmzYgKNHj6Jly5Za768PP/wQv/32m/K1r6D53iYiIqoWBCLSadmyZQIAISsrq8Jtw8PDhcTERKF+/frClClT1B77+++/BYlEIowcOVIAIPz222/Kx6ZPny4AEK5fv65zv7169TJ4zLm5uQIAITExUQAgfP7552qPix1v6NChgqenp+j+duzYIbi4uAixsbFq97/55psCAGHFihWizzt79qzw119/qY3p448/Nvg8qpKh1zgzM1NwdnYWevbsKfzzzz9aj5eUlAibNm1S3n7jjTcEAMKaNWu0tj1z5ozg4+MjNGvWTHj48KEgCIJw/vx5AYDw/vvvix6/rKxM9P6KXqdi5yeTyQQfHx8hLCxM7f7ffvtNACCsW7dOdF8Kxoz1/fffFwAI58+fr3BbMYaMaenSpQIAYffu3UYdQ99rn4iIqLrhtE8iM3JycsKQIUOwYsUK5ZRHQJ71Cw0NRffu3atsLF27dsWzzz6LDz/8EHfu3DF5PwkJCRg5ciQOHDiA9PR0AEBBQQG+/vprPPvssxgyZIjo8xo2bIiWLVsafJwHDx4gMDAQgwcP1nrs9u3bcHd3x8SJEwHIp5vOmjULjRo1gru7O2rXro2WLVvis88+M+EMDTd79mxIJBIsXrwYbm5uWo+7urqid+/eAOTXaOnSpXj22WfRv39/rW2joqIwefJknDhxAj/++CMAKKeBBgcHix7fycl8/2R7e3sjKioKV69eNen5xoz1xo0bcHJyQmBgYIXbmqoqrx0REZG94l9DIgOUlZXh4cOHaj9lZWWi277++uu4cuUKduzYoXzuihUrMGzYsCr/ADpnzhwUFhbi448/rtR+FAGNIvj77bff8ODBAyQlJVV2iEouLi549dVXsX79eq2psatXr8Y///yD1157DQAwd+5czJgx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54aEhOD69esAgNraWl0ZERER0VjhY59EZFEef/xxHDp0SFE2ZcoUvXorVqzAli1bcOHCBRw5csSss35aDz30EHbu3Inf/OY3A34/0BARgUql0v0MQPc7ERER0VjgzB8RWRRXV1fMnDlT8TKU/Dk4OCAhIQFpaWm4ePEi4uPjx6R/27dvR1dXFw4ePDis82pqahAUFAQAmD17tq6MiIiIaKww+SMiq5WYmIjz58/jqaeegoeHx5i0OXnyZLz22mvIyMhAR0fHkM65evUqzpw5g6effhrAd4u6hIaG4ve//73B7w+2tbWNZpeJiIiIADD5IyIL093djaamJsWrpaXFYN05c+agpaVFb9sHc9u8eTM0Go3eFhQA0Nvbi6amJty+fRuVlZX4wx/+gJiYGERGRuKVV14B8N3jnjk5Ofjiiy+wZMkSnD59GvX19fj888+RkZGBp556akzjISIiItvA7/wRkUU5c+YMfHx8FGXBwcG4evWqwfpTp04di24pODo6Ys+ePdiwYYPesaqqKvj4+MDe3h4ajQahoaFITU3FCy+8ACcnJ129BQsW4PLly8jIyMCmTZvQ0tICHx8fREdH48CBA2MYDREREdkKlWhXHiAiIiIiIqIJi499EhERERER2QAmf0RERERERDaAyR8REREREZENYPJHRERERERkA5j8ERERERER2QAmf0RERERERDaAyR8REREREZENYPJHRERERERkA5j8ERERERER2QAmf0RERERERDaAyR8REREREZENYPJHRERERERkA/4PEEv7McosD1MAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Visualize Regression\n", + "fig,ax = plt.subplots(1,1)\n", + "ax.plot(x.flatten(), y.flatten(), '.')\n", + "ax.plot(df.x.values, intercept + slope * df.x.values, 'r', linewidth=.5)\n", + "ax.set_xlabel('EMIT NDCI')\n", + "ax.set_ylabel('ECOSTRESS LST')\n", + "ax.text(0.1, 287, f\" N = {str(len(df.x))} {chr(10)} y={np.round(slope, 2)}x + {np.round(intercept, 2)} {chr(10)} $R^2:{np.round(r ** 2, 2)}$\")\n", + "ax.set_title('EMIT NDCI vs. ECOSTRESS LST')" + ] + }, + { + "cell_type": "markdown", + "id": "f5e56685-25ac-45ad-8b24-ba835cb135d8", + "metadata": {}, + "source": [ + "
\n", + " Exercises \n", + "\n", + "1. Try out different bands in the spectral indices. How does it change the spatial patterns in the lake?\n", + "\n", + "2. What aquatic processes could contribute to the differences between chlorophyll and temperature in the regression plot (e.g., phytoplankton bloom, other types of aquatic biomass present)?\n", + "\n", + "3. Replace the filenames with the Niwot Ridge EMIT (EMIT_L2A_RFL_001_20230625T170814_2317611_005.nc) and and ECOSTRESS (data/iplant/home/shared/esiil/HYR_SENSE/data/water_quality/ECOv002_L2T_LSTE_28176_004_13TDE_20230625T170739_0710_01_LST.tif) scenes uploaded in the data-store. Modify the code to make it work! You got this! \n", + " \n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "b4681f1d-3870-40ce-86fb-4d847bf2d684", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "## Additional Resources\n", + "\n", + "- [CSIRO EMIT Exploration Code](https://github.com/auspatious/hyperspectral-notebooks/blob/main): Water Extraction and Exploration code \n", + "- [HyperCoast](https://github.com/opengeos/HyperCoast): EMIT and PACE visualization and algorithm toolbox in Python\n", + "- [Digital Earth Africa](https://docs.digitalearthafrica.org/en/latest/sandbox/notebooks/Real_world_examples/index.html): Digital Earth Africa has several notebook tutorials with Landsat based spectral indices\n", + "- [NEON Tutorials](https://www.neonscience.org/resources/learning-hub/tutorials): Search for \"hyperspectral\" in the keyword box and you will find lots of great resources!\n", + "\n", + "## References\n", + "\n", + "- Lacaux et al (2007), Classification of ponds from high-spatial resolution remote sensing: Application to Rift Valley Fever epidemics in Senegal, Remote Sensing of Environment, 106, 66-74.\n", + "- Mishra & Mishra (2012). Normalized difference chlorophyll index: A novel model for remote estimation of chlorophyll-a concentration in turbid productive waters. Remote Sensing of Environment, 117, 394-406. \n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hyrsense", + "language": "python", + "name": "hyrsense" + }, + "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.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/water_quality/lesson2_EMITnECO.ipynb b/notebooks/water_quality/lesson2_EMITnECO.ipynb index 971487d..746714d 100644 --- a/notebooks/water_quality/lesson2_EMITnECO.ipynb +++ b/notebooks/water_quality/lesson2_EMITnECO.ipynb @@ -564,11 +564,11 @@ "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", - "
\n", + "
\n", "
\n", "" + ], + "text/plain": [ + ":Overlay\n", + " .WMTS.I :WMTS [Longitude,Latitude]\n", + " .Image.I :Image [longitude,latitude] (value)\n", + " .Polygons.I :Polygons [Longitude,Latitude]" + ] + }, + "execution_count": 9, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1160" + } + }, + "output_type": "execute_result" + } + ], "source": [ "# ECOSTRESS Visualization\n", "size_opts = dict(frame_height=405, frame_width=720, fontscale=2)\n", @@ -1388,22 +1475,110 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 10, "id": "13386023-7e9a-40ec-9c1b-866b797c268d", "metadata": { "scrolled": true }, "outputs": [ { - "ename": "NameError", - "evalue": "name 'emit_rgb' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[2], line 7\u001b[0m\n\u001b[1;32m 4\u001b[0m color_cycle \u001b[38;5;241m=\u001b[39m hv\u001b[38;5;241m.\u001b[39mCycle(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCategory20\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# Create RGB Map\u001b[39;00m\n\u001b[0;32m----> 7\u001b[0m \u001b[38;5;28mmap\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43memit_rgb\u001b[49m\u001b[38;5;241m.\u001b[39mhvplot\u001b[38;5;241m.\u001b[39mrgb(fontscale\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1.5\u001b[39m, xlabel\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mLongitude\u001b[39m\u001b[38;5;124m'\u001b[39m,ylabel\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mLatitude\u001b[39m\u001b[38;5;124m'\u001b[39m,frame_width\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m480\u001b[39m, frame_height\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m480\u001b[39m)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# Set up a holoviews points array to enable plotting of the clicked points\u001b[39;00m\n\u001b[1;32m 10\u001b[0m xmid \u001b[38;5;241m=\u001b[39m emit_ds\u001b[38;5;241m.\u001b[39mlongitude\u001b[38;5;241m.\u001b[39mvalues[\u001b[38;5;28mint\u001b[39m(\u001b[38;5;28mlen\u001b[39m(emit_ds\u001b[38;5;241m.\u001b[39mlongitude) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m)]\n", - "\u001b[0;31mNameError\u001b[0m: name 'emit_rgb' is not defined" - ] + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + ":Layout\n", + " .DynamicMap.I :DynamicMap []\n", + " :Overlay\n", + " .Curve.I :Curve [wavelengths] (reflectance)\n", + " .Curve.A_0 :Curve [wavelengths] (reflectance)\n", + " .Overlay.I :Overlay\n", + " .RGB.I :RGB [longitude,latitude] (R,G,B)\n", + " .Points.I :Points [x,y] (id)" + ] + }, + "execution_count": 10, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1286" + } + }, + "output_type": "execute_result" } ], "source": [ @@ -1472,7 +1647,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 12, "id": "2f8213e6-c097-44da-8d61-86ad0772968b", "metadata": {}, "outputs": [], @@ -1489,9 +1664,9 @@ " row = [i, x, y] + list(spectra)\n", " rows.append(row)\n", "\n", - "#with open('data/emit_click_data.csv', 'w', newline='') as f:\n", - "# writer = csv.writer(f)\n", - "# writer.writerows(rows)" + "with open('data/emit_click_data.csv', 'w', newline='') as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(rows)" ] }, { @@ -1514,7 +1689,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 13, "id": "e056b1c6", "metadata": {}, "outputs": [ @@ -1900,8 +2075,7 @@ "Data variables:\n", " reflectance (latitude, longitude, wavelengths) float32 12MB 0.04834...\n", " Rrs (latitude, longitude, wavelengths) float32 12MB 0.01539...\n", - " NDCI (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n", - " NDTI (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n", + " NDCI (latitude, longitude) float32 42kB 0.04259 ... 0.04818\n", "Attributes: (12/40)\n", " ncei_template_version: NCEI_NetCDF_Swath_Template_v2.0\n", " summary: The Earth Surface Mineral Dust Source ...\n", @@ -1915,8 +2089,8 @@ " day_night_flag: Day\n", " title: EMIT L2A Estimated Surface Reflectance...\n", " granule_id: EMIT_L2A_RFL_001_20230403T190544_23093...\n", - " Orthorectified: True" ], "text/plain": [ @@ -2143,8 +2317,7 @@ "Data variables:\n", " reflectance (latitude, longitude, wavelengths) float32 12MB 0.04834...\n", " Rrs (latitude, longitude, wavelengths) float32 12MB 0.01539...\n", - " NDCI (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n", - " NDTI (latitude, longitude) float32 42kB 1.0 1.0 1.0 ... 1.0 1.0\n", + " NDCI (latitude, longitude) float32 42kB 0.04259 ... 0.04818\n", "Attributes: (12/40)\n", " ncei_template_version: NCEI_NetCDF_Swath_Template_v2.0\n", " summary: The Earth Surface Mineral Dust Source ...\n", @@ -2161,7 +2334,7 @@ " Orthorectified: True" ] }, - "execution_count": 25, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -2176,7 +2349,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 14, "id": "a39aa077-bb76-4d56-b91b-c984f97fa292", "metadata": {}, "outputs": [ @@ -2189,12 +2362,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "