├── .editorconfig ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── docs ├── Makefile ├── authors.rst ├── conf.py ├── contributing.rst ├── history.rst ├── index.rst ├── installation.rst ├── make.bat ├── readme.rst └── usage.rst ├── examples ├── geehydro-tutorials.ipynb ├── landsat_wrs2_grid.ipynb ├── landsat_wrs2_grid.py ├── naip.ipynb ├── template.ipynb └── template.nbconvert.ipynb ├── geehydro ├── __init__.py ├── add_layer.py ├── basemaps.py ├── cli.py ├── geehydro.py └── utilities.py ├── requirements.txt ├── requirements_dev.txt ├── setup.cfg ├── setup.py ├── tests ├── __init__.py └── test_geehydro.py └── tox.ini /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * geehydro version: 2 | * Python version: 3 | * Operating System: 4 | 5 | ### Description 6 | 7 | Describe what you were trying to get done. 8 | Tell us what happened, what went wrong, and what you expected to happen. 9 | 10 | ### What I Did 11 | 12 | ``` 13 | Paste the command(s) you ran and the output. 14 | If there was a crash, please include the traceback here. 15 | ``` 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Config file for automatic testing at travis-ci.org 2 | 3 | language: python 4 | python: 5 | - 3.8 6 | - 3.7 7 | - 3.6 8 | - 3.5 9 | 10 | # Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors 11 | install: pip install -U tox-travis 12 | 13 | # Command to run tests, e.g. python setup.py test 14 | script: tox 15 | 16 | # Assuming you have installed the travis-ci CLI tool, after you 17 | # create the Github repo and add it to Travis, run the 18 | # following command to finish PyPI deployment setup: 19 | # $ travis encrypt --add deploy.password 20 | deploy: 21 | provider: pypi 22 | distributions: sdist bdist_wheel 23 | user: giswqs 24 | password: 25 | secure: PLEASE_REPLACE_ME 26 | on: 27 | tags: true 28 | repo: giswqs/geehydro 29 | python: 3.8 30 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Current File", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/home/qiusheng/.conda/envs/dl/bin/python", 3 | "python.linting.flake8Enabled": false, 4 | "python.linting.enabled": true, 5 | "python.linting.pylintEnabled": true, 6 | "python.linting.mypyEnabled": false 7 | } -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * Qiusheng Wu 9 | 10 | Contributors 11 | ------------ 12 | 13 | None yet. Why not be the first? 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! Every little bit 8 | helps, and credit will always be given. 9 | 10 | You can contribute in many ways: 11 | 12 | Types of Contributions 13 | ---------------------- 14 | 15 | Report Bugs 16 | ~~~~~~~~~~~ 17 | 18 | Report bugs at https://github.com/giswqs/geehydro/issues. 19 | 20 | If you are reporting a bug, please include: 21 | 22 | * Your operating system name and version. 23 | * Any details about your local setup that might be helpful in troubleshooting. 24 | * Detailed steps to reproduce the bug. 25 | 26 | Fix Bugs 27 | ~~~~~~~~ 28 | 29 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help 30 | wanted" is open to whoever wants to implement it. 31 | 32 | Implement Features 33 | ~~~~~~~~~~~~~~~~~~ 34 | 35 | Look through the GitHub issues for features. Anything tagged with "enhancement" 36 | and "help wanted" is open to whoever wants to implement it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | geehydro could always use more documentation, whether as part of the 42 | official geehydro docs, in docstrings, or even on the web in blog posts, 43 | articles, and such. 44 | 45 | Submit Feedback 46 | ~~~~~~~~~~~~~~~ 47 | 48 | The best way to send feedback is to file an issue at https://github.com/giswqs/geehydro/issues. 49 | 50 | If you are proposing a feature: 51 | 52 | * Explain in detail how it would work. 53 | * Keep the scope as narrow as possible, to make it easier to implement. 54 | * Remember that this is a volunteer-driven project, and that contributions 55 | are welcome :) 56 | 57 | Get Started! 58 | ------------ 59 | 60 | Ready to contribute? Here's how to set up `geehydro` for local development. 61 | 62 | 1. Fork the `geehydro` repo on GitHub. 63 | 2. Clone your fork locally:: 64 | 65 | $ git clone git@github.com:your_name_here/geehydro.git 66 | 67 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 68 | 69 | $ mkvirtualenv geehydro 70 | $ cd geehydro/ 71 | $ python setup.py develop 72 | 73 | 4. Create a branch for local development:: 74 | 75 | $ git checkout -b name-of-your-bugfix-or-feature 76 | 77 | Now you can make your changes locally. 78 | 79 | 5. When you're done making changes, check that your changes pass flake8 and the 80 | tests, including testing other Python versions with tox:: 81 | 82 | $ flake8 geehydro tests 83 | $ python setup.py test or pytest 84 | $ tox 85 | 86 | To get flake8 and tox, just pip install them into your virtualenv. 87 | 88 | 6. Commit your changes and push your branch to GitHub:: 89 | 90 | $ git add . 91 | $ git commit -m "Your detailed description of your changes." 92 | $ git push origin name-of-your-bugfix-or-feature 93 | 94 | 7. Submit a pull request through the GitHub website. 95 | 96 | Pull Request Guidelines 97 | ----------------------- 98 | 99 | Before you submit a pull request, check that it meets these guidelines: 100 | 101 | 1. The pull request should include tests. 102 | 2. If the pull request adds functionality, the docs should be updated. Put 103 | your new functionality into a function with a docstring, and add the 104 | feature to the list in README.rst. 105 | 3. The pull request should work for Python 2.7, 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check 106 | https://travis-ci.org/giswqs/geehydro/pull_requests 107 | and make sure that the tests pass for all supported Python versions. 108 | 109 | Tips 110 | ---- 111 | 112 | To run a subset of tests:: 113 | 114 | 115 | $ python -m unittest tests.test_geehydro 116 | 117 | Deploying 118 | --------- 119 | 120 | A reminder for the maintainers on how to deploy. 121 | Make sure all your changes are committed (including an entry in HISTORY.rst). 122 | Then run:: 123 | 124 | $ bump2version patch # possible: major / minor / patch 125 | $ git push 126 | $ git push --tags 127 | 128 | Travis will then deploy to PyPI if tests pass. 129 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 0.2.0 (2020-03-21) 5 | ------------------ 6 | 0.1.0 (2019-11-19) 7 | ------------------ 8 | 9 | * First release on PyPI. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019, Qiusheng Wu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | include requirements.txt 7 | 8 | recursive-include tests * 9 | recursive-exclude * __pycache__ 10 | recursive-exclude * *.py[co] 11 | 12 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean clean-test clean-pyc clean-build docs help 2 | .DEFAULT_GOAL := help 3 | 4 | define BROWSER_PYSCRIPT 5 | import os, webbrowser, sys 6 | 7 | try: 8 | from urllib import pathname2url 9 | except: 10 | from urllib.request import pathname2url 11 | 12 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 13 | endef 14 | export BROWSER_PYSCRIPT 15 | 16 | define PRINT_HELP_PYSCRIPT 17 | import re, sys 18 | 19 | for line in sys.stdin: 20 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) 21 | if match: 22 | target, help = match.groups() 23 | print("%-20s %s" % (target, help)) 24 | endef 25 | export PRINT_HELP_PYSCRIPT 26 | 27 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 28 | 29 | help: 30 | @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) 31 | 32 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 33 | 34 | clean-build: ## remove build artifacts 35 | rm -fr build/ 36 | rm -fr dist/ 37 | rm -fr .eggs/ 38 | find . -name '*.egg-info' -exec rm -fr {} + 39 | find . -name '*.egg' -exec rm -f {} + 40 | 41 | clean-pyc: ## remove Python file artifacts 42 | find . -name '*.pyc' -exec rm -f {} + 43 | find . -name '*.pyo' -exec rm -f {} + 44 | find . -name '*~' -exec rm -f {} + 45 | find . -name '__pycache__' -exec rm -fr {} + 46 | 47 | clean-test: ## remove test and coverage artifacts 48 | rm -fr .tox/ 49 | rm -f .coverage 50 | rm -fr htmlcov/ 51 | rm -fr .pytest_cache 52 | 53 | lint: ## check style with flake8 54 | flake8 geehydro tests 55 | 56 | test: ## run tests quickly with the default Python 57 | python setup.py test 58 | 59 | test-all: ## run tests on every Python version with tox 60 | tox 61 | 62 | coverage: ## check code coverage quickly with the default Python 63 | coverage run --source geehydro setup.py test 64 | coverage report -m 65 | coverage html 66 | $(BROWSER) htmlcov/index.html 67 | 68 | docs: ## generate Sphinx HTML documentation, including API docs 69 | rm -f docs/geehydro.rst 70 | rm -f docs/modules.rst 71 | sphinx-apidoc -o docs/ geehydro 72 | $(MAKE) -C docs clean 73 | $(MAKE) -C docs html 74 | $(BROWSER) docs/_build/html/index.html 75 | 76 | servedocs: docs ## compile the docs watching for changes 77 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 78 | 79 | release: dist ## package and upload a release 80 | twine upload dist/* 81 | 82 | dist: clean ## builds source and wheel package 83 | python setup.py sdist 84 | python setup.py bdist_wheel 85 | ls -l dist 86 | 87 | install: clean ## install the package to the active Python's site-packages 88 | python setup.py install 89 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | geehydro 3 | ======== 4 | 5 | 6 | .. image:: https://img.shields.io/pypi/v/geehydro.svg 7 | :target: https://pypi.python.org/pypi/geehydro 8 | 9 | .. image:: https://img.shields.io/conda/vn/conda-forge/geehydro.svg 10 | :target: https://anaconda.org/conda-forge/geehydro 11 | 12 | .. image:: https://img.shields.io/travis/giswqs/geehydro.svg 13 | :target: https://travis-ci.com/giswqs/geehydro 14 | 15 | .. image:: https://readthedocs.org/projects/geehydro/badge/?version=latest 16 | :target: https://geehydro.readthedocs.io/en/latest/?badge=latest 17 | :alt: Documentation Status 18 | 19 | 20 | 21 | 22 | Python package for mapping inundation dynamics using Google Earth Engine 23 | 24 | 25 | * PyPI: https://pypi.python.org/pypi/geehydro 26 | * Conda-forge: https://anaconda.org/conda-forge/geehydro 27 | * Documentation: https://geehydro.readthedocs.io 28 | * Free software: MIT license 29 | 30 | 31 | Important Note 32 | -------------- 33 | This package is no longer being actively maintained. Please use the `geemap `__ package instead. 34 | 35 | 36 | Installation 37 | ------------ 38 | 39 | The **geehydro** Python package is built upon the `folium `__ package and 40 | implements several methods for interacting with Earth Engine data layers, such as ``Map.addLayer()``, ``Map.setCenter()``, and ``Map.centerObject()``. 41 | 42 | 43 | To install **geehydro**, run this command in your terminal: 44 | 45 | .. code:: python 46 | 47 | pip install geehydro 48 | 49 | 50 | **geehydro** is also available on `conda-forge `__. If you have Anaconda_ or Miniconda_ installed on your computer, you can create a conda Python environment to install geehydro: 51 | 52 | .. code:: python 53 | 54 | conda create -n gee python 55 | conda activate gee 56 | conda install -c conda-forge geehydro 57 | 58 | 59 | If you have installed **geehydro** before and want to upgrade to the latest version, you can run the following command in your terminal: 60 | 61 | .. code:: python 62 | 63 | pip install -U geehydro 64 | 65 | 66 | To install the development version from GitHub, run the following command in your terminal: 67 | 68 | .. code:: python 69 | 70 | pip install git+https://github.com/giswqs/geehydro 71 | 72 | 73 | .. _Anaconda: https://www.anaconda.com/distribution/#download-section 74 | .. _Miniconda: https://docs.conda.io/en/latest/miniconda.html 75 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = geehydro 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # geehydro documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Jun 9 13:47:02 2017. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another 17 | # directory, add these directories to sys.path here. If the directory is 18 | # relative to the documentation root, use os.path.abspath to make it 19 | # absolute, like shown here. 20 | # 21 | import os 22 | import sys 23 | sys.path.insert(0, os.path.abspath('..')) 24 | 25 | import geehydro 26 | 27 | # -- General configuration --------------------------------------------- 28 | 29 | # If your documentation needs a minimal Sphinx version, state it here. 30 | # 31 | # needs_sphinx = '1.0' 32 | 33 | # Add any Sphinx extension module names here, as strings. They can be 34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 35 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix(es) of source filenames. 41 | # You can specify multiple suffix as a list of string: 42 | # 43 | # source_suffix = ['.rst', '.md'] 44 | source_suffix = '.rst' 45 | 46 | # The master toctree document. 47 | master_doc = 'index' 48 | 49 | # General information about the project. 50 | project = u'geehydro' 51 | copyright = u"2019, Qiusheng Wu" 52 | author = u"Qiusheng Wu" 53 | 54 | # The version info for the project you're documenting, acts as replacement 55 | # for |version| and |release|, also used in various other places throughout 56 | # the built documents. 57 | # 58 | # The short X.Y version. 59 | version = geehydro.__version__ 60 | # The full version, including alpha/beta/rc tags. 61 | release = geehydro.__version__ 62 | 63 | # The language for content autogenerated by Sphinx. Refer to documentation 64 | # for a list of supported languages. 65 | # 66 | # This is also used if you do content translation via gettext catalogs. 67 | # Usually you set "language" from the command line for these cases. 68 | language = None 69 | 70 | # List of patterns, relative to source directory, that match files and 71 | # directories to ignore when looking for source files. 72 | # This patterns also effect to html_static_path and html_extra_path 73 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 74 | 75 | # The name of the Pygments (syntax highlighting) style to use. 76 | pygments_style = 'sphinx' 77 | 78 | # If true, `todo` and `todoList` produce output, else they produce nothing. 79 | todo_include_todos = False 80 | 81 | 82 | # -- Options for HTML output ------------------------------------------- 83 | 84 | # The theme to use for HTML and HTML Help pages. See the documentation for 85 | # a list of builtin themes. 86 | # 87 | # html_theme = 'alabaster' 88 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 89 | 90 | if not on_rtd: # only import and set the theme if we're building docs locally 91 | import sphinx_rtd_theme 92 | html_theme = 'sphinx_rtd_theme' 93 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 94 | 95 | html_context = { 96 | 'css_files': [ 97 | '_static/theme_overrides.css' 98 | ] 99 | } 100 | else: 101 | html_context = { 102 | 'css_files': [ 103 | '//media.readthedocs.org/css/sphinx_rtd_theme.css', 104 | '//media.readthedocs.org/css/readthedocs-doc-embed.css', 105 | '_static/theme_overrides.css' 106 | ] 107 | } 108 | 109 | # Theme options are theme-specific and customize the look and feel of a 110 | # theme further. For a list of options available for each theme, see the 111 | # documentation. 112 | # 113 | # html_theme_options = {} 114 | 115 | # Add any paths that contain custom static files (such as style sheets) here, 116 | # relative to this directory. They are copied after the builtin static files, 117 | # so a file named "default.css" will overwrite the builtin "default.css". 118 | html_static_path = ['_static'] 119 | 120 | 121 | # -- Options for HTMLHelp output --------------------------------------- 122 | 123 | # Output file base name for HTML help builder. 124 | htmlhelp_basename = 'geehydrodoc' 125 | 126 | 127 | # -- Options for LaTeX output ------------------------------------------ 128 | 129 | latex_elements = { 130 | # The paper size ('letterpaper' or 'a4paper'). 131 | # 132 | # 'papersize': 'letterpaper', 133 | 134 | # The font size ('10pt', '11pt' or '12pt'). 135 | # 136 | # 'pointsize': '10pt', 137 | 138 | # Additional stuff for the LaTeX preamble. 139 | # 140 | # 'preamble': '', 141 | 142 | # Latex figure (float) alignment 143 | # 144 | # 'figure_align': 'htbp', 145 | } 146 | 147 | # Grouping the document tree into LaTeX files. List of tuples 148 | # (source start file, target name, title, author, documentclass 149 | # [howto, manual, or own class]). 150 | latex_documents = [ 151 | (master_doc, 'geehydro.tex', 152 | u'geehydro Documentation', 153 | u'Qiusheng Wu', 'manual'), 154 | ] 155 | 156 | 157 | # -- Options for manual page output ------------------------------------ 158 | 159 | # One entry per manual page. List of tuples 160 | # (source start file, name, description, authors, manual section). 161 | man_pages = [ 162 | (master_doc, 'geehydro', 163 | u'geehydro Documentation', 164 | [author], 1) 165 | ] 166 | 167 | 168 | # -- Options for Texinfo output ---------------------------------------- 169 | 170 | # Grouping the document tree into Texinfo files. List of tuples 171 | # (source start file, target name, title, author, 172 | # dir menu entry, description, category) 173 | texinfo_documents = [ 174 | (master_doc, 'geehydro', 175 | u'geehydro Documentation', 176 | author, 177 | 'geehydro', 178 | 'One line description of project.', 179 | 'Miscellaneous'), 180 | ] 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to geehydro's documentation! 2 | ====================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | readme 9 | installation 10 | usage 11 | modules 12 | contributing 13 | authors 14 | history 15 | 16 | Indices and tables 17 | ================== 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | 8 | Stable release 9 | -------------- 10 | 11 | To install geehydro, run this command in your terminal: 12 | 13 | .. code-block:: console 14 | 15 | $ pip install geehydro 16 | 17 | This is the preferred method to install geehydro, as it will always install the most recent stable release. 18 | 19 | If you don't have `pip`_ installed, this `Python installation guide`_ can guide 20 | you through the process. 21 | 22 | .. _pip: https://pip.pypa.io 23 | .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ 24 | 25 | 26 | From sources 27 | ------------ 28 | 29 | The sources for geehydro can be downloaded from the `Github repo`_. 30 | 31 | You can either clone the public repository: 32 | 33 | .. code-block:: console 34 | 35 | $ git clone git://github.com/giswqs/geehydro 36 | 37 | Or download the `tarball`_: 38 | 39 | .. code-block:: console 40 | 41 | $ curl -OJL https://github.com/giswqs/geehydro/tarball/master 42 | 43 | Once you have a copy of the source, you can install it with: 44 | 45 | .. code-block:: console 46 | 47 | $ python setup.py install 48 | 49 | 50 | .. _Github repo: https://github.com/giswqs/geehydro 51 | .. _tarball: https://github.com/giswqs/geehydro/tarball/master 52 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=geehydro 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | To use geehydro in a project:: 6 | 7 | import geehydro 8 | -------------------------------------------------------------------------------- /examples/geehydro-tutorials.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "
\n", 8 | "\n", 9 | " Run in Google Colab\n", 10 | "\n", 11 | " View source on GitHub\n", 12 | "Notebook Viewer\n", 13 | "Run in binder
" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 1, 19 | "metadata": { 20 | "scrolled": true 21 | }, 22 | "outputs": [], 23 | "source": [ 24 | "# !pip install geehydro" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": { 31 | "scrolled": true 32 | }, 33 | "outputs": [], 34 | "source": [ 35 | "import ee\n", 36 | "import folium\n", 37 | "import geehydro" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 3, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "# ee.Authenticate()\n", 47 | "ee.Initialize()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 4, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "Map = folium.Map(location=[40, -100], zoom_start=4)\n", 57 | "Map.setOptions('HYBRID')" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 5, 63 | "metadata": { 64 | "scrolled": false 65 | }, 66 | "outputs": [], 67 | "source": [ 68 | "dem = ee.Image('USGS/SRTMGL1_003')\n", 69 | "\n", 70 | "vis_params = {\n", 71 | "'min': 0,\n", 72 | "'max': 4000,\n", 73 | "'palette': ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5']}\n", 74 | "\n", 75 | "Map.addLayer(dem, vis_params, 'DEM')" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 6, 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "dataset = ee.FeatureCollection('projects/google/wrs2_descending')\n", 85 | "\n", 86 | "# empty = ee.Image().byte()\n", 87 | "\n", 88 | "Map.setCenter(-78, 36, 8)\n", 89 | "Map.addLayer(dataset, {}, 'Landsat WRS-2 grid', False, 0.5)\n", 90 | "# Map.addLayer(empty.paint(dataset, 0, 2), {}, 'Landsat WRS-2 grid')" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 7, 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "data": { 100 | "text/html": [ 101 | "
" 102 | ], 103 | "text/plain": [ 104 | "" 105 | ] 106 | }, 107 | "execution_count": 7, 108 | "metadata": {}, 109 | "output_type": "execute_result" 110 | } 111 | ], 112 | "source": [ 113 | "Map.setControlVisibility(layerControl=True, fullscreenControl=True, latLngPopup=True)\n", 114 | "Map" 115 | ] 116 | } 117 | ], 118 | "metadata": { 119 | "kernelspec": { 120 | "display_name": "Python 3", 121 | "language": "python", 122 | "name": "python3" 123 | }, 124 | "language_info": { 125 | "codemirror_mode": { 126 | "name": "ipython", 127 | "version": 3 128 | }, 129 | "file_extension": ".py", 130 | "mimetype": "text/x-python", 131 | "name": "python", 132 | "nbconvert_exporter": "python", 133 | "pygments_lexer": "ipython3", 134 | "version": "3.7.3" 135 | } 136 | }, 137 | "nbformat": 4, 138 | "nbformat_minor": 4 139 | } 140 | -------------------------------------------------------------------------------- /examples/landsat_wrs2_grid.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "
\n", 8 | "\n", 9 | " Run in Google Colab\n", 10 | "\n", 11 | " View source on GitHub\n", 12 | "Notebook Viewer\n", 13 | "Run in binder
" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 14, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "# !pip install geehydro" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 15, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "import ee\n", 32 | "import folium\n", 33 | "import geehydro" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 16, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "# ee.Authenticate()\n", 43 | "ee.Initialize()" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 17, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "Map = folium.Map(location=[40, -100], zoom_start=4)\n", 53 | "Map.setOptions('ROADMAP')" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 18, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "dataset = ee.FeatureCollection('projects/google/wrs2_descending')\n", 63 | "empty = ee.Image().byte()" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 19, 69 | "metadata": {}, 70 | "outputs": [ 71 | { 72 | "data": { 73 | "text/html": [ 74 | "
" 75 | ], 76 | "text/plain": [ 77 | "" 78 | ] 79 | }, 80 | "execution_count": 19, 81 | "metadata": {}, 82 | "output_type": "execute_result" 83 | } 84 | ], 85 | "source": [ 86 | "Map.setCenter(-78, 36, 8)\n", 87 | "Map.addLayer(dataset, {}, 'Landsat WRS-2 grid')\n", 88 | "# Map.addLayer(empty.paint(dataset, 0, 2), {}, 'Landsat WRS-2 grid')\n", 89 | "\n", 90 | "Map.setControlVisibility(layerControl=True, fullscreenControl=True, latLngPopup=True)\n", 91 | "Map" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [] 100 | } 101 | ], 102 | "metadata": { 103 | "anaconda-cloud": {}, 104 | "kernelspec": { 105 | "display_name": "Python 3", 106 | "language": "python", 107 | "name": "python3" 108 | }, 109 | "language_info": { 110 | "codemirror_mode": { 111 | "name": "ipython", 112 | "version": 3 113 | }, 114 | "file_extension": ".py", 115 | "mimetype": "text/x-python", 116 | "name": "python", 117 | "nbconvert_exporter": "python", 118 | "pygments_lexer": "ipython3", 119 | "version": "3.7.3" 120 | } 121 | }, 122 | "nbformat": 4, 123 | "nbformat_minor": 1 124 | } 125 | -------------------------------------------------------------------------------- /examples/landsat_wrs2_grid.py: -------------------------------------------------------------------------------- 1 | ''' 2 |
3 | 4 | Run in Google Colab 5 | 6 | View source on GitHub 7 | Notebook Viewer 8 | Run in binder
9 | ''' 10 | 11 | # %% 12 | # !pip install geehydro 13 | 14 | # %% 15 | import ee 16 | import folium 17 | import geehydro 18 | 19 | # %% 20 | ee.Authenticate() 21 | ee.Initialize() 22 | 23 | # %% 24 | Map = folium.Map(location=[40, -100], zoom_start=4) 25 | Map.setOptions('HYBRID') 26 | 27 | # %% 28 | dataset = ee.FeatureCollection('projects/google/wrs2_descending') 29 | empty = ee.Image().byte() 30 | 31 | # %% 32 | Map.setCenter(-78, 36, 8) 33 | Map.addLayer(empty.paint(dataset, 0, 2), {}, 'Landsat WRS-2 grid') 34 | Map.setControlVisibility(layerControl=True, fullscreenControl=True, latLngPopup=True) 35 | Map 36 | 37 | # %% 38 | -------------------------------------------------------------------------------- /examples/naip.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | " \n", 9 | " \n", 10 | " \n", 11 | " \n", 12 | "
View source on GitHubNotebook ViewerRun in binder Run in Google Colab
" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "## Install Earth Engine API\n", 20 | "Install the [Earth Engine Python API](https://developers.google.com/earth-engine/python_install) and [geehydro](https://github.com/giswqs/geehydro). The **geehydro** Python package builds on the [folium](https://github.com/python-visualization/folium) package and implements several methods for displaying Earth Engine data layers, such as `Map.addLayer()`, `Map.setCenter()`, `Map.centerObject()`, and `Map.setOptions()`.\n", 21 | "The magic command `%%capture` can be used to hide output from a specific cell." 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "# %%capture\n", 31 | "# !pip install earthengine-api\n", 32 | "# !pip install geehydro" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "Import libraries" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "import ee\n", 49 | "import folium\n", 50 | "import geehydro\n", 51 | "from geehydro.utilities import *" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "Authenticate and initialize Earth Engine API. You only need to authenticate the Earth Engine API once. Uncomment the line `ee.Authenticate()` \n", 59 | "if you are running this notebook for this first time or if you are getting an authentication error. " 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 3, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "# ee.Authenticate()\n", 69 | "ee.Initialize()" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "## Create an interactive map \n", 77 | "This step creates an interactive map using [folium](https://github.com/python-visualization/folium). The default basemap is the OpenStreetMap. Additional basemaps can be added using the `Map.setOptions()` function. \n", 78 | "The optional basemaps can be `ROADMAP`, `SATELLITE`, `HYBRID`, `TERRAIN`, or `ESRI`." 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 4, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "Map = folium.Map(location=[40, -100], zoom_start=4)\n", 88 | "Map.setOptions('HYBRID')" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "## Add Earth Engine Python script " 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 5, 101 | "metadata": {}, 102 | "outputs": [ 103 | { 104 | "name": "stdout", 105 | "output_type": "stream", 106 | "text": [ 107 | "Available NAIP images: 4\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "#Step 1: Get county boundary\n", 113 | "counties = ee.FeatureCollection('TIGER/2018/Counties')\n", 114 | "# Map.addLayer(counties, {}, 'US Counties', False)\n", 115 | "\n", 116 | "knox = counties.filter(ee.Filter.And(ee.Filter.eq('NAME', 'Knox'), ee.Filter.eq('STATEFP', '47')))\n", 117 | "Map.centerObject(knox, 10)\n", 118 | "Map.addLayer(knox, {}, 'Knox County')\n", 119 | "\n", 120 | "naip_images = findNAIP(knox)\n", 121 | "naip_count = naip_images.size().getInfo()\n", 122 | "print('Available NAIP images: {}'.format(naip_count))" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 6, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | "['2010-04-11', '2012-05-28', '2014-04-27', '2016-04-18']\n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "dates = ee.List(naip_images.aggregate_array('system:time_start')).map(lambda x: ee.Date(x).format('YYYY-MM-dd'))\n", 140 | "dates_list = dates.getInfo()\n", 141 | "print(dates_list)\n", 142 | "\n", 143 | "ndvi_vis = {\n", 144 | " 'min': 0,\n", 145 | " 'max': 1,\n", 146 | " 'palette': [\n", 147 | " 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718',\n", 148 | " '74A901', '66A000', '529400', '3E8601', '207401', '056201',\n", 149 | " '004C00', '023B01', '012E01', '011D01', '011301'] \n", 150 | "}\n", 151 | "\n", 152 | "for i in range(0, naip_count):\n", 153 | " naip_image = ee.Image(naip_images.toList(naip_count).get(i))\n", 154 | " ndvi_image = naip_image.select('ndvi')\n", 155 | " Map.addLayer(naip_image, {'bands': ['N', 'R', 'G']}, 'NAIP ' + dates_list[i])\n", 156 | " Map.addLayer(ndvi_image, ndvi_vis, 'NDVI ' + dates_list[i])" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "## Display Earth Engine data layers " 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 7, 169 | "metadata": {}, 170 | "outputs": [ 171 | { 172 | "data": { 173 | "text/html": [ 174 | "
" 175 | ], 176 | "text/plain": [ 177 | "" 178 | ] 179 | }, 180 | "execution_count": 7, 181 | "metadata": {}, 182 | "output_type": "execute_result" 183 | } 184 | ], 185 | "source": [ 186 | "Map.setControlVisibility(layerControl=True, fullscreenControl=True, latLngPopup=True)\n", 187 | "Map" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [] 196 | } 197 | ], 198 | "metadata": { 199 | "anaconda-cloud": {}, 200 | "kernelspec": { 201 | "display_name": "Python 3", 202 | "language": "python", 203 | "name": "python3" 204 | }, 205 | "language_info": { 206 | "codemirror_mode": { 207 | "name": "ipython", 208 | "version": 3 209 | }, 210 | "file_extension": ".py", 211 | "mimetype": "text/x-python", 212 | "name": "python", 213 | "nbconvert_exporter": "python", 214 | "pygments_lexer": "ipython3", 215 | "version": "3.7.3" 216 | } 217 | }, 218 | "nbformat": 4, 219 | "nbformat_minor": 1 220 | } 221 | -------------------------------------------------------------------------------- /examples/template.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "
\n", 8 | " View source on GitHub\n", 9 | "Notebook Viewer\n", 10 | "Run in binder\n", 11 | " Run in Google Colab\n", 12 | "
" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": { 19 | "scrolled": true 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "# !pip install geehydro" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": { 30 | "scrolled": true 31 | }, 32 | "outputs": [], 33 | "source": [ 34 | "import ee\n", 35 | "import folium\n", 36 | "import geehydro" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "# ee.Authenticate()\n", 46 | "ee.Initialize()" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "Map = folium.Map(location=[40, -100], zoom_start=4)\n", 56 | "Map.setOptions('HYBRID')" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": { 63 | "scrolled": false 64 | }, 65 | "outputs": [], 66 | "source": [] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": { 72 | "scrolled": true 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "Map.setControlVisibility(layerControl=True, fullscreenControl=True, latLngPopup=True)\n", 77 | "Map" 78 | ] 79 | } 80 | ], 81 | "metadata": { 82 | "kernelspec": { 83 | "display_name": "Python 3", 84 | "language": "python", 85 | "name": "python3" 86 | }, 87 | "language_info": { 88 | "codemirror_mode": { 89 | "name": "ipython", 90 | "version": 3 91 | }, 92 | "file_extension": ".py", 93 | "mimetype": "text/x-python", 94 | "name": "python", 95 | "nbconvert_exporter": "python", 96 | "pygments_lexer": "ipython3", 97 | "version": "3.7.3" 98 | } 99 | }, 100 | "nbformat": 4, 101 | "nbformat_minor": 4 102 | } 103 | -------------------------------------------------------------------------------- /examples/template.nbconvert.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "
\n", 8 | "\n", 9 | " Run in Google Colab\n", 10 | "\n", 11 | " View source on GitHub\n", 12 | "Notebook Viewer\n", 13 | "Run in binder
" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 1, 19 | "metadata": { 20 | "scrolled": true 21 | }, 22 | "outputs": [], 23 | "source": [ 24 | "# !pip install geehydro" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": { 31 | "scrolled": true 32 | }, 33 | "outputs": [], 34 | "source": [ 35 | "import ee\n", 36 | "import folium\n", 37 | "import geehydro" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 3, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "# ee.Authenticate()\n", 47 | "ee.Initialize()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 4, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "Map = folium.Map(location=[40, -100], zoom_start=4)\n", 57 | "Map.setOptions('HYBRID')" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": { 64 | "scrolled": false 65 | }, 66 | "outputs": [], 67 | "source": [] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 5, 72 | "metadata": { 73 | "scrolled": true 74 | }, 75 | "outputs": [ 76 | { 77 | "data": { 78 | "text/html": [ 79 | "
" 80 | ], 81 | "text/plain": [ 82 | "" 83 | ] 84 | }, 85 | "execution_count": 5, 86 | "metadata": {}, 87 | "output_type": "execute_result" 88 | } 89 | ], 90 | "source": [ 91 | "Map.setControlVisibility(layerControl=True, fullscreenControl=True, latLngPopup=True)\n", 92 | "Map" 93 | ] 94 | } 95 | ], 96 | "metadata": { 97 | "kernelspec": { 98 | "display_name": "Python 3", 99 | "language": "python", 100 | "name": "python3" 101 | }, 102 | "language_info": { 103 | "codemirror_mode": { 104 | "name": "ipython", 105 | "version": 3 106 | }, 107 | "file_extension": ".py", 108 | "mimetype": "text/x-python", 109 | "name": "python", 110 | "nbconvert_exporter": "python", 111 | "pygments_lexer": "ipython3", 112 | "version": "3.7.3" 113 | } 114 | }, 115 | "nbformat": 4, 116 | "nbformat_minor": 4 117 | } 118 | -------------------------------------------------------------------------------- /geehydro/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Top-level package for geehydro.""" 4 | 5 | __author__ = """Qiusheng Wu""" 6 | __email__ = 'giswqs@gmail.com' 7 | __version__ = '0.2.0' 8 | 9 | from .geehydro import * 10 | -------------------------------------------------------------------------------- /geehydro/add_layer.py: -------------------------------------------------------------------------------- 1 | import ee 2 | import folium 3 | from folium import plugins 4 | 5 | ee.Initialize() 6 | 7 | # Define a method for displaying Earth Engine image tiles on a folium map. 8 | def add_ee_layer(self, ee_object, vis_params, name): 9 | 10 | try: 11 | # display ee.Image() 12 | if isinstance(ee_object, ee.image.Image): 13 | map_id_dict = ee.Image(ee_object).getMapId(vis_params) 14 | folium.raster_layers.TileLayer( 15 | tiles = map_id_dict['tile_fetcher'].url_format, 16 | attr = 'Google Earth Engine', 17 | name = name, 18 | overlay = True, 19 | control = True 20 | ).add_to(self) 21 | # display ee.ImageCollection() 22 | elif isinstance(ee_object, ee.imagecollection.ImageCollection): 23 | ee_object_new = ee_object.mosaic() 24 | map_id_dict = ee.Image(ee_object_new).getMapId(vis_params) 25 | folium.raster_layers.TileLayer( 26 | tiles = map_id_dict['tile_fetcher'].url_format, 27 | attr = 'Google Earth Engine', 28 | name = name, 29 | overlay = True, 30 | control = True 31 | ).add_to(self) 32 | # display ee.Geometry() 33 | elif isinstance(ee_object, ee.geometry.Geometry): 34 | folium.GeoJson( 35 | data = ee_object.getInfo(), 36 | name = name, 37 | overlay = True, 38 | control = True 39 | ).add_to(self) 40 | # display ee.FeatureCollection() 41 | elif isinstance(ee_object, ee.featurecollection.FeatureCollection): 42 | ee_object_new = ee.Image().paint(ee_object, 0, 2) 43 | map_id_dict = ee.Image(ee_object_new).getMapId(vis_params) 44 | folium.raster_layers.TileLayer( 45 | tiles = map_id_dict['tile_fetcher'].url_format, 46 | attr = 'Google Earth Engine', 47 | name = name, 48 | overlay = True, 49 | control = True 50 | ).add_to(self) 51 | 52 | except: 53 | print("Could not display {}".format(name)) 54 | 55 | # Add EE drawing method to folium. 56 | folium.Map.add_ee_layer = add_ee_layer 57 | 58 | -------------------------------------------------------------------------------- /geehydro/basemaps.py: -------------------------------------------------------------------------------- 1 | import folium 2 | 3 | # Add custom basemaps to folium 4 | basemaps = { 5 | 'Google Maps': folium.TileLayer( 6 | tiles = 'https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', 7 | attr = 'Google', 8 | name = 'Google Maps', 9 | overlay = True, 10 | control = True 11 | ), 12 | 'Google Satellite': folium.TileLayer( 13 | tiles = 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', 14 | attr = 'Google', 15 | name = 'Google Satellite', 16 | overlay = True, 17 | control = True 18 | ), 19 | 'Google Terrain': folium.TileLayer( 20 | tiles = 'https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}', 21 | attr = 'Google', 22 | name = 'Google Terrain', 23 | overlay = True, 24 | control = True 25 | ), 26 | 'Google Satellite Hybrid': folium.TileLayer( 27 | tiles = 'https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', 28 | attr = 'Google', 29 | name = 'Google Satellite', 30 | overlay = True, 31 | control = True 32 | ), 33 | 'Esri Satellite': folium.TileLayer( 34 | tiles = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', 35 | attr = 'Esri', 36 | name = 'Esri Satellite', 37 | overlay = True, 38 | control = True 39 | ) 40 | } 41 | 42 | -------------------------------------------------------------------------------- /geehydro/cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Console script for geehydro.""" 4 | import sys 5 | import click 6 | 7 | 8 | @click.command() 9 | def main(args=None): 10 | """Console script for geehydro.""" 11 | click.echo("Replace this message by putting your code into " 12 | "geehydro.cli.main") 13 | click.echo("See click documentation at https://click.palletsprojects.com/") 14 | return 0 15 | 16 | 17 | if __name__ == "__main__": 18 | sys.exit(main()) # pragma: no cover 19 | -------------------------------------------------------------------------------- /geehydro/geehydro.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Main module.""" 4 | 5 | import os 6 | import ee 7 | import folium 8 | from folium import plugins 9 | 10 | # Add Earth Engine layer to folium 11 | def addLayer(self, ee_object, vis_params={}, name='Layer untitled', shown=True, opacity=1): 12 | 13 | image = None 14 | 15 | if not isinstance(ee_object, ee.Image) and not isinstance(ee_object, ee.ImageCollection) and not isinstance(ee_object, ee.FeatureCollection) and not isinstance(ee_object, ee.Feature) and not isinstance(ee_object, ee.Geometry): 16 | err_str = "\n\nThe image argument in 'addLayer' function must be an instace of one of ee.Image, ee.Geometry, ee.Feature or ee.FeatureCollection." 17 | raise AttributeError(err_str) 18 | 19 | if isinstance(ee_object, ee.geometry.Geometry) or isinstance(ee_object, ee.feature.Feature) or isinstance(ee_object, ee.featurecollection.FeatureCollection): 20 | features = ee.FeatureCollection(ee_object) 21 | 22 | width = 2 23 | 24 | if 'width' in vis_params: 25 | width = vis_params['width'] 26 | 27 | color = '000000' 28 | 29 | if 'color' in vis_params: 30 | color = vis_params['color'] 31 | 32 | image_fill = features.style( 33 | **{'fillColor': color}).updateMask(ee.Image.constant(0.5)) 34 | image_outline = features.style( 35 | **{'color': color, 'fillColor': '00000000', 'width': width}) 36 | 37 | image = image_fill.blend(image_outline) 38 | elif isinstance(ee_object, ee.image.Image): 39 | image = ee_object 40 | elif isinstance(ee_object, ee.imagecollection.ImageCollection): 41 | image = ee_object.median() 42 | 43 | map_id_dict = ee.Image(image).getMapId(vis_params) 44 | folium.raster_layers.TileLayer( 45 | tiles=map_id_dict['tile_fetcher'].url_format, 46 | attr='Google Earth Engine', 47 | name=name, 48 | overlay=True, 49 | control=True, 50 | show=shown, 51 | opacity=opacity 52 | ).add_to(self) 53 | 54 | folium.Map.addLayer = addLayer 55 | 56 | # Add custom WMS tile layer to folium 57 | def addWmsTileLayer(self, url, layers, name=None, attr='', overlay=True, control=True, show=True): 58 | try: 59 | folium.raster_layers.WmsTileLayer( 60 | url=url, 61 | layers=layers, 62 | attr=attr, 63 | name=name, 64 | overlay=overlay, 65 | control=control, 66 | show=show 67 | ).add_to(self) 68 | except: 69 | print("Failed to add the specified WMS TileLayer.") 70 | 71 | folium.Map.addWmsTileLayer = addWmsTileLayer 72 | 73 | 74 | # Add custom tile layer to folium 75 | def addTileLayer(self, tiles='OpenStreetMap', name=None, attr='', overlay=True, control=True, show=True, opacity=1, API_key=None): 76 | try: 77 | folium.raster_layers.TileLayer( 78 | tiles=tiles, 79 | name=name, 80 | attr=attr, 81 | overlay=overlay, 82 | control=control, 83 | show=show, 84 | opacity=opacity, 85 | API_key=API_key 86 | ).add_to(self) 87 | except: 88 | print("Failed to add the specified TileLayer.") 89 | 90 | folium.Map.addTileLayer = addTileLayer 91 | 92 | 93 | # https://viewer.nationalmap.gov/services/ 94 | # Modifies the Google Maps basemap 95 | # A mapTypeId to set the basemap to. Can be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN" to select one of the standard Google Maps API map types 96 | def setOptions(self, mapTypeId='HYBRID', styles={}, types=[]): 97 | # Add custom basemaps to folium 98 | basemaps = { 99 | 'ROADMAP': folium.TileLayer( 100 | tiles='https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', 101 | attr='Google', 102 | name='Google Maps', 103 | overlay=True, 104 | control=True 105 | ), 106 | 'SATELLITE': folium.TileLayer( 107 | tiles='https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', 108 | attr='Google', 109 | name='Google Satellite', 110 | overlay=True, 111 | control=True 112 | ), 113 | 'TERRAIN': folium.TileLayer( 114 | tiles='https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}', 115 | attr='Google', 116 | name='Google Terrain', 117 | overlay=True, 118 | control=True 119 | ), 120 | 'HYBRID': folium.TileLayer( 121 | tiles='https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', 122 | attr='Google', 123 | name='Google Satellite', 124 | overlay=True, 125 | control=True 126 | ), 127 | 'ESRI': folium.TileLayer( 128 | tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', 129 | attr='Esri', 130 | name='Esri Satellite', 131 | overlay=True, 132 | control=True 133 | ), 134 | 'Esri Ocean': folium.TileLayer( 135 | tiles='https://services.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}', 136 | attr='Esri', 137 | name='Esri Ocean', 138 | overlay=True, 139 | control=True 140 | ), 141 | 'Esri Satellite': folium.TileLayer( 142 | tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', 143 | attr='Esri', 144 | name='Esri Satellite', 145 | overlay=True, 146 | control=True 147 | ), 148 | 'Esri Standard': folium.TileLayer( 149 | tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', 150 | attr='Esri', 151 | name='Esri Standard', 152 | overlay=True, 153 | control=True 154 | ), 155 | 'Esri Terrain': folium.TileLayer( 156 | tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}', 157 | attr='Esri', 158 | name='Esri Terrain', 159 | overlay=True, 160 | control=True 161 | ), 162 | 'Esri Transportation': folium.TileLayer( 163 | tiles='https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}', 164 | attr='Esri', 165 | name='Esri Transportation', 166 | overlay=True, 167 | control=True 168 | ), 169 | 170 | 'Esri Topo World': folium.TileLayer( 171 | tiles='https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', 172 | attr='Esri', 173 | name='Esri Topo World', 174 | overlay=True, 175 | control=True 176 | ), 177 | 178 | 'Esri National Geographic': folium.TileLayer( 179 | tiles='http://services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}', 180 | attr='Esri', 181 | name='Esri National Geographic', 182 | overlay=True, 183 | control=True 184 | ), 185 | 186 | 'Esri Shaded Relief': folium.TileLayer( 187 | tiles='https://services.arcgisonline.com/arcgis/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}', 188 | attr='Esri', 189 | name='Esri Shaded Relief', 190 | overlay=True, 191 | control=True 192 | ), 193 | 194 | 'Esri Physical Map': folium.TileLayer( 195 | tiles='https://services.arcgisonline.com/arcgis/rest/services/World_Physical_Map/MapServer/tile/{z}/{y}/{x}', 196 | attr='Esri', 197 | name='Esri Physical Map', 198 | overlay=True, 199 | control=True 200 | ), 201 | 202 | 'Bing VirtualEarth': folium.TileLayer( 203 | tiles='http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1', 204 | attr='Microsoft', 205 | name='Bing VirtualEarth', 206 | overlay=True, 207 | control=True 208 | ), 209 | 210 | '3DEP Elevation': folium.WmsTileLayer( 211 | url='https://elevation.nationalmap.gov/arcgis/services/3DEPElevation/ImageServer/WMSServer?', 212 | layers = '3DEPElevation:None', 213 | attr='USGS', 214 | name='3DEP Elevation', 215 | overlay=True, 216 | control=True 217 | ), 218 | 219 | 'NAIP Imagery': folium.WmsTileLayer( 220 | url='https://services.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?', 221 | layers = '0', 222 | attr='USGS', 223 | name='NAIP Imagery', 224 | overlay=True, 225 | control=True 226 | ), 227 | } 228 | 229 | try: 230 | basemaps[mapTypeId].add_to(self) 231 | except: 232 | print('Basemap can only be one of "ROADMAP", "SATELLITE", "HYBRID", "TERRAIN", "NAIP", or "ESRI"') 233 | 234 | 235 | folium.Map.setOptions = setOptions 236 | 237 | # show the map 238 | 239 | 240 | 241 | def setControlVisibility(self, layerControl=True, fullscreenControl=True, latLngPopup=True): 242 | 243 | if layerControl: 244 | folium.LayerControl().add_to(self) 245 | if fullscreenControl: 246 | plugins.Fullscreen().add_to(self) 247 | if latLngPopup: 248 | folium.LatLngPopup().add_to(self) 249 | 250 | 251 | folium.Map.setControlVisibility = setControlVisibility 252 | 253 | 254 | def setCenter(self, lon, lat, zoom=10): 255 | self.fit_bounds([[lat, lon], [lat, lon]], max_zoom=zoom) 256 | 257 | 258 | folium.Map.setCenter = setCenter 259 | 260 | 261 | def centerObject(self, ee_object, zoom=10): 262 | # try: 263 | 264 | lat = 0 265 | lon = 0 266 | bounds = [[lat, lon], [lat, lon]] 267 | if isinstance(ee_object, ee.geometry.Geometry): 268 | centroid = ee_object.centroid() 269 | lon, lat = centroid.getInfo()['coordinates'] 270 | bounds = [[lat, lon], [lat, lon]] 271 | elif isinstance(ee_object, ee.featurecollection.FeatureCollection): 272 | centroid = ee_object.geometry().centroid() 273 | lon, lat = centroid.getInfo()['coordinates'] 274 | bounds = [[lat, lon], [lat, lon]] 275 | elif isinstance(ee_object, ee.image.Image): 276 | geometry = ee_object.geometry() 277 | coordinates = geometry.getInfo()['coordinates'][0] 278 | bounds = [coordinates[0][::-1], coordinates[2][::-1]] 279 | elif isinstance(ee_object, ee.imagecollection.ImageCollection): 280 | geometry = ee_object.geometry() 281 | coordinates = geometry.getInfo()['coordinates'][0] 282 | bounds = [coordinates[0][::-1], coordinates[2][::-1]] 283 | else: 284 | bounds = [[0, 0], [0, 0]] 285 | 286 | self.fit_bounds(bounds, max_zoom=zoom) 287 | 288 | # except: 289 | # print("Failed to centerObject") 290 | 291 | 292 | folium.Map.centerObject = centerObject 293 | 294 | 295 | if __name__ == '__main__': 296 | 297 | ee.Initialize() 298 | 299 | dem = ee.Image('USGS/SRTMGL1_003') 300 | # Set visualization parameters. 301 | vis_params = { 302 | 'min': 0, 303 | 'max': 4000, 304 | 'palette': ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5']} 305 | 306 | # Create a folium map object. 307 | Map = folium.Map(location=[20, 0], zoom_start=3, height=500) 308 | 309 | # # Add custom basemaps 310 | # basemaps['Google Maps'].add_to(my_map) 311 | # basemaps['Google Satellite Hybrid'].add_to(my_map) 312 | 313 | # Add the elevation model to the map object. 314 | Map.addLayer(dem.updateMask(dem.gt(0)), vis_params, 'DEM') 315 | 316 | # Add a layer control panel to the map. 317 | Map.add_child(folium.LayerControl()) 318 | 319 | # Add fullscreen button 320 | plugins.Fullscreen().add_to(Map) 321 | 322 | # Display the map. 323 | # display(my_map) 324 | Map 325 | print("Testing done") 326 | -------------------------------------------------------------------------------- /geehydro/utilities.py: -------------------------------------------------------------------------------- 1 | import ee 2 | 3 | # Compute area in square meters 4 | 5 | def vecArea(f): 6 | # Compute area in square meters. Convert to hectares. 7 | areaSqm = f.area() 8 | # A new property called 'area' will be set on each feature. 9 | return f.set({'area': areaSqm}) 10 | 11 | 12 | def vecAreaSqkm(f): 13 | areaSqkm = f.area().divide(1000 * 1000) 14 | return f.set({'area': areaSqkm}) 15 | 16 | 17 | def vecAreaHa(f): 18 | # Compute area in square meters. Convert to hectares. 19 | areaHa = f.area(1).divide(100 * 100) 20 | 21 | # A new property called 'area' will be set on each feature. 22 | return f.set({'area': areaHa}) 23 | 24 | 25 | def getYear(date): 26 | return ee.Date(date).get('year') 27 | 28 | 29 | # Convert string to number 30 | def stringToNumber(str): 31 | return ee.Number.parse(str) 32 | 33 | 34 | # Calculate array sum 35 | def arraySum(arr): 36 | return ee.Array(arr).accum(0).get([-1]) 37 | 38 | 39 | # Calculate array mean 40 | def arrayMean(arr): 41 | sum = ee.Array(arr).accum(0).get([-1]) 42 | size = arr.length() 43 | return ee.Number(sum.divide(size)) 44 | 45 | 46 | # Create NAIP mosaic for a specified year 47 | def annualNAIP(year, geometry): 48 | start_date = ee.Date.fromYMD(year, 1, 1) 49 | end_date = ee.Date.fromYMD(year, 12, 31) 50 | collection = ee.ImageCollection('USDA/NAIP/DOQQ') \ 51 | .filterDate(start_date, end_date) \ 52 | .filterBounds(geometry) 53 | 54 | time_start = ee.Date( 55 | ee.List(collection.aggregate_array('system:time_start')).sort().get(0)) 56 | time_end = ee.Date( 57 | ee.List(collection.aggregate_array('system:time_end')).sort().get(-1)) 58 | image = ee.Image(collection.mosaic().clip(geometry)) 59 | NDWI = ee.Image(image).normalizedDifference( 60 | ['G', 'N']).select(['nd'], ['ndwi']) 61 | NDVI = ee.Image(image).normalizedDifference( 62 | ['N', 'R']).select(['nd'], ['ndvi']) 63 | image = image.addBands(NDWI) 64 | image = image.addBands(NDVI) 65 | return image.set({'system:time_start': time_start, 'system:time_end': time_end}) 66 | 67 | 68 | # Find all available NAIP images for a geometry 69 | def findNAIP(geometry): 70 | init_collection = ee.ImageCollection('USDA/NAIP/DOQQ') \ 71 | .filterBounds(geometry) \ 72 | .filterDate('2009-01-01', '2018-12-31') \ 73 | .filter(ee.Filter.listContains("system:band_names", "N")) 74 | 75 | yearList = ee.List(init_collection.distinct( 76 | ['system:time_start']).aggregate_array('system:time_start')) 77 | init_years = yearList.map(lambda y: ee.Date(y).get('year')) 78 | 79 | # remove duplicates 80 | init_years = ee.Dictionary(init_years.reduce( 81 | ee.Reducer.frequencyHistogram())).keys() 82 | years = init_years.map(lambda x: ee.Number.parse(x)) 83 | # years = init_years.map(lambda x: x) 84 | 85 | # Available NAIP years with NIR band 86 | def NAIPAnnual(year): 87 | start_date = ee.Date.fromYMD(year, 1, 1) 88 | end_date = ee.Date.fromYMD(year, 12, 31) 89 | collection = init_collection.filterDate(start_date, end_date) 90 | # .filterBounds(geometry) 91 | # .filter(ee.Filter.listContains("system:band_names", "N")) 92 | time_start = ee.Date( 93 | ee.List(collection.aggregate_array('system:time_start')).sort().get(0)) 94 | time_end = ee.Date( 95 | ee.List(collection.aggregate_array('system:time_end')).sort().get(-1)) 96 | col_size = collection.size() 97 | image = ee.Image(collection.mosaic().clip(geometry)) 98 | NDWI = ee.Image(image).normalizedDifference( 99 | ['G', 'N']).select(['nd'], ['ndwi']) 100 | NDVI = ee.Image(image).normalizedDifference( 101 | ['N', 'R']).select(['nd'], ['ndvi']) 102 | image = image.addBands(NDWI) 103 | image = image.addBands(NDVI) 104 | return image.set({'system:time_start': time_start, 'system:time_end': time_end, 'tiles': col_size}) 105 | 106 | # remove years with incomplete coverage 107 | naip = ee.ImageCollection(years.map(NAIPAnnual)) 108 | mean_size = ee.Number(naip.aggregate_mean('tiles')) 109 | total_sd = ee.Number(naip.aggregate_total_sd('tiles')) 110 | threshold = mean_size.subtract(total_sd.multiply(1)) 111 | naip = naip.filter(ee.Filter.Or(ee.Filter.gte( 112 | 'tiles', threshold), ee.Filter.gte('tiles', 15))) 113 | naip = naip.filter(ee.Filter.gte('tiles', 7)) 114 | 115 | naip_count = naip.size() 116 | naip_seq = ee.List.sequence(0, naip_count.subtract(1)) 117 | 118 | def set_index(index): 119 | img = ee.Image(naip.toList(naip_count).get(index)) 120 | return img.set({'system:uid': ee.Number(index).toUint8()}) 121 | 122 | naip = naip_seq.map(set_index) 123 | 124 | return ee.ImageCollection(naip) 125 | 126 | 127 | # Get NWI by HUC 128 | def filterNWI(HUC08_Id, geometry): 129 | nwi_asset_prefix = 'users/wqs/NWI-HU8/HU8_' 130 | nwi_asset_suffix = '_Wetlands' 131 | nwi_asset_path = nwi_asset_prefix + HUC08_Id + nwi_asset_suffix 132 | nwi_huc = ee.FeatureCollection(nwi_asset_path).filterBounds(geometry) \ 133 | .filter(ee.Filter.notEquals(**{'leftField': 'WETLAND_TY', 'rightValue': 'Riverine'})) 134 | return nwi_huc 135 | 136 | 137 | # Find HUC08 intersecting a geometry 138 | def filterHUC08(geometry): 139 | USGS_HUC08 = ee.FeatureCollection('USGS/WBD/2017/HUC08') # Subbasins 140 | HUC08 = USGS_HUC08.filterBounds(geometry) 141 | return HUC08 142 | 143 | 144 | # Find HUC10 intersecting a geometry 145 | def filterHUC10(geometry): 146 | USGS_HUC10 = ee.FeatureCollection('USGS/WBD/2017/HUC10') # Watersheds 147 | HUC10 = USGS_HUC10.filterBounds(geometry) 148 | return HUC10 149 | 150 | # Find HUC08 by HUC ID 151 | 152 | 153 | def findHUC08(HUC08_Id): 154 | USGS_HUC08 = ee.FeatureCollection('USGS/WBD/2017/HUC08') # Subbasins 155 | HUC08 = USGS_HUC08.filter(ee.Filter.eq('huc8', HUC08_Id)) 156 | return HUC08 157 | 158 | 159 | # Find HUC10 by HUC ID 160 | def findHUC10(HUC10_Id): 161 | USGS_HUC10 = ee.FeatureCollection('USGS/WBD/2017/HUC10') # Watersheds 162 | HUC10 = USGS_HUC10.filter(ee.Filter.eq('huc10', HUC10_Id)) 163 | return HUC10 164 | 165 | 166 | # find NWI by HUC08 167 | def findNWI(HUC08_Id): 168 | nwi_asset_prefix = 'users/wqs/NWI-HU8/HU8_' 169 | nwi_asset_suffix = '_Wetlands' 170 | nwi_asset_path = nwi_asset_prefix + HUC08_Id + nwi_asset_suffix 171 | nwi_huc = ee.FeatureCollection(nwi_asset_path) \ 172 | .filter(ee.Filter.notEquals(**{'leftField': 'WETLAND_TY', 'rightValue': 'Riverine'})) 173 | return nwi_huc 174 | 175 | 176 | # Extract NWI by providing a geometry 177 | def extractNWI(geometry): 178 | 179 | HUC08 = filterHUC08(geometry) 180 | HUC_list = ee.List(HUC08.aggregate_array('huc8')).getInfo() 181 | # print('Intersecting HUC08 IDs:', HUC_list) 182 | nwi = ee.FeatureCollection(HUC_list.map(findNWI)).flatten() 183 | return nwi.filterBounds(geometry) 184 | 185 | # NWI legend: https://www.fws.gov/wetlands/Data/Mapper-Wetlands-Legend.html 186 | 187 | 188 | def nwi_add_color(fc): 189 | emergent = ee.FeatureCollection( 190 | fc.filter(ee.Filter.eq('WETLAND_TY', 'Freshwater Emergent Wetland'))) 191 | emergent = emergent.map(lambda f: f.set( 192 | 'R', 127).set('G', 195).set('B', 28)) 193 | # print(emergent.first()) 194 | 195 | forested = fc.filter(ee.Filter.eq( 196 | 'WETLAND_TY', 'Freshwater Forested/Shrub Wetland')) 197 | forested = forested.map(lambda f: f.set('R', 0).set('G', 136).set('B', 55)) 198 | 199 | pond = fc.filter(ee.Filter.eq('WETLAND_TY', 'Freshwater Pond')) 200 | pond = pond.map(lambda f: f.set('R', 104).set('G', 140).set('B', 192)) 201 | 202 | lake = fc.filter(ee.Filter.eq('WETLAND_TY', 'Lake')) 203 | lake = lake.map(lambda f: f.set('R', 19).set('G', 0).set('B', 124)) 204 | 205 | riverine = fc.filter(ee.Filter.eq('WETLAND_TY', 'Riverine')) 206 | riverine = riverine.map(lambda f: f.set( 207 | 'R', 1).set('G', 144).set('B', 191)) 208 | 209 | fc = ee.FeatureCollection(emergent.merge( 210 | forested).merge(pond).merge(lake).merge(riverine)) 211 | 212 | # base = ee.Image(0).mask(0).toInt8() 213 | base = ee.Image().byte() 214 | img = base.paint(fc, 'R') \ 215 | .addBands(base.paint(fc, 'G') 216 | .addBands(base.paint(fc, 'B'))) 217 | return img 218 | 219 | 220 | # calculate total image area (unit: m2) 221 | def imageArea(img, geometry, scale): 222 | pixelArea = img.Add(ee.Image(1)).multiply( 223 | ee.Image.pixelArea()) 224 | imgArea = pixelArea.reduceRegion(**{ 225 | 'geometry': geometry, 226 | 'reducer': ee.Reducer.sum(), 227 | 'scale': scale, 228 | 'maxPixels': 1e9 229 | }) 230 | return imgArea 231 | 232 | 233 | # calculate total image area (unit: ha) 234 | def imageAreaHa(img, geometry, scale): 235 | pixelArea = img.Add(ee.Image(1)).multiply( 236 | ee.Image.pixelArea()).divide(10000) 237 | imgArea = pixelArea.reduceRegion(**{ 238 | 'geometry': geometry, 239 | 'reducer': ee.Reducer.sum(), 240 | 'scale': scale, 241 | 'maxPixels': 1e9 242 | }) 243 | return imgArea 244 | 245 | 246 | # get highest value 247 | def maxValue(img, scale=30): 248 | max_value = img.reduceRegion(**{ 249 | 'reducer': ee.Reducer.max(), 250 | 'geometry': img.geometry(), 251 | 'scale': scale, 252 | 'maxPixels': 1e9 253 | }) 254 | return max_value 255 | 256 | 257 | # get lowest value 258 | def minValue(img, scale=30): 259 | min_value = img.reduceRegion(**{ 260 | 'reducer': ee.Reducer.min(), 261 | 'geometry': img.geometry(), 262 | 'scale': scale, 263 | 'maxPixels': 1e9 264 | }) 265 | return min_value 266 | 267 | 268 | # get mean value 269 | def meanValue(img, scale=30): 270 | mean_value = img.reduceRegion(**{ 271 | 'reducer': ee.Reducer.mean(), 272 | 'geometry': img.geometry(), 273 | 'scale': scale, 274 | 'maxPixels': 1e9 275 | }) 276 | return mean_value 277 | 278 | 279 | # get standard deviation 280 | def stdValue(img, scale=30): 281 | std_value = img.reduceRegion(**{ 282 | 'reducer': ee.Reducer.stdDev(), 283 | 'geometry': img.geometry(), 284 | 'scale': scale, 285 | 'maxPixels': 1e9 286 | }) 287 | return std_value 288 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | earthengine-api 2 | folium 3 | click -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | pip 2 | bump2version 3 | wheel 4 | watchdog 5 | flake8 6 | tox 7 | coverage 8 | Sphinx 9 | twine 10 | Click 11 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.2.0 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | search = version='{current_version}' 8 | replace = version='{new_version}' 9 | 10 | [bumpversion:file:geehydro/__init__.py] 11 | search = __version__ = '{current_version}' 12 | replace = __version__ = '{new_version}' 13 | 14 | [bdist_wheel] 15 | universal = 1 16 | 17 | [flake8] 18 | exclude = docs 19 | 20 | [aliases] 21 | 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """The setup script.""" 5 | import os, platform 6 | from os import path as op 7 | import io 8 | from setuptools import setup, find_packages 9 | 10 | with open('README.rst') as readme_file: 11 | readme = readme_file.read() 12 | 13 | with open('HISTORY.rst') as history_file: 14 | history = history_file.read() 15 | 16 | here = op.abspath(op.dirname(__file__)) 17 | 18 | # get the dependencies and installs 19 | with io.open(op.join(here, 'requirements.txt'), encoding='utf-8') as f: 20 | all_reqs = f.read().split('\n') 21 | 22 | install_requires = [x.strip() for x in all_reqs if 'git+' not in x] 23 | dependency_links = [x.strip().replace('git+', '') for x in all_reqs if 'git+' not in x] 24 | 25 | 26 | requirements = ['Click>=7.0', ] 27 | 28 | setup_requirements = [ ] 29 | 30 | test_requirements = [ ] 31 | 32 | setup( 33 | author="Qiusheng Wu", 34 | author_email='giswqs@gmail.com', 35 | python_requires='>=3.5', 36 | classifiers=[ 37 | 'Development Status :: 2 - Pre-Alpha', 38 | 'Intended Audience :: Developers', 39 | 'License :: OSI Approved :: MIT License', 40 | 'Natural Language :: English', 41 | 'Programming Language :: Python :: 3.5', 42 | 'Programming Language :: Python :: 3.6', 43 | 'Programming Language :: Python :: 3.7', 44 | 'Programming Language :: Python :: 3.8', 45 | ], 46 | description="Python package for mapping inundation dynamics using Google Earth Engine", 47 | entry_points={ 48 | 'console_scripts': [ 49 | 'geehydro=geehydro.cli:main', 50 | ], 51 | }, 52 | install_requires=install_requires, 53 | dependency_links=dependency_links, 54 | license="MIT license", 55 | long_description=readme + '\n\n' + history, 56 | include_package_data=True, 57 | keywords='geehydro', 58 | name='geehydro', 59 | packages=find_packages(include=['geehydro', 'geehydro.*']), 60 | setup_requires=setup_requirements, 61 | test_suite='tests', 62 | tests_require=test_requirements, 63 | url='https://github.com/giswqs/geehydro', 64 | version='0.2.0', 65 | zip_safe=False, 66 | ) 67 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Unit test package for geehydro.""" 4 | -------------------------------------------------------------------------------- /tests/test_geehydro.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """Tests for `geehydro` package.""" 5 | 6 | 7 | import unittest 8 | from click.testing import CliRunner 9 | 10 | # from geehydro import geehydro 11 | from geehydro import cli 12 | 13 | 14 | class TestGeehydro(unittest.TestCase): 15 | """Tests for `geehydro` package.""" 16 | 17 | def setUp(self): 18 | """Set up test fixtures, if any.""" 19 | 20 | def tearDown(self): 21 | """Tear down test fixtures, if any.""" 22 | 23 | def test_000_something(self): 24 | """Test something.""" 25 | 26 | def test_command_line_interface(self): 27 | """Test the CLI.""" 28 | runner = CliRunner() 29 | result = runner.invoke(cli.main) 30 | assert result.exit_code == 0 31 | assert 'geehydro.cli.main' in result.output 32 | help_result = runner.invoke(cli.main, ['--help']) 33 | assert help_result.exit_code == 0 34 | assert '--help Show this message and exit.' in help_result.output 35 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py35, py36, py37, py38, flake8 3 | 4 | [travis] 5 | python = 6 | 3.8: py38 7 | 3.7: py37 8 | 3.6: py36 9 | 3.5: py35 10 | 2.7: py27 11 | 12 | [testenv:flake8] 13 | basepython = python 14 | deps = flake8 15 | commands = flake8 geehydro 16 | 17 | [testenv] 18 | setenv = 19 | PYTHONPATH = {toxinidir} 20 | 21 | commands = python setup.py test 22 | --------------------------------------------------------------------------------