├── LICENSE ├── README.md ├── database └── db_dump.tar.xz ├── images ├── Flood_Example_Campur.jpeg ├── Flood_Example_Tabasco.jpeg ├── GEE Auth Info.png └── Google Drive Auth Info.png ├── notebooks ├── 01.01.Getting_Started_ODC_and_Colab.ipynb ├── 02.01.Colab_Cloud_Statistics_L8.ipynb ├── 02.02.Colab_Cloud_Statistics_S2.ipynb ├── 02.03.Colab_Median_Mosaic_L8.ipynb ├── 02.04.Colab_Water_WOFS_L8.ipynb ├── 02.05.Colab_Spectral_Products_L8.ipynb ├── 02.06.Colab_Vegetation_Change_L8.ipynb ├── 02.07.Colab_Vegetation_Phenology_L8.ipynb ├── 02.08.01.Colab_S1_Flooding_Detailed_Region.ipynb ├── 02.08.02.Colab_S1_Flooding_Large_Region.ipynb ├── 02.08.03.Colab_S1_SDG_661_WaterExtent.ipynb ├── 02.09.Colab_Mission_Coincidences.ipynb ├── 02.10.Colab_VIIRS_Night_Lights.ipynb ├── 02.11.01.Colab_ALOS_Land_Change_Detailed_Region.ipynb ├── 02.11.02.Colab_ALOS_Land_Change_Large_Region.ipynb ├── 02.12.Colab_Rainfall_AirTemp.ipynb ├── 02.13.Colab_NASA_DEM.ipynb ├── 02.14.01.Colab_LandCover_WorldCover_10m.ipynb ├── 02.14.02.Colab_LandCover_Copernicus_100m.ipynb └── 02.14.03.Colab_LandCover_MODIS_500m.ipynb ├── odc_colab.py ├── patches ├── default.diff └── schema.diff └── tests └── Automated_Testing.ipynb /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | ODC-Colab is a CEOS initiative to demonstrate Open Data Cube notebooks running on Google Colab. 190 | Copyright 2021 CEOS 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ODC-Colab 2 | ODC-Colab is a CEOS initiative to demonstrate [Open Data 3 | Cube](https://www.opendatacube.org/) notebooks running within [Google 4 | Colab](https://colab.research.google.com/). This is done through a Python 5 | module with methods that perform an automated setup of an ODC environment 6 | through simple method calls. 7 | 8 | This repository includes several example notebooks in the `./notebooks` 9 | directory. We suggest starting with 10 | [01.01.Getting\_Started\_ODC\_and\_Colab.ipynb](https://github.com/ceos-seo/odc-colab/blob/master/notebooks/01.01.Getting_Started_ODC_and_Colab.ipynb) 11 | if unfamiliar with ODC or Colab notebooks. 12 | 13 | The example notebooks make use of Google Earth Engine data. They will will 14 | require some user interaction for Google authentication, and the user needs to 15 | be registered as an Earth Engine developer. If not, you may submit an 16 | [application to Google](https://signup.earthengine.google.com/). These 17 | notebooks make use of the CEOS ODC-GEE project which can be found here: 18 | [https://github.com/ceos-seo/odc-gee](https://github.com/ceos-seo/odc-gee). 19 | 20 | **Note:** The `gee-notebooks` use global products obtained from GEE 21 | using [ODC-GEE real-time indexing 22 | capabilities](https://github.com/ceos-seo/odc-gee#real-time-indexing). Other 23 | GEE datasets may also be used by including an asset parameter in the `dc.load` 24 | as shown in the README of the ODC-GEE project. 25 | 26 | ## Usage 27 | You will need to add some code to the top of your notebook to use the Python 28 | module. There are two different example options for environments shown, but 29 | these are not the only uses of the module. More options are available and can 30 | be found by reading the included docstrings in the `odc_colab.py` source file. 31 | ### Local database environment 32 | This environment is for installing ODC with a local database. Local in this 33 | context means **local to the Colab VM**. This code should not be used outside 34 | of Colab. 35 | 36 | The following block downloads the Python module and then runs the setup with a 37 | default local database configuration that includes CEOS ODC utilities: 38 | 39 | !wget -nc https://raw.githubusercontent.com/ceos-seo/odc-colab/master/odc_colab.py 40 | from odc_colab import odc_colab_init 41 | odc_colab_init() 42 | 43 | The previous block of code will create an environment, but the index will be 44 | empty so needs to be populated. This can be done by importing a database dump 45 | of an existing ODC index: 46 | 47 | from odc_colab import populate_db 48 | populate_db(path=.tar.xz) 49 | 50 | The `populate_db()` command without parameters will download 51 | `database/db_dump.tar.xz` from this repository to use for populating the 52 | database. 53 | 54 | ##### Converting existing notebooks (advanced) 55 | If you have existing notebooks you want to convert for use with this Colab 56 | configuration, a diff file is included to make converting from existing Jupyter 57 | notebooks to Colab notebooks simple. This can be done using the GNU `patch` 58 | tool: `patch default.diff`. 59 | 60 | This will also add a Colab button to the top of the notebook. This button can 61 | take a GitHub URI for the notebook and automatically open it in Colab from 62 | there. You will have to replace the `` with your notebook's 63 | URI first, or you can optionally remove that block from your notebook. 64 | 65 | **NOTE:** The patch only adds the default top blocks specified earlier. You may 66 | have to specify to install ODC-GEE if wanting a similar environment as the 67 | example notebooks, or you may have to provide a database dump to populate the 68 | index. 69 | 70 | ### Remote database environment 71 | This environment is for installing ODC within Colab for a remote database 72 | connection. A remote database would be a database outside of the Colab VM (i.e. 73 | a remote PostgreSQL server). 74 | 75 | The following block downloads the Python module, sets an environment variable 76 | to allow remote connections, and initializes the ODC environment with CEOS ODC 77 | utilities included: 78 | 79 | Substitutions: 80 | * `hostname`: the hostname of the target database. 81 | * `username`: the username of the target database. 82 | * `password`: Optional; the password for the connecting username (default: None). 83 | * `dbname`: Optional; the database name to connect to (default: datacube). 84 | * `port`: Optional; the port number to connect to (default: 5432). 85 | 86 | ``` 87 | !wget -nc https://raw.githubusercontent.com/ceos-seo/odc-colab/master/odc_colab.py 88 | from odc_colab import build_datacube_db_url, odc_colab_init 89 | odc_colab_init(install_postgresql=False, use_defaults=False, 90 | DATACUBE_DB_URL=build_datacube_db_url(, , password=, 91 | dbname=, port=) 92 | ``` 93 | -------------------------------------------------------------------------------- /database/db_dump.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceos-seo/odc-colab/a5f20c1e18e2be33efe9150cb65f814acba96d70/database/db_dump.tar.xz -------------------------------------------------------------------------------- /images/Flood_Example_Campur.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceos-seo/odc-colab/a5f20c1e18e2be33efe9150cb65f814acba96d70/images/Flood_Example_Campur.jpeg -------------------------------------------------------------------------------- /images/Flood_Example_Tabasco.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceos-seo/odc-colab/a5f20c1e18e2be33efe9150cb65f814acba96d70/images/Flood_Example_Tabasco.jpeg -------------------------------------------------------------------------------- /images/GEE Auth Info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceos-seo/odc-colab/a5f20c1e18e2be33efe9150cb65f814acba96d70/images/GEE Auth Info.png -------------------------------------------------------------------------------- /images/Google Drive Auth Info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceos-seo/odc-colab/a5f20c1e18e2be33efe9150cb65f814acba96d70/images/Google Drive Auth Info.png -------------------------------------------------------------------------------- /notebooks/02.14.03.Colab_LandCover_MODIS_500m.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\"Open" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# MODIS Landcover\n", 15 | "This notebook uses the MODIS (500-meter) land cover product over the period of 2001 to 2020. The output shows a land classification (17 classes) map for any selected year. This data can be found in the Google Earth Engine database as \"MCD12Q1.006 MODIS Land Cover Type Yearly Global 500m\". " 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "## Instructions for Execution\n", 23 | "\n", 24 | "It is suggested that users first execute the notebook \"as is\" to successfully complete the Google authorizations and view sample results. Then, users should look for the \"MODIFY HERE\" labels to modify the region of interest and the analysis year.\n", 25 | "\n", 26 | "Once the full notebook has been run, users can run individual code blocks using \"Shift-Return\" or run segments of the code using the Runtime menu. Users do not have to go thru the Google authorization steps for additional execution cycles. " 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "!wget -nc https://raw.githubusercontent.com/ceos-seo/odc-colab/master/odc_colab.py\n", 36 | "from odc_colab import odc_colab_init\n", 37 | "odc_colab_init(install_odc_gee=True)" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "from odc_colab import populate_db\n", 47 | "populate_db()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "## Load the Data Cube Configuration and Import Utilities" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 1, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "# Ignore warnings \n", 64 | "import warnings\n", 65 | "warnings.simplefilter('ignore')\n", 66 | "\n", 67 | "# Load Data Cube Configuration\n", 68 | "import datacube\n", 69 | "from odc_gee import earthengine\n", 70 | "dc = earthengine.Datacube(app='MODIS_Landcover')\n", 71 | "\n", 72 | "# Import Utilities\n", 73 | "from utils.data_cube_utilities.dc_display_map import display_map\n", 74 | "from matplotlib.colors import ListedColormap, BoundaryNorm\n", 75 | "import numpy as np\n", 76 | "import pandas as pd\n", 77 | "import matplotlib.pyplot as plt" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "## Define the Extents of the Analysis and View\n", 85 | "Select the center of an analysis region (lat_long) below. The size of the region (in degrees) that surrounds this center point is defined using the \"box_size_deg\" parameter. Users can select one of the sample regions or add a new region. Use the map below to zoom in-or-out to find other regions. Click on the map to view a Lat-Lon position. " 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 2, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "# MODIFY HERE\n", 95 | "\n", 96 | "# Select a Latitude-Longitude point for the center of the analysis region\n", 97 | "# Select the size of the box (in degrees) surrounding the center point\n", 98 | "\n", 99 | "# Kumasi, Ghana \n", 100 | "lat_long = (6.7, -1.6)\n", 101 | "box_size_deg = 0.50\n", 102 | "\n", 103 | "# Calculates the latitude and longitude bounds of the analysis box\n", 104 | "latitude = (lat_long[0]-box_size_deg/2, lat_long[0]+box_size_deg/2)\n", 105 | "longitude = (lat_long[1]-box_size_deg/2, lat_long[1]+box_size_deg/2)" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": 3, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "# Define the time range of the dataset\n", 115 | "time_range = ('2001', '2020')" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 4, 121 | "metadata": { 122 | "scrolled": false 123 | }, 124 | "outputs": [ 125 | { 126 | "data": { 127 | "text/html": [ 128 | "
Make this Notebook Trusted to load map: File -> Trust Notebook
" 129 | ], 130 | "text/plain": [ 131 | "" 132 | ] 133 | }, 134 | "execution_count": 4, 135 | "metadata": {}, 136 | "output_type": "execute_result" 137 | } 138 | ], 139 | "source": [ 140 | "# The code below renders a map that can be used to view the region.\n", 141 | "display_map(latitude,longitude)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "## Load the Dataset\n", 149 | "Since the data uses a sinusoidal grid projection, we will convert to a common WGS84 UTM grid projection." 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 5, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "dataset = dc.load(product='modis_landcover_google',\n", 159 | " time=time_range,measurements=['lc_type1'],\n", 160 | " latitude=latitude, \n", 161 | " longitude=longitude,\n", 162 | " output_crs='PROJCS[\"MODIS Sinusoidal\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],PROJECTION[\"Sinusoidal\"],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],PARAMETER[\"longitude_of_center\",0],PARAMETER[\"semi_major\",6371007.181],PARAMETER[\"semi_minor\",6371007.181],UNIT[\"m\",1],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],AUTHORITY[\"SR-ORG\",\"6974\"]]',\n", 163 | " resolution=(-463.312716527000021, 463.312716528000010))" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 6, 169 | "metadata": {}, 170 | "outputs": [ 171 | { 172 | "data": { 173 | "text/html": [ 174 | "
\n", 175 | "\n", 176 | "\n", 177 | "\n", 178 | "\n", 179 | "\n", 180 | "\n", 181 | "\n", 182 | "\n", 183 | "\n", 184 | "\n", 185 | "\n", 186 | "\n", 187 | "\n", 188 | "\n", 189 | "
<xarray.Dataset>\n",
 526 |        "Dimensions:      (time: 20, x: 120, y: 120)\n",
 527 |        "Coordinates:\n",
 528 |        "  * time         (time) datetime64[ns] 2001-01-01 2002-01-01 ... 2020-01-01\n",
 529 |        "  * y            (y) float64 7.684e+05 7.679e+05 ... 7.137e+05 7.133e+05\n",
 530 |        "  * x            (x) float64 -2.046e+05 -2.041e+05 ... -1.499e+05 -1.494e+05\n",
 531 |        "    spatial_ref  int32 0\n",
 532 |        "Data variables:\n",
 533 |        "    lc_type1     (time, y, x) uint8 9 9 9 9 9 9 9 9 9 9 ... 2 2 8 8 2 2 8 8 8 8\n",
 534 |        "Attributes:\n",
 535 |        "    crs:           PROJCS["MODIS Sinusoidal",GEOGCS["WGS 84",DATUM["WGS_1984"...\n",
 536 |        "    grid_mapping:  spatial_ref
" 645 | ], 646 | "text/plain": [ 647 | "\n", 648 | "Dimensions: (time: 20, x: 120, y: 120)\n", 649 | "Coordinates:\n", 650 | " * time (time) datetime64[ns] 2001-01-01 2002-01-01 ... 2020-01-01\n", 651 | " * y (y) float64 7.684e+05 7.679e+05 ... 7.137e+05 7.133e+05\n", 652 | " * x (x) float64 -2.046e+05 -2.041e+05 ... -1.499e+05 -1.494e+05\n", 653 | " spatial_ref int32 0\n", 654 | "Data variables:\n", 655 | " lc_type1 (time, y, x) uint8 9 9 9 9 9 9 9 9 9 9 ... 2 2 8 8 2 2 8 8 8 8\n", 656 | "Attributes:\n", 657 | " crs: PROJCS[\"MODIS Sinusoidal\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\"...\n", 658 | " grid_mapping: spatial_ref" 659 | ] 660 | }, 661 | "execution_count": 6, 662 | "metadata": {}, 663 | "output_type": "execute_result" 664 | } 665 | ], 666 | "source": [ 667 | "# Show the dimensions of the dataset\n", 668 | "# The latitude and longitude bounds are in pixels\n", 669 | "# The time index is in years \n", 670 | "# The \"data variables\" data are the classifications\n", 671 | "dataset" 672 | ] 673 | }, 674 | { 675 | "cell_type": "code", 676 | "execution_count": 7, 677 | "metadata": {}, 678 | "outputs": [ 679 | { 680 | "data": { 681 | "text/html": [ 682 | "
\n", 683 | "\n", 696 | "\n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | " \n", 739 | " \n", 740 | " \n", 741 | " \n", 742 | " \n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | "
Year
02001
12002
22003
32004
42005
52006
62007
72008
82009
92010
102011
112012
122013
132014
142015
152016
162017
172018
182019
192020
\n", 786 | "
" 787 | ], 788 | "text/plain": [ 789 | " Year\n", 790 | "0 2001\n", 791 | "1 2002\n", 792 | "2 2003\n", 793 | "3 2004\n", 794 | "4 2005\n", 795 | "5 2006\n", 796 | "6 2007\n", 797 | "7 2008\n", 798 | "8 2009\n", 799 | "9 2010\n", 800 | "10 2011\n", 801 | "11 2012\n", 802 | "12 2013\n", 803 | "13 2014\n", 804 | "14 2015\n", 805 | "15 2016\n", 806 | "16 2017\n", 807 | "17 2018\n", 808 | "18 2019\n", 809 | "19 2020" 810 | ] 811 | }, 812 | "execution_count": 7, 813 | "metadata": {}, 814 | "output_type": "execute_result" 815 | } 816 | ], 817 | "source": [ 818 | "# Show data layer indices and corresponding years\n", 819 | "# These indices will be used later to view the classification data\n", 820 | "pd.DataFrame(list(dataset.time.values.astype('datetime64[Y]').astype(int)+1970),columns=['Year'])" 821 | ] 822 | }, 823 | { 824 | "cell_type": "markdown", 825 | "metadata": {}, 826 | "source": [ 827 | "### Create classification labels\n", 828 | "The product comes with `flags_definition` metadata." 829 | ] 830 | }, 831 | { 832 | "cell_type": "code", 833 | "execution_count": 8, 834 | "metadata": {}, 835 | "outputs": [], 836 | "source": [ 837 | "stac_metadata = dc.get_stac_metadata('MODIS/006/MCD12Q1')\n", 838 | "\n", 839 | "flags = {0: 'nodata'}\n", 840 | "flags.update({int(list(val['values'].keys())[1]): key\\\n", 841 | " for key, val in dataset['lc_type1'].flags_definition.items()})\n", 842 | "\n", 843 | "labels = {0: dict(color='#000000', flag=flags[0])}\n", 844 | "labels.update({_class['value']: dict(color=f'#{_class[\"color\"]}',\n", 845 | " flag=flags[_class['value']])\\\n", 846 | " for _class in stac_metadata['summaries']['eo:bands'][0]['gee:classes']})\n", 847 | "colors = [label['color'] for label in labels.values()]" 848 | ] 849 | }, 850 | { 851 | "cell_type": "markdown", 852 | "metadata": {}, 853 | "source": [ 854 | "### Create color map\n", 855 | "Create the cmap from colors/labels and offset ticks to center everything." 856 | ] 857 | }, 858 | { 859 | "cell_type": "code", 860 | "execution_count": 9, 861 | "metadata": {}, 862 | "outputs": [], 863 | "source": [ 864 | "cmap = ListedColormap([label['color'] for label in labels.values()])\n", 865 | "norm = BoundaryNorm(list(labels.keys())+[18], cmap.N+1, extend='max')\n", 866 | "ticks = list(np.mean((list(list(labels.keys())+[18])[i+1], val)) for i, val in enumerate(list(labels.keys())))" 867 | ] 868 | }, 869 | { 870 | "cell_type": "markdown", 871 | "metadata": {}, 872 | "source": [ 873 | "### Plot the classification data" 874 | ] 875 | }, 876 | { 877 | "cell_type": "code", 878 | "execution_count": 10, 879 | "metadata": {}, 880 | "outputs": [], 881 | "source": [ 882 | "# MODIFY HERE\n", 883 | "\n", 884 | "# Choose a single year by its index (listed above)\n", 885 | "year_to_show = 19" 886 | ] 887 | }, 888 | { 889 | "cell_type": "code", 890 | "execution_count": 11, 891 | "metadata": {}, 892 | "outputs": [ 893 | { 894 | "data": { 895 | "image/png": "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", 896 | "text/plain": [ 897 | "
" 898 | ] 899 | }, 900 | "metadata": { 901 | "needs_background": "light" 902 | }, 903 | "output_type": "display_data" 904 | } 905 | ], 906 | "source": [ 907 | "aspect = dataset.dims['x']/dataset.dims['y']\n", 908 | "fig = dataset['lc_type1'].isel(time=year_to_show).plot.imshow(cmap=cmap, size=8, norm=norm,\n", 909 | " cbar_kwargs=dict(ticks=ticks),aspect=aspect)\n", 910 | "\n", 911 | "cbar = fig.colorbar\n", 912 | "cbar.ax.set_yticklabels(labels=[label['flag'] for label in labels.values()])\n", 913 | "plt.title('MODIS 500-meter Land Classification')\n", 914 | "plt.xlabel(\"X (meter)\")\n", 915 | "plt.ylabel(\"Y (meter)\")\n", 916 | "plt.show()" 917 | ] 918 | }, 919 | { 920 | "cell_type": "markdown", 921 | "metadata": {}, 922 | "source": [ 923 | "### Statistics" 924 | ] 925 | }, 926 | { 927 | "cell_type": "code", 928 | "execution_count": 12, 929 | "metadata": { 930 | "scrolled": false 931 | }, 932 | "outputs": [ 933 | { 934 | "name": "stdout", 935 | "output_type": "stream", 936 | "text": [ 937 | "\u001b[1;4mTotal number of pixels for each classification.\u001b[0m\n", 938 | "nodata: 0\n", 939 | "evergreen_needleleaf_forests: 0\n", 940 | "evergreen_broadleaf_forests: 82\n", 941 | "deciduous_needleleaf_forests: 0\n", 942 | "deciduous_broadleaf_forests: 0\n", 943 | "mixed_forests: 0\n", 944 | "closed_shrublands: 0\n", 945 | "open_shrublands: 0\n", 946 | "woody_savannas: 802\n", 947 | "savannas: 7074\n", 948 | "grasslands: 153\n", 949 | "permanent_wetlands: 14\n", 950 | "croplands: 28\n", 951 | "urban_and_built_up_lands: 1705\n", 952 | "croplandornatural_vegetation_mosaics: 4327\n", 953 | "permanent_snow_and_ice: 0\n", 954 | "barren: 0\n", 955 | "water_bodies: 215\n", 956 | "\n", 957 | "\u001b[1;4mPercent of total pixel area.\u001b[0m\n", 958 | "nodata: 0.0%\n", 959 | "evergreen_needleleaf_forests: 0.0%\n", 960 | "evergreen_broadleaf_forests: 0.57%\n", 961 | "deciduous_needleleaf_forests: 0.0%\n", 962 | "deciduous_broadleaf_forests: 0.0%\n", 963 | "mixed_forests: 0.0%\n", 964 | "closed_shrublands: 0.0%\n", 965 | "open_shrublands: 0.0%\n", 966 | "woody_savannas: 5.57%\n", 967 | "savannas: 49.12%\n", 968 | "grasslands: 1.06%\n", 969 | "permanent_wetlands: 0.1%\n", 970 | "croplands: 0.19%\n", 971 | "urban_and_built_up_lands: 11.84%\n", 972 | "croplandornatural_vegetation_mosaics: 30.05%\n", 973 | "permanent_snow_and_ice: 0.0%\n", 974 | "barren: 0.0%\n", 975 | "water_bodies: 1.49%\n" 976 | ] 977 | } 978 | ], 979 | "source": [ 980 | "print('\\033[1;4mTotal number of pixels for each classification.\\033[0m')\n", 981 | "for val, label in labels.items():\n", 982 | " print(f'{label[\"flag\"]}: {np.sum(dataset.lc_type1.isel(time=0).values == val)}')\n", 983 | " \n", 984 | "print('\\n\\033[1;4mPercent of total pixel area.\\033[0m')\n", 985 | "for val, label in labels.items():\n", 986 | " area = np.sum(dataset.lc_type1.isel(time=0).values == val)\\\n", 987 | " /dataset.lc_type1.isel(time=0).size * 100\n", 988 | " print(f'{label[\"flag\"]}: {round(area, 2)}%')" 989 | ] 990 | } 991 | ], 992 | "metadata": { 993 | "kernelspec": { 994 | "display_name": "Python 3", 995 | "language": "python", 996 | "name": "python3" 997 | }, 998 | "language_info": { 999 | "codemirror_mode": { 1000 | "name": "ipython", 1001 | "version": 3 1002 | }, 1003 | "file_extension": ".py", 1004 | "mimetype": "text/x-python", 1005 | "name": "python", 1006 | "nbconvert_exporter": "python", 1007 | "pygments_lexer": "ipython3", 1008 | "version": "3.6.13" 1009 | }, 1010 | "widgets": { 1011 | "application/vnd.jupyter.widget-state+json": { 1012 | "state": {}, 1013 | "version_major": 2, 1014 | "version_minor": 0 1015 | } 1016 | } 1017 | }, 1018 | "nbformat": 4, 1019 | "nbformat_minor": 4 1020 | } 1021 | -------------------------------------------------------------------------------- /odc_colab.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=broad-except,unused-argument,import-outside-toplevel,too-many-arguments,too-many-branches 2 | ''' Tools for setting up ODC in a Colab environment. ''' 3 | import pwd 4 | import sys 5 | from os import environ, getuid, listdir, remove 6 | import subprocess 7 | import warnings 8 | 9 | assert 'google.colab' in sys.modules, 'Not in a Google Colab environment.' 10 | assert pwd.getpwuid(getuid()).pw_name == 'root', 'Not running as root.' 11 | 12 | 13 | def build_datacube_db_url(hostname, username, password=None, dbname='datacube', port=5432): 14 | ''' Build a PostgreSQL URL for connecting to a networked ODC database. 15 | 16 | Args: 17 | hostname (str): The hostname of the target database. 18 | username (str): The username of the target database. 19 | password (str): Optional; the password for the connecting username. 20 | dbname (str): Optional; the database name to connect to. 21 | port (int): Optional; the port to connect to. 22 | 23 | Returns the URL string. 24 | ''' 25 | return (f'postgresql://{username}{":"+password if password is not None else ""}' 26 | f'@{hostname}:{port}/{dbname}') 27 | 28 | def _shell_cmd(cmd): 29 | ''' Executes a list of shell arguments. 30 | 31 | Args: 32 | cmd (list): A list of arguments being supplied to the shell. 33 | 34 | Returns the output of the command. 35 | ''' 36 | return subprocess.check_output( 37 | cmd, 38 | stderr=subprocess.STDOUT, 39 | universal_newlines=True, # Python 3.7 would prefer text=True 40 | ) 41 | 42 | def _pip_install(module, *args, verbose=False): 43 | ''' Installs a Python module using pip. 44 | 45 | Args: 46 | module (str): The name of the module to install. 47 | verbose (bool): Optional; flag to set verbosity for install. 48 | 49 | Returns the result of the pip command. 50 | ''' 51 | return _shell_cmd([sys.executable, "-m", "pip", "install"]+list(args)+[module]) 52 | 53 | def _apt_install(package, verbose=False): 54 | ''' Install a system package using apt-get. 55 | 56 | Args: 57 | package (str): The package name to install. 58 | verbose (bool): Optional; flag to set verbosity for install. 59 | 60 | Returns the result of the apt-get command. 61 | ''' 62 | try: 63 | _shell_cmd(["apt-get", "update"]) 64 | except subprocess.CalledProcessError: 65 | warnings.warn(message=f'Unable to complete `apt-get update` before installing "{package}". Attempting to install anyway.', stacklevel=2) 66 | return _shell_cmd(["apt-get", "install", package]) 67 | 68 | def _git_install(url, module_name=None, verbose=False): 69 | ''' Checks if a git module exists. 70 | 71 | Args: 72 | url (str): The URL location of the git module. 73 | module_name (str): Optional; the name of the module. 74 | verbose (bool): Optional; flag to set verbosity for install. 75 | 76 | Returns the result of installing the git module. 77 | ''' 78 | cmd = ["git", "clone", url] 79 | if module_name: 80 | cmd.append(module_name) 81 | return _shell_cmd(cmd) 82 | 83 | def _module_found(module): 84 | ''' Checks if module is loadable. 85 | 86 | Args: 87 | module (str): The module name to check. 88 | ''' 89 | if module in sys.modules: 90 | return True # Already loaded 91 | import importlib 92 | spam_spec = importlib.util.find_spec(module) 93 | return spam_spec is not None 94 | 95 | def _package_found(package): 96 | ''' Checks if package is installed. 97 | 98 | Args: 99 | package (str): The package name to check. 100 | ''' 101 | try: 102 | return bool(_shell_cmd(["dpkg", "-l"]).count(package)) 103 | except Exception as error: 104 | warnings.warn(message=f'Unable to check dpkg for "{package}" package. Assuming it is not present.', stacklevel=2) 105 | return False 106 | 107 | def _check_pip_install(module, *args, verbose=False): 108 | ''' Installs a Python package if it is not found. 109 | 110 | Args: 111 | module (str): The name of the module to check. 112 | verbose (bool): Optional; flag to set verbosity for install. 113 | ''' 114 | if _module_found(module): 115 | if verbose: 116 | print(f'Found {module} module, skipping install.') 117 | else: 118 | print(f'Module {module} was not found; installing it...') 119 | shell_result = _pip_install(module, *args) 120 | if verbose: 121 | print(shell_result) 122 | 123 | def _check_apt_install(package, verbose=False): 124 | ''' Installs a system package if it is not found. 125 | 126 | Args: 127 | package (str): The name of the package to check. 128 | verbose (bool): Optional; flag to set verbosity for install. 129 | ''' 130 | if _package_found(package): 131 | if verbose: 132 | print(f'Found {package} package, skipping install.') 133 | else: 134 | print(f'Package {package} was not found; installing it...') 135 | shell_result = _apt_install(package) 136 | if verbose: 137 | print(shell_result) 138 | 139 | def _check_git_install(module, url, verbose=False): 140 | ''' Installs a git module if it is not found. 141 | 142 | Args: 143 | module (str): The name of the git module. 144 | url (str): The git URL of module. 145 | verbose (bool): Optional; flag to set verbosity for install. 146 | ''' 147 | if _module_found(module): 148 | if verbose: 149 | print(f'Found {module} module, skipping install.') 150 | else: 151 | print(f'Module {module} was not found; cloning {url} to CWD...') 152 | shell_result = _git_install(url, module_name=module) 153 | if verbose: 154 | print(shell_result) 155 | 156 | def _dc_config_present(use_defaults): 157 | ''' Checks if the datacube configuration exists. 158 | 159 | Args: 160 | use_defaults (bool): A flag to use a default local database configuration or not. 161 | 162 | Returns: 163 | False if the configuration does not exist. 164 | True if the configuration does exist. 165 | ''' 166 | # See https://opendatacube.readthedocs.io/en/latest/ops/config.html 167 | from os import path 168 | if use_defaults: 169 | datacube_conf = (""" 170 | [default] 171 | db_database: datacube 172 | 173 | # A blank host will use a local socket. Specify a hostname (such as localhost) to use TCP. 174 | db_hostname: 175 | """).lstrip().rstrip() 176 | with open('./datacube.conf', 'w') as _file: 177 | _file.write(datacube_conf) 178 | return True 179 | if 'DATACUBE_DB_URL' in environ: 180 | return True 181 | if 'DATACUBE_CONFIG_PATH' in environ: 182 | if path.exists(environ['DATACUBE_CONFIG_PATH']): 183 | return True 184 | if (path.exists('/etc/datacube.conf') or 185 | path.exists('~/.datacube.conf') or 186 | path.exists('datacube.conf')): 187 | return True 188 | return False 189 | 190 | def _psql_running(): 191 | ''' Checks if a PostgreSQL configuration is present. 192 | 193 | Returns: 194 | False if the configuration does not exist. 195 | True if the configuration does exist. 196 | ''' 197 | from os import path 198 | if path.exists('/var/run/postgresql/10-main.pid'): 199 | return True 200 | return False 201 | 202 | def odc_colab_init( 203 | verbose=False, 204 | install_datacube=True, 205 | install_ceos_utils=True, 206 | install_postgresql=True, 207 | install_odc_gee=False, 208 | use_defaults=True, 209 | **kwargs 210 | ): 211 | ''' 212 | Configures Colab environment for Open Data Cube 213 | 214 | This function sets several environment variables and 215 | installs the datacube module and the CEOS datacube_utiltities 216 | module if necessary. Additional enviroment variables 217 | can be passed as kwargs. They are set before installing 218 | modules, in case anything specific to the install is needed. 219 | 220 | The ODC DB Credentials can be provided by either setting 221 | DATACUBE_CONFIG_PATH to point to a configuration file, or 222 | DATACUBE_DB_URL with the connection information in the format 223 | postgresql://user:password@host:port/database 224 | 225 | build_datacube_db_url is provided to help create connection string. 226 | 227 | NOTE: This function will install CEOS utils to the CURRENT 228 | WORKING DIRECTORY if it can't load the module. If using a 229 | notebook which changes system path before importing modules, 230 | the path should be changed (or the module imported) BEFORE 231 | calling this function, lest it install a duplicate copy. 232 | If this happens by mistake, the directory can simply be deleted. 233 | 234 | Args: 235 | verbose (bool): Optional; flag to set verbosity for install. 236 | install_datacube (bool): Optional; flag to install an ODC environment. 237 | install_ceos_utils (bool): Optional; flag to install CEOS ODC utilities. 238 | install_postgresql (bool): Optional; flag to install postgresql. 239 | install_odc_gee (bool): Optional; flag to install CEOS ODC-GEE tools. 240 | use_defaults (bool): Optional; 241 | flag to install environment with default local database configuration. 242 | install_odc_gee (bool): Optional; install the CEOS ODC-GEE toolset. 243 | ''' 244 | # Set environment variables 245 | env = { 246 | # default values here (may be overridden by user input) 247 | 'AWS_NO_SIGN_REQUEST': 'YES', 248 | 'CURL_CA_BUNDLE': '/etc/ssl/certs/ca-certificates.crt', 249 | } 250 | # If user supplied DATACUBE_CONFIG_PATH, we don't want to set DATACUBE_DB_URL 251 | if 'DATACUBE_CONFIG_PATH' in kwargs: 252 | del env['DATACUBE_DB_URL'] 253 | env.update(kwargs) # Merge default and user-supplied vars 254 | if len(env) > 0: 255 | if verbose: 256 | print('Setting environment variables:') 257 | for key, var in env.items(): 258 | if verbose: 259 | print(f'\t{key}={var}') 260 | environ[key] = var 261 | 262 | if not _dc_config_present(use_defaults): 263 | # Python version on Colab has buffer issue with warnings, causing extra junk to leak. 264 | # Just using a print for now. 265 | print("Warning:", end='') 266 | #from warnings import warn 267 | print(""" 268 | There does not appear to be an Open Data Cube environment configured, so 269 | instantiating a Datacube may fail. An environment configuration can be 270 | specified in one of the following ways: 271 | - Pass the DATACUBE_DB_URL arg to this function, with a valid connection 272 | string containing credentials for a (possibly remote) ODC database instance. 273 | This file includes a build_datacube_db_url() function to help generate one. 274 | - Pass the DATACUBE_CONFIG_PATH arg to this function, containing a (string) 275 | path pointing to a valid config file. 276 | - Put a valid config file at any of the default search locations. 277 | More information on ODC environment configuration can be found at: 278 | https://opendatacube.readthedocs.io/en/latest/ops/config.html 279 | """) 280 | # Upgrade pip to do proper dependency resolution 281 | _pip_install('pip', '--upgrade', verbose=verbose) 282 | if install_datacube: 283 | _pip_install('datacube==1.8.3', verbose=verbose) 284 | _pip_install('click==7.1.2', verbose=verbose) 285 | _pip_install('SQLAlchemy==1.4', verbose=verbose) 286 | 287 | if install_ceos_utils: 288 | _check_git_install('utils', 289 | 'https://github.com/ceos-seo/data_cube_utilities.git', 290 | verbose=verbose) 291 | _pip_install('xarray==2022.3.0', '--upgrade', verbose=verbose) 292 | _shell_cmd(['mkdir', '-p', '/content/output']) 293 | _shell_cmd(['mkdir', '-p', '/content/geotiffs']) 294 | 295 | if install_postgresql: 296 | _check_apt_install('postgresql', verbose=verbose) 297 | if not _psql_running(): 298 | try: 299 | _shell_cmd(["service", "postgresql", "start"]) 300 | _shell_cmd(["sudo", "-u", "postgres", 301 | "createuser", "-s", "root"]) 302 | if install_datacube: 303 | _shell_cmd(["sudo", "-u", "postgres", 304 | "createdb", "-O", "root", "datacube"]) 305 | #_shell_cmd(["datacube", "system", "init"]) 306 | except Exception as error: 307 | print(error) 308 | 309 | if install_odc_gee: 310 | import site 311 | import os 312 | dist_packages_dirs = site.getsitepackages() 313 | for d in dist_packages_dirs: 314 | if os.path.isdir(f'{d}/datacube'): 315 | dist_packages_dir = d 316 | _check_git_install('odc-gee', 317 | 'https://github.com/ceos-seo/odc-gee.git', 318 | verbose=verbose) 319 | _check_pip_install('odc-gee', '-e', verbose=verbose) 320 | _shell_cmd(["ln", "-sf", "/content/odc-gee/odc_gee", 321 | f"{dist_packages_dir}/odc_gee"]) 322 | _patch_schema(dist_packages_dir) 323 | _shell_cmd(["datacube", "system", "init"]) 324 | 325 | def _patch_schema(dist_packages_dir): 326 | from importlib.util import find_spec 327 | from pathlib import Path 328 | from types import SimpleNamespace 329 | from urllib import request 330 | 331 | # Download file if it doesn't exist 332 | patch_url = 'https://raw.githubusercontent.com/ceos-seo/odc-colab/master/patches/schema.diff' 333 | patch_file = f'./{patch_url.split("/")[-1]}' 334 | dummy_response = SimpleNamespace(code=0) 335 | resp = request.urlopen(patch_url) if not Path(patch_file).exists() else dummy_response 336 | if resp.code in range(200, 300): 337 | with open(patch_file, 'wb') as _file: 338 | _file.write(resp.read()) 339 | 340 | # Patch file if unlocked 341 | if not Path(patch_file).with_suffix('.lock').exists(): 342 | odc_loc = f'{dist_packages_dir}/datacube' 343 | _shell_cmd(["patch", f"{odc_loc}/model/schema/dataset-type-schema.yaml", 344 | patch_file]) 345 | Path(patch_file).with_suffix('.lock').touch() 346 | 347 | def _combine_split_files(path): 348 | from pathlib import Path 349 | part_files = list(filter(lambda f: '.part' in f, listdir(path))) 350 | if part_files: 351 | part_files.sort() 352 | path = Path(path).joinpath(part_files[0].split('.')[0][:-3]) 353 | with open(path, 'wb') as combined_file: 354 | for part_file in part_files: 355 | with open(path.parent.joinpath(part_file), 'rb') as _file: 356 | combined_file.write(_file.read()) 357 | return path 358 | 359 | def _download_db(*args, **kwargs): 360 | from urllib import request 361 | url = 'https://raw.githubusercontent.com/ceos-seo/odc-colab/master/database/db_dump.tar.xz' 362 | print('No database file supplied. Downloading default index.') 363 | resp = request.urlopen(url) 364 | if resp.code < 300: 365 | tar_file = f'./{url.split("/")[-1]}' 366 | with open(tar_file, 'wb') as _file: 367 | _file.write(resp.read()) 368 | return tar_file 369 | 370 | def populate_db(path=None): 371 | ''' Populates the datacube database from a compressed SQL dump. 372 | 373 | Args: 374 | path (str): The path to a tar file to load or a directory of a split tar file. 375 | earthengine (bool): Flag to download Google Earth Engine Landsat 8 index. 376 | 377 | Raises OSError if tar file is not found. 378 | ''' 379 | import tarfile 380 | import tempfile 381 | from pathlib import Path 382 | from shutil import move 383 | 384 | if not path: 385 | path = _download_db() 386 | 387 | path = Path(path).absolute() 388 | if path.exists(): 389 | if not path.with_suffix('').with_suffix('').with_suffix('.lock').exists(): 390 | path.with_suffix('').with_suffix('').with_suffix('.lock').touch() 391 | path = _combine_split_files(path) if path.is_dir() else path 392 | with tarfile.open(str(path), 'r:xz') as tar: 393 | tar.extractall(path=path.parent) 394 | sql_files = list(filter(lambda f: '.sql' in f, 395 | listdir(path.parent))) 396 | for sql_file in sql_files: 397 | with open(path.parent.joinpath(sql_file), 'r') as old_file: 398 | with open(tempfile.mkstemp()[-1], 'w') as new_file: 399 | line = old_file.readline() 400 | while line: 401 | new_file.write(line.replace('$$PATH$$', str(path.parent))) 402 | line = old_file.readline() 403 | remove(old_file.name) 404 | move(new_file.name, old_file.name) 405 | _shell_cmd(["psql", "-f", old_file.name, 406 | "-d", "datacube"]) 407 | cleanup = [remove(_dir) for _dir in listdir('./')\ 408 | if '.dat' in _dir or '.sql' in _dir] 409 | if cleanup: 410 | print('Cleaned up extracted database files.') 411 | else: 412 | print('Lockfile exists, skipping population.') 413 | else: 414 | raise OSError('Tar file does not exist.') 415 | -------------------------------------------------------------------------------- /patches/default.diff: -------------------------------------------------------------------------------- 1 | 2a3,44 2 | > { 3 | > "cell_type": "markdown", 4 | > "metadata": {}, 5 | > "source": [ 6 | > "\" target=\"_parent\">\"Open" 7 | > ] 8 | > }, 9 | > { 10 | > "cell_type": "markdown", 11 | > "metadata": {}, 12 | > "source": [ 13 | > "Downloads the odc-colab Python module and runs it to setup ODC." 14 | > ] 15 | > }, 16 | > { 17 | > "cell_type": "code", 18 | > "execution_count": null, 19 | > "metadata": {}, 20 | > "outputs": [], 21 | > "source": [ 22 | > "!wget -nc https://raw.githubusercontent.com/ceos-seo/odc-colab/master/odc_colab.py\n", 23 | > "from odc_colab import odc_colab_init\n", 24 | > "odc_colab_init()" 25 | > ] 26 | > }, 27 | > { 28 | > "cell_type": "markdown", 29 | > "metadata": {}, 30 | > "source": [ 31 | > "Downloads an existing index and populates the new ODC environment with it." 32 | > ] 33 | > }, 34 | > { 35 | > "cell_type": "code", 36 | > "execution_count": null, 37 | > "metadata": {}, 38 | > "outputs": [], 39 | > "source": [ 40 | > "from odc_colab import populate_db\n", 41 | > "populate_db()" 42 | > ] 43 | > }, 44 | -------------------------------------------------------------------------------- /patches/schema.diff: -------------------------------------------------------------------------------- 1 | @@ -51,7 +51,7 @@ definitions: 2 | properties: 3 | name: 4 | type: string 5 | - pattern: '^\w+$' 6 | + pattern: '^[\w-]+$' 7 | dtype: 8 | "$ref": "#/definitions/dtype" 9 | nodata: 10 | -------------------------------------------------------------------------------- /tests/Automated_Testing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "kernelspec": { 6 | "display_name": "Python 3", 7 | "language": "python", 8 | "name": "python3" 9 | }, 10 | "language_info": { 11 | "codemirror_mode": { 12 | "name": "ipython", 13 | "version": 3 14 | }, 15 | "file_extension": ".py", 16 | "mimetype": "text/x-python", 17 | "name": "python", 18 | "nbconvert_exporter": "python", 19 | "pygments_lexer": "ipython3", 20 | "version": "3.6.9" 21 | }, 22 | "colab": { 23 | "name": "Automated_Testing.ipynb", 24 | "provenance": [], 25 | "collapsed_sections": [] 26 | } 27 | }, 28 | "cells": [ 29 | { 30 | "cell_type": "code", 31 | "metadata": { 32 | "id": "KvJOCXbfPF_s" 33 | }, 34 | "source": [ 35 | "import ee\n", 36 | "ee.Authenticate()\n", 37 | "ee.Initialize()" 38 | ], 39 | "execution_count": null, 40 | "outputs": [] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "metadata": { 45 | "id": "PN_1_iqgFLQA" 46 | }, 47 | "source": [ 48 | "!wget -nc https://raw.githubusercontent.com/ceos-seo/odc-colab/master/odc_colab.py && git clone https://github.com/ceos-seo/odc-colab\n", 49 | "from odc_colab import odc_colab_init\n", 50 | "odc_colab_init(install_odc_gee=True)" 51 | ], 52 | "execution_count": null, 53 | "outputs": [] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "metadata": { 58 | "id": "fs0n9aYGFSKV" 59 | }, 60 | "source": [ 61 | "from odc_colab import populate_db\n", 62 | "populate_db()" 63 | ], 64 | "execution_count": null, 65 | "outputs": [] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "metadata": { 70 | "id": "C3yFviKrFKNv" 71 | }, 72 | "source": [ 73 | "import nbformat\n", 74 | "from nbconvert.preprocessors import ExecutePreprocessor\n", 75 | "from nbconvert.preprocessors import CellExecutionError\n", 76 | "from nbclient.exceptions import CellControlSignal" 77 | ], 78 | "execution_count": null, 79 | "outputs": [] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": { 84 | "id": "ApC8pCH0FKNx" 85 | }, 86 | "source": [ 87 | "## Get a list of notebooks to run" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "metadata": { 93 | "id": "j4O4YZtoFKNx" 94 | }, 95 | "source": [ 96 | "import sys\n", 97 | "import os\n", 98 | "nb_path = '/content/odc-colab/notebooks/'\n", 99 | "\n", 100 | "excluded_notebooks = {'01.01.Getting_Started_ODC_and_Colab.ipynb'}\n", 101 | "\n", 102 | "def ls_nb(nb_path):\n", 103 | " nb_files = []\n", 104 | " for nb_path, dirs, files in os.walk(nb_path):\n", 105 | " files = set(files).difference(excluded_notebooks)\n", 106 | " nb_files += [os.path.join(nb_path, f) for f in files if '.ipynb' in f]\n", 107 | " return sorted(nb_files)" 108 | ], 109 | "execution_count": null, 110 | "outputs": [] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "metadata": { 115 | "id": "ONta3TP1IvL6" 116 | }, 117 | "source": [ 118 | "notebook_file_paths = ls_nb(nb_path)" 119 | ], 120 | "execution_count": null, 121 | "outputs": [] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": { 126 | "id": "A4vpHj21FKNy" 127 | }, 128 | "source": [ 129 | "## Run the notebooks and record their status (e.g. working, error) to HTML as each completes" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "metadata": { 135 | "id": "hIwEARQOFKNy" 136 | }, 137 | "source": [ 138 | "import re\n", 139 | "import pandas\n", 140 | "ansi_escape = re.compile(r'\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])')\n", 141 | "full_report = pandas.DataFrame(columns=['Notebook', 'Status', 'Bug Description'])\n", 142 | "error_report = pandas.DataFrame(columns=['Notebook', 'Status', 'Bug Description'])\n", 143 | "success_report = pandas.DataFrame(columns=['Notebook', 'Status', 'Bug Description'])\n", 144 | "# Unless this cell is rerun, only run notebooks that have not been run successfully yet.\n", 145 | "success_notebooks = []" 146 | ], 147 | "execution_count": null, 148 | "outputs": [] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "id": "2ZfZrKRNFKNy" 154 | }, 155 | "source": [ 156 | "**To rerun all notebooks, the file `success_nbks_file_name` must be deleted and then this notebook must be restarted**" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "metadata": { 162 | "scrolled": true, 163 | "id": "oV0mBkWaFKNz", 164 | "colab": { 165 | "base_uri": "https://localhost:8080/" 166 | }, 167 | "outputId": "d606ed8f-6240-4f82-f714-c9dc75685970" 168 | }, 169 | "source": [ 170 | "import pickle\n", 171 | "\n", 172 | "# Load the list of successful notebooks.\n", 173 | "success_nbks_file_name = 'success_nbks.pkl'\n", 174 | "if os.path.exists(success_nbks_file_name):\n", 175 | " success_nbks_file_in = open(success_nbks_file_name, 'rb')\n", 176 | " success_notebooks = pickle.load(success_nbks_file_in)\n", 177 | "\n", 178 | "notebook_file_paths_to_run = [nbk_pth for nbk_pth in notebook_file_paths if nbk_pth not in success_notebooks]\n", 179 | "for notebook_file_path in notebook_file_paths_to_run:\n", 180 | " print(f'Running {notebook_file_path}')\n", 181 | " run_result = {'Notebook': notebook_file_path, 'Status': 'Working', 'Bug Description': ''}\n", 182 | " with open(notebook_file_path, 'r+', encoding='utf-8') as notebook_file:\n", 183 | " notebook = nbformat.read(notebook_file, as_version=4)\n", 184 | " notebook_runner = ExecutePreprocessor(timeout=None)\n", 185 | " try:\n", 186 | " notebook_runner.preprocess(notebook, {'metadata': {'path': '/content'}})\n", 187 | " except CellExecutionError as err:\n", 188 | " run_result['Status'] = 'Error'\n", 189 | " run_result['Bug Description'] = err\n", 190 | " error = run_result['Status'] == 'Error'\n", 191 | " # Save the notebook.\n", 192 | "# nbformat.write(notebook, notebook_file_path)\n", 193 | " full_report = full_report.append(run_result, ignore_index=True)\n", 194 | " if error:\n", 195 | " error_report = error_report.append(run_result, ignore_index=True)\n", 196 | " else:\n", 197 | " # Record that this notebook ran successfully to avoid running it again for this testing session.\n", 198 | " success_notebooks.append(notebook_file_path)\n", 199 | " success_report = success_report.append(run_result, ignore_index=True)\n", 200 | " success_nbks_file_out = open(success_nbks_file_name, 'wb') \n", 201 | " pickle.dump(success_notebooks, success_nbks_file_out)\n", 202 | " full_report.to_html('full_test_report.html', escape=False, formatters={'Bug Description': lambda e: ansi_escape.sub('', str(e).replace('\\n', '
'))})\n", 203 | " error_report.to_html('error_report.html', escape=False, formatters={'Bug Description': lambda e: ansi_escape.sub('', str(e).replace('\\n', '
'))})\n", 204 | " success_report.to_html('success_report.html', escape=False, formatters={'Bug Description': lambda e: ansi_escape.sub('', str(e).replace('\\n', '
'))})" 205 | ], 206 | "execution_count": null, 207 | "outputs": [ 208 | { 209 | "output_type": "stream", 210 | "name": "stdout", 211 | "text": [ 212 | "Running /content/odc-colab/notebooks/02.01.Colab_Cloud_Statistics_L8.ipynb\n", 213 | "Running /content/odc-colab/notebooks/02.02.Colab_Cloud_Statistics_S2.ipynb\n", 214 | "Running /content/odc-colab/notebooks/02.03.Colab_Median_Mosaic_L8.ipynb\n", 215 | "Running /content/odc-colab/notebooks/02.04.Colab_Water_WOFS_L8.ipynb\n", 216 | "Running /content/odc-colab/notebooks/02.05.Colab_Spectral_Products_L8.ipynb\n", 217 | "Running /content/odc-colab/notebooks/02.06.Colab_Vegetation_Change_L8.ipynb\n", 218 | "Running /content/odc-colab/notebooks/02.07.Colab_Vegetation_Phenology_L8.ipynb\n", 219 | "Running /content/odc-colab/notebooks/02.08.01.Colab_S1_Data_Viewer.ipynb\n", 220 | "Running /content/odc-colab/notebooks/02.08.02.Colab_S1_Flooding.ipynb\n", 221 | "Running /content/odc-colab/notebooks/02.09.Colab_Mission_Coincidences.ipynb\n", 222 | "Running /content/odc-colab/notebooks/02.10.Colab_VIIRS_Night_Lights.ipynb\n" 223 | ] 224 | } 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": { 230 | "id": "2aS_a5BOFKN0" 231 | }, 232 | "source": [ 233 | "### Export the results to a CSV" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "metadata": { 239 | "id": "4urWYxHTFKN1" 240 | }, 241 | "source": [ 242 | "full_report['Bug Description'] = full_report['Bug Description'].map(lambda e: ansi_escape.sub('', str(e)))\n", 243 | "full_report.to_csv('full_test_report.csv')\n", 244 | "error_report['Bug Description'] = error_report['Bug Description'].map(lambda e: ansi_escape.sub('', str(e)))\n", 245 | "error_report.to_csv('error_report.csv')\n", 246 | "success_report['Bug Description'] = success_report['Bug Description'].map(lambda e: ansi_escape.sub('', str(e)))\n", 247 | "success_report.to_csv('success_report_report.csv')" 248 | ], 249 | "execution_count": null, 250 | "outputs": [] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": { 255 | "id": "e3ouDjMRixmE" 256 | }, 257 | "source": [ 258 | "# Display Results" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "metadata": { 264 | "id": "YpyflHQ5ajm0" 265 | }, 266 | "source": [ 267 | "from IPython.display import HTML\n", 268 | "with open('./full_test_report.html', 'r') as report:\n", 269 | " report = report.read()" 270 | ], 271 | "execution_count": null, 272 | "outputs": [] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "metadata": { 277 | "id": "wbO_8_0wa1O5", 278 | "colab": { 279 | "base_uri": "https://localhost:8080/", 280 | "height": 377 281 | }, 282 | "outputId": "f0890b49-2414-4313-8fbf-94075bdad74c" 283 | }, 284 | "source": [ 285 | "HTML(report)" 286 | ], 287 | "execution_count": null, 288 | "outputs": [ 289 | { 290 | "output_type": "execute_result", 291 | "data": { 292 | "text/html": [ 293 | "\n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | "
NotebookStatusBug Description
0/content/odc-colab/notebooks/02.01.Colab_Cloud_Statistics_L8.ipynbWorking
1/content/odc-colab/notebooks/02.02.Colab_Cloud_Statistics_S2.ipynbWorking
2/content/odc-colab/notebooks/02.03.Colab_Median_Mosaic_L8.ipynbWorking
3/content/odc-colab/notebooks/02.04.Colab_Water_WOFS_L8.ipynbWorking
4/content/odc-colab/notebooks/02.05.Colab_Spectral_Products_L8.ipynbWorking
5/content/odc-colab/notebooks/02.06.Colab_Vegetation_Change_L8.ipynbWorking
6/content/odc-colab/notebooks/02.07.Colab_Vegetation_Phenology_L8.ipynbWorking
7/content/odc-colab/notebooks/02.08.01.Colab_S1_Data_Viewer.ipynbWorking
8/content/odc-colab/notebooks/02.08.02.Colab_S1_Flooding.ipynbWorking
9/content/odc-colab/notebooks/02.09.Colab_Mission_Coincidences.ipynbWorking
10/content/odc-colab/notebooks/02.10.Colab_VIIRS_Night_Lights.ipynbWorking
" 371 | ], 372 | "text/plain": [ 373 | "" 374 | ] 375 | }, 376 | "metadata": {}, 377 | "execution_count": 11 378 | } 379 | ] 380 | } 381 | ] 382 | } --------------------------------------------------------------------------------