{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# ODC Basic Functionality\n", "\n", "\n", "\n", "\n", "## What you'll discover using ODC.\n", "\n", "- Shift in paradigm from scene based analysis to pixel based.\n", "- A simple, standard, and extensible way to interact with and perform analysis on data.\n", "- Allow users to define exactly in what state data is to be delivered in terms of projection, resolution, bands and datasets.\n", "- Easily create subsets or derivative products that are managed and tracked by the ODC.\n", "- Provide a base set of functions and tools that make analysis more simple!\n", "\n", "\n", "### Let's get right into it by loading a cube.\n", "\n", "In the sample below we use the datacube.load command to load the RGB and Quality Assurance(QA) bands from the AWS Landsat archive. Landsat 8 has a return period of 16 days capturing over 24 snapshots a year so care should be taken when requesting a datacube as large geographical or time extents can quickly over fill memory and generate huge lag. \n", "\n", "For our first visualisation we'll load a single time slice of the full geographical extent indexed and then proceed to select a smaller zone to explore through time.\n", "\n", "It should be noted that images on AWS are referenced to WGS 84 so the extent bounds that are entered into the datacube.load() must match the coordinate system in which they're being stored. \n", "\n", "The datacube.load() command also reprojects into a coordinate system in the below datacube load we automatically generate an EPSG code from the lat/long of the provided extent. \n", "\n", "If you'd like to visualize other bands add any of the below measurements to the `datacube.load(measurements= ...`:\n", "\n", "Landsat 8 measurement options are:\n", "\n", " ('1', 'coastal_aerosol')\n", " ('2', 'blue')\n", " ('3', 'green')\n", " ('4', 'red')\n", " ('5', 'nir')\n", " ('6', 'swir1')\n", " ('7', 'swir2')\n", " ('8', 'panchromatic')\n", " ('9', 'cirrus')\n", " ('10', 'lwir1')\n", " ('11', 'lwir2')\n", " ('QUALITY', 'quality')]\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "## First we load the libraries that are going to utilise\n", "\n", "%matplotlib notebook\n", "import datacube # Load the datacube library\n", "import datetime\n", "import numpy as np\n", "import json\n", "import matplotlib.pyplot as plt\n", "from utils.utils import (\n", " lat_lon_to_epsg,\n", " three_band_image,\n", " load_config_extents,\n", " transform_to_wgs,\n", " load_config)\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 33.5 s, sys: 3.38 s, total: 36.9 s\n", "Wall time: 2min\n" ] } ], "source": [ "%%time\n", "\n", "dc = datacube.Datacube(app='load-data-example')\n", "\n", "# Let's request a datacube!!\n", "\n", "#if you want to load the case study area that has been chosen in the landing page uncomment the below\n", "# the code marked [LANDING PAGE EXTENT LOAD].\n", "\n", "lon_min,lon_max,lat_min,lat_max = [146.30,146.83,-43.54,-43.20]\n", "date_range = (\n", " datetime.datetime(2017, 1, 1),\n", " datetime.datetime(2018, 1, 1)) \n", "\n", "\n", "#config = load_config('./configIndex.txt') #[LANDING PAGE EXTENT LOAD]\n", "#lon_min,lon_max = config['lon'] #[LANDING PAGE EXTENT LOAD]\n", "#lat_min,lat_max = config['lat'] #[LANDING PAGE EXTENT LOAD]\n", "#date_range=tuple(sorted(config['time'])) #[LANDING PAGE EXTENT LOAD]\n", "\n", "\n", "# Get the EPSG of a WGS UTM coordinate reference system that is appropriate for our data\n", "EPSG = lat_lon_to_epsg(lat_max,lon_min)\n", "\n", "data_cube = dc.load(\n", " product='ls8_level1_usgs',\n", " x=(lon_min, lon_max),\n", " y=(lat_min, lat_max), \n", " output_crs='epsg:' + EPSG,\n", " resolution=(-30, 30),\n", " time = date_range, \n", " measurements = ('red','green','blue','quality'))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Dimensions: (time: 37, x: 1439, y: 1267)\n", "Coordinates:\n", " * time (time) datetime64[ns] 2017-03-03T23:58:42.374786 ...\n", " * y (y) float64 5.217e+06 5.217e+06 5.217e+06 5.217e+06 5.217e+06 ...\n", " * x (x) float64 4.431e+05 4.431e+05 4.432e+05 4.432e+05 4.432e+05 ...\n", "Data variables:\n", " red (time, y, x) int16 13965 14398 15275 15624 15004 13273 11270 ...\n", " green (time, y, x) int16 13767 14052 14824 15144 14751 13032 11156 ...\n", " blue (time, y, x) int16 14225 14421 15204 15508 15189 13604 11835 ...\n", " quality (time, y, x) int16 2800 2800 2800 2800 2800 2800 2800 2800 2800 ...\n", "Attributes:\n", " crs: epsg:32755\n" ] } ], "source": [ "print(data_cube)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Let's explore what a data cube is.\n", "\n", "In the context of earth observation a data cube is a multi-dimensional array that will consistantly contain the dimensions of time and a spatial grid. Along these dimensions any number of measurements can be associated to these grids and will represent the measurement taken at a specific time and space. \n", "\n", "\n", "\n", "The ODC uses the XArray library http://xarray.pydata.org/en/stable/, the key to building effective ODC algorithms is to master the use of the xarray. Please click on the documention to find out more otherwise a number of examples are provided below.\n", "\n", "They're also python libraries such as Dask http://dask.pydata.org/en/latest/ that can scale up computation of XArray to supercomputing, and cloud solutions. They're many other project utilising XArray and it becoming a standard for multi-dimenional data analysis.\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Dimensions: (time: 37, x: 1, y: 1)\n", "Coordinates:\n", " * time (time) datetime64[ns] 2017-03-03T23:58:42.374786 ...\n", " * y (y) float64 5.187e+06\n", " * x (x) float64 4.581e+05\n", "Data variables:\n", " red (time, y, x) int16 5988 12339 20695 20597 6000 14938 6776 12790 ...\n", " green (time, y, x) int16 6652 12497 20690 20136 6636 14783 7123 12620 ...\n", " blue (time, y, x) int16 7419 12678 22285 21359 7491 15937 7853 13692 ...\n", " quality (time, y, x) int16 2720 2800 2800 2800 2720 2800 2800 2800 2720 ...\n", "Attributes:\n", " crs: epsg:32755\n", "----------------------------------------------\n", "\n", "Dimensions: (time: 37, x: 1, y: 1)\n", "Coordinates:\n", " * time (time) datetime64[ns] 2017-03-03T23:58:42.374786 ...\n", " * y (y) float64 5.179e+06\n", " * x (x) float64 4.431e+05\n", "Data variables:\n", " red (time, y, x) int16 6528 6525 28579 12248 6449 18529 5795 18697 ...\n", " green (time, y, x) int16 6987 7003 27724 12491 6931 17894 6183 17808 ...\n", " blue (time, y, x) int16 7708 7755 28732 13710 7723 19014 6915 18639 ...\n", " quality (time, y, x) int16 2720 2720 2800 2800 2720 2800 2976 2800 2720 ...\n", "Attributes:\n", " crs: epsg:32755\n", "----------------------------------------------\n", "\n", "Dimensions: (x: 100, y: 100)\n", "Coordinates:\n", " time datetime64[ns] 2017-03-19T23:58:32.578365\n", " * y (y) float64 5.211e+06 5.211e+06 5.211e+06 5.211e+06 5.211e+06 ...\n", " * x (x) float64 4.491e+05 4.491e+05 4.492e+05 4.492e+05 4.492e+05 ...\n", "Data variables:\n", " red (y, x) int16 21484 21018 20389 21588 21654 21391 21316 21179 ...\n", " green (y, x) int16 21053 20686 20158 21053 21308 21040 21035 20862 ...\n", " blue (y, x) int16 21595 21414 21163 22249 22284 22107 22006 21767 ...\n", " quality (y, x) int16 2800 2800 2800 2800 2800 2800 2800 2800 2800 2800 ...\n", "Attributes:\n", " crs: epsg:32755\n" ] } ], "source": [ "%matplotlib notebook\n", "# Pixel Drill by index through time\n", "pixel_drill_index = data_cube.isel(x=[500], y=[1000])\n", "print(pixel_drill_index)\n", "print('----------------------------------------------')\n", "\n", "# Pixel Drill by coordinates through time.\n", "pixel_drill_coordinates = data_cube.sel(x=[-4788000], y=[1197000], method='nearest')\n", "print(pixel_drill_coordinates)\n", "print('----------------------------------------------')\n", "\n", "# Pixel Drill by coordinates through time.\n", "pixel_slice_index = data_cube.isel(x=slice(200,300), y=slice(200,300), time=2)\n", "print(pixel_slice_index)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Querying a data cube.\n", "\n", "Our datacube can now be sliced, trimmed or querried with masks, you can basically sculpt any object out of the cube pixels.\n", "\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('
');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", " this.imageObj.onload = function() {\n", " if (fig.image_mode == 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function() {\n", " fig.ws.close();\n", " }\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "}\n", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '
');\n", " var titletext = $(\n", " '
');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('
');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('
')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('
');\n", " var button = $('');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " event.shiftKey = false;\n", " // Send a \"J\" for go to next cell\n", " event.which = 74;\n", " event.keyCode = 74;\n", " manager.command_mode();\n", " manager.handle_keydown(event);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "[]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%matplotlib notebook\n", "# Operations on cubes.\n", "monthly_means = pixel_drill_coordinates.groupby('time.month').mean()\n", "print(monthly_means)\n", "print('---------------------------------')\n", "\n", "y_cross_sections = pixel_slice_index.groupby('x').mean()\n", "print(y_cross_sections)\n", "y_cross_sections.red.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we'll explore [Landsat 8 quality band](https://landsat.usgs.gov/collectionqualityband), each pixel in the QA band contains unsigned integers that represent bit-packed combinations of surface, atmospheric, and sensor conditions that can affect the overall usefulness of a given pixel.\n", "\n", "Used effectively, QA bits improve the integrity of science investigations by indicating which pixels might be affected by instrument artifacts or subject to cloud contamination. The ODC has in built methods that transform the metadata of a specific product to a libary of masking templates. For example, you are able to build a cloud mask directly from the ODC library.\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " bits \\\n", "cirrus_confidence [11, 12] \n", "cloud [4] \n", "cloud_confidence [5, 6] \n", "cloud_shadow_conf [7, 8] \n", "designated_fill [0] \n", "radiometric_saturation [2, 3] \n", "snow_ice_conf [9, 10] \n", "terrain_occlusion [1] \n", "\n", " values \\\n", "cirrus_confidence {'0': 'Not Determined', '1': 'Low', '2': 'Medi... \n", "cloud {'0': False, '1': True} \n", "cloud_confidence {'0': 'Not Determined', '1': 'Low', '2': 'Medi... \n", "cloud_shadow_conf {'0': 'Not Determined', '1': 'Low', '2': 'Medi... \n", "designated_fill {'0': False, '1': True} \n", "radiometric_saturation {'0': 'none', '1': '1-2', '2': '3-4', '3': '<=5'} \n", "snow_ice_conf {'0': 'Not Determined', '1': 'Low', '2': 'Medi... \n", "terrain_occlusion {'0': False, '1': True} \n", "\n", " description \n", "cirrus_confidence Cirrus Confidence with low =(0-33)%, medium =(... \n", "cloud Cloud \n", "cloud_confidence Cloud Confidence with low =(0-33)%, medium =(3... \n", "cloud_shadow_conf Cloud Shadow Confidence with low =(0-33)%, med... \n", "designated_fill Used to identify fill values \n", "radiometric_saturation Radiometric saturation bits, represents how ma... \n", "snow_ice_conf Snow/Ice Confidence with low =(0-33)%, medium ... \n", "terrain_occlusion Terrain Occlusion \n" ] } ], "source": [ "from datacube.storage import masking # Import masking capabilities\n", "print (masking.describe_variable_flags(ds)) #D escribe the masks available\n", "\n" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "array([[[False, False, ..., True, True],\n", " [False, False, ..., True, True],\n", " ...,\n", " [ True, True, ..., True, True],\n", " [ True, True, ..., True, True]]])\n", "Coordinates:\n", " * time (time) datetime64[ns] 2017-03-12T23:52:26.445797\n", " * y (y) float64 5.217e+06 5.217e+06 5.217e+06 5.217e+06 5.217e+06 ...\n", " * x (x) float64 4.431e+05 4.431e+05 4.432e+05 4.432e+05 4.432e+05 ...\n", "\n", "Dimensions: (time: 1, x: 1439, y: 1267)\n", "Coordinates:\n", " * time (time) datetime64[ns] 2017-03-12T23:52:26.445797\n", " * y (y) float64 5.217e+06 5.217e+06 5.217e+06 5.217e+06 5.217e+06 ...\n", " * x (x) float64 4.431e+05 4.431e+05 4.432e+05 4.432e+05 4.432e+05 ...\n", "Data variables:\n", " red (time, y, x) float64 nan nan nan nan nan nan nan nan nan nan ...\n", " green (time, y, x) float64 nan nan nan nan nan nan nan nan nan nan ...\n", " blue (time, y, x) float64 nan nan nan nan nan nan nan nan nan nan ...\n", " quality (time, y, x) float64 nan nan nan nan nan nan nan nan nan nan ...\n", "Attributes:\n", " crs: epsg:32755\n" ] } ], "source": [ "# Create mask around all pixels deemed good according to parameters around cloud cover and saturation.\n", "clean_pixel_mask = masking.make_mask(\n", " ds.quality,\n", " cloud=False,\n", " radiometric_saturation='none',\n", " terrain_occlusion = False)\n", "\n", "print(clean_pixel_mask)\n", "\n", "masked_cloud = ds.where(clean_pixel_mask)\n", "\n", "print(masked_cloud)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we'll display the RGB bands that we have extracted from our cube for the first time slice (time = 0) in order to visualise a comprehendible RGB image we apply a histogram equalisation on each band before displaying. We'll also create visualisation of the pixels that are occluding land areas." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "scrolled": false }, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('
');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", " this.imageObj.onload = function() {\n", " if (fig.image_mode == 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function() {\n", " fig.ws.close();\n", " }\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "}\n", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '
');\n", " var titletext = $(\n", " '
');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('
');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('
')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('