├── VERSION.txt ├── hydrobox ├── utils │ ├── __init__.py │ ├── typing.py │ └── decorators.py ├── preprocessing │ ├── __init__.py │ ├── union.py │ └── scale.py ├── discharge │ ├── __init__.py │ ├── indices.py │ └── catchment.py ├── stats │ ├── __init__.py │ ├── rolling.py │ └── regression.py ├── __init__.py ├── data │ ├── __init__.py │ ├── sample_sr.csv │ ├── pan_sample.csv │ └── sample_lr.csv ├── plotting │ ├── __init__.py │ ├── variogram.py │ ├── _backend.py │ ├── kriging.py │ ├── flow_duration_curve.py │ └── regime.py ├── geostat │ ├── typing.py │ ├── __init__.py │ ├── variogram.py │ ├── gridsearch.py │ └── kriging.py └── tests │ └── test_geostat.py ├── doc ├── gen_modules │ ├── backreferences │ │ ├── hydrobox.geostat.examples │ │ ├── hydrobox.geostat.simple_kriging.examples │ │ ├── hydrobox.geostat.ext_drift_kriging.examples │ │ ├── hydrobox.geostat.universal_kriging.examples │ │ ├── hydrobox.data.pancake.examples │ │ ├── hydrobox.plotting_backend.examples │ │ ├── hydrobox.geostat.variogram.examples │ │ ├── hydrobox.geostat.gridsearch.examples │ │ └── hydrobox.geostat.ordinary_kriging.examples │ ├── hydrobox.geostat.variogram.rst │ ├── hydrobox.geostat.gridsearch.rst │ ├── hydrobox.geostat.simple_kriging.rst │ ├── hydrobox.geostat.ordinary_kriging.rst │ ├── hydrobox.geostat.ext_drift_kriging.rst │ └── hydrobox.geostat.universal_kriging.rst ├── auto_examples │ ├── geostat │ │ ├── plot_gridsearch.py.md5 │ │ ├── plot_variogram.py.md5 │ │ ├── plot_ordinary_kriging.py.md5 │ │ ├── plot_gridsearch_codeobj.pickle │ │ ├── plot_variogram_codeobj.pickle │ │ ├── plot_ordinary_kriging_codeobj.pickle │ │ ├── images │ │ │ ├── sphx_glr_plot_variogram_001.png │ │ │ ├── sphx_glr_plot_variogram_002.png │ │ │ ├── sphx_glr_plot_gridsearch_001.png │ │ │ ├── sphx_glr_plot_ordinary_kriging_001.png │ │ │ ├── thumb │ │ │ │ ├── sphx_glr_plot_variogram_thumb.png │ │ │ │ ├── sphx_glr_plot_gridsearch_thumb.png │ │ │ │ └── sphx_glr_plot_ordinary_kriging_thumb.png │ │ │ ├── sphx_glr_plot_gridsearch_001.html │ │ │ └── sphx_glr_plot_variogram_001.html │ │ ├── sg_execution_times.rst │ │ ├── plot_ordinary_kriging.py │ │ ├── plot_variogram.py │ │ ├── plot_gridsearch.py │ │ ├── plot_ordinary_kriging.ipynb │ │ ├── plot_ordinary_kriging.rst │ │ ├── plot_variogram.ipynb │ │ ├── plot_gridsearch.ipynb │ │ ├── plot_gridsearch.rst │ │ └── plot_variogram.rst │ ├── auto_examples_python.zip │ ├── auto_examples_jupyter.zip │ └── index.rst ├── toolboxes │ ├── geostat.rst │ ├── index.rst │ └── gen_modules │ │ ├── hydrobox.geostat.variogram.rst │ │ ├── hydrobox.geostat.gridsearch.rst │ │ ├── hydrobox.geostat.simple_kriging.rst │ │ ├── hydrobox.geostat.ordinary_kriging.rst │ │ ├── hydrobox.geostat.ext_drift_kriging.rst │ │ └── hydrobox.geostat.universal_kriging.rst ├── Makefile ├── make.bat ├── index.rst └── conf.py ├── examples ├── README.rst └── geostat │ ├── README.rst │ ├── plot_ordinary_kriging.py │ ├── plot_variogram.py │ └── plot_gridsearch.py ├── requirements.txt ├── MANIFEST.in ├── classifiers.txt ├── .coveragerc ├── setup.py ├── LICENSE ├── .github └── workflows │ └── main.yaml ├── .gitignore └── README.md /VERSION.txt: -------------------------------------------------------------------------------- 1 | 0.2.0 2 | -------------------------------------------------------------------------------- /hydrobox/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hydrobox/preprocessing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.examples: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.simple_kriging.examples: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.ext_drift_kriging.examples: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.universal_kriging.examples: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_gridsearch.py.md5: -------------------------------------------------------------------------------- 1 | 5afe77ecb8029bad8b45f1b6caeeed19 -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_variogram.py.md5: -------------------------------------------------------------------------------- 1 | e865bb35235811251eb818a95e29a994 -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_ordinary_kriging.py.md5: -------------------------------------------------------------------------------- 1 | 0edca8dd2db51a6491a99f77651997f7 -------------------------------------------------------------------------------- /hydrobox/discharge/__init__.py: -------------------------------------------------------------------------------- 1 | from .catchment import regime, flow_duration_curve 2 | from . import indices -------------------------------------------------------------------------------- /hydrobox/stats/__init__.py: -------------------------------------------------------------------------------- 1 | from .rolling import moving_window 2 | from .regression import linear_regression -------------------------------------------------------------------------------- /doc/toolboxes/geostat.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Geostatistics 3 | ============= 4 | 5 | .. automodule:: hydrobox.geostat -------------------------------------------------------------------------------- /doc/auto_examples/auto_examples_python.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/auto_examples_python.zip -------------------------------------------------------------------------------- /examples/README.rst: -------------------------------------------------------------------------------- 1 | Hydrobox Examples 2 | ================= 3 | 4 | This gallery collects example scripts for most functions in hydrobox. -------------------------------------------------------------------------------- /doc/auto_examples/auto_examples_jupyter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/auto_examples_jupyter.zip -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | pandas 4 | matplotlib 5 | plotly 6 | colorcet 7 | scikit-learn 8 | scikit-gstat>=0.5.4 9 | gstools>=1.3.0 -------------------------------------------------------------------------------- /examples/geostat/README.rst: -------------------------------------------------------------------------------- 1 | Geostatistics Toolbox 2 | --------------------- 3 | 4 | The following examples demonstrate the usage of the geostatistics toolbox. -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_gridsearch_codeobj.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/plot_gridsearch_codeobj.pickle -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_variogram_codeobj.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/plot_variogram_codeobj.pickle -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_ordinary_kriging_codeobj.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/plot_ordinary_kriging_codeobj.pickle -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/sphx_glr_plot_variogram_001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/sphx_glr_plot_variogram_001.png -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/sphx_glr_plot_variogram_002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/sphx_glr_plot_variogram_002.png -------------------------------------------------------------------------------- /doc/toolboxes/index.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Toolboxes Overview 3 | ================== 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | :caption: All toolboxes 8 | 9 | geostat -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/sphx_glr_plot_gridsearch_001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/sphx_glr_plot_gridsearch_001.png -------------------------------------------------------------------------------- /doc/gen_modules/hydrobox.geostat.variogram.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.variogram 2 | ========================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: variogram -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include VERSION.txt 3 | include requirements.txt 4 | include LICENSE 5 | include classifiers.txt 6 | graft hydrobox/data/*.csv 7 | graft hydrobox/data/*.txt -------------------------------------------------------------------------------- /doc/gen_modules/hydrobox.geostat.gridsearch.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.gridsearch 2 | =========================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: gridsearch -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/sphx_glr_plot_ordinary_kriging_001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/sphx_glr_plot_ordinary_kriging_001.png -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/thumb/sphx_glr_plot_variogram_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/thumb/sphx_glr_plot_variogram_thumb.png -------------------------------------------------------------------------------- /doc/toolboxes/gen_modules/hydrobox.geostat.variogram.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.variogram 2 | ========================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: variogram -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/thumb/sphx_glr_plot_gridsearch_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/thumb/sphx_glr_plot_gridsearch_thumb.png -------------------------------------------------------------------------------- /doc/toolboxes/gen_modules/hydrobox.geostat.gridsearch.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.gridsearch 2 | =========================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: gridsearch -------------------------------------------------------------------------------- /doc/gen_modules/hydrobox.geostat.simple_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.simple\_kriging 2 | ================================ 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: simple_kriging -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/thumb/sphx_glr_plot_ordinary_kriging_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VForWaTer/hydrobox/HEAD/doc/auto_examples/geostat/images/thumb/sphx_glr_plot_ordinary_kriging_thumb.png -------------------------------------------------------------------------------- /doc/gen_modules/hydrobox.geostat.ordinary_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.ordinary\_kriging 2 | ================================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: ordinary_kriging -------------------------------------------------------------------------------- /doc/toolboxes/gen_modules/hydrobox.geostat.simple_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.simple\_kriging 2 | ================================ 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: simple_kriging -------------------------------------------------------------------------------- /doc/gen_modules/hydrobox.geostat.ext_drift_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.ext\_drift\_kriging 2 | ==================================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: ext_drift_kriging -------------------------------------------------------------------------------- /doc/gen_modules/hydrobox.geostat.universal_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.universal\_kriging 2 | =================================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: universal_kriging -------------------------------------------------------------------------------- /doc/toolboxes/gen_modules/hydrobox.geostat.ordinary_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.ordinary\_kriging 2 | ================================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: ordinary_kriging -------------------------------------------------------------------------------- /doc/toolboxes/gen_modules/hydrobox.geostat.ext_drift_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.ext\_drift\_kriging 2 | ==================================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: ext_drift_kriging -------------------------------------------------------------------------------- /doc/toolboxes/gen_modules/hydrobox.geostat.universal_kriging.rst: -------------------------------------------------------------------------------- 1 | hydrobox.geostat.universal\_kriging 2 | =================================== 3 | 4 | .. currentmodule:: hydrobox.geostat 5 | 6 | .. autofunction:: universal_kriging -------------------------------------------------------------------------------- /hydrobox/utils/typing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Typing 3 | ====== 4 | 5 | The typing utils package collects some more complex types 6 | of input and output data in hydrobox. 7 | """ 8 | from typing import Union, Callable, Literal 9 | # geostat Package 10 | -------------------------------------------------------------------------------- /classifiers.txt: -------------------------------------------------------------------------------- 1 | Development Status :: 4 - Beta 2 | Intended Audience :: Science/Research 3 | License :: OSI Approved :: MIT License 4 | Natural Language :: English 5 | Programming Language :: Python :: 3.8 6 | Programming Language :: Python :: 3.9 7 | Topic :: Scientific/Engineering :: Information Analysis 8 | -------------------------------------------------------------------------------- /hydrobox/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # Python 3.3 is not supported. 4 | if sys.version_info < (3, 8): 5 | raise ImportError('Python < 3.8 is not supported') 6 | 7 | 8 | import hydrobox.utils 9 | from hydrobox.plotting._backend import plotting_backend 10 | import hydrobox.geostat 11 | 12 | __version__ = '0.2.0' 13 | __plot_backend__ = 'matplotlib' 14 | -------------------------------------------------------------------------------- /hydrobox/data/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pandas as pd 3 | 4 | 5 | def __read(fname): 6 | df = pd.read_csv(os.path.join(os.path.dirname(__file__), fname)) 7 | return df 8 | 9 | 10 | def pancake(): 11 | return __read('pan_sample.csv') 12 | 13 | 14 | def sr(): 15 | return __read('sample_sr') 16 | 17 | 18 | def lr(): 19 | return __read('sample_lr') -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | hydrobox/tests/* 4 | hydrobox/plotting/* 5 | doc/* 6 | examples/* 7 | setup.py 8 | */typing.py 9 | 10 | [report] 11 | exclude_lines = 12 | pragma: no cover 13 | def __repr__ 14 | def __str__ 15 | if self\.debug: 16 | if False: 17 | if 0: 18 | raise AssertionError 19 | raise NotImplementedError 20 | if __name__ == .__main__.: -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.data.pancake.examples: -------------------------------------------------------------------------------- 1 | 2 | 3 | Examples using ``hydrobox.data.pancake`` 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | 6 | .. raw:: html 7 | 8 |
9 | 10 | .. only:: html 11 | 12 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_variogram_thumb.png 13 | :alt: Estimate a Variogram 14 | 15 | :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 16 | 17 | .. raw:: html 18 | 19 |
20 | 21 | .. only:: not html 22 | 23 | * :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 24 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.plotting_backend.examples: -------------------------------------------------------------------------------- 1 | 2 | 3 | Examples using ``hydrobox.plotting_backend`` 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | 6 | .. raw:: html 7 | 8 |
9 | 10 | .. only:: html 11 | 12 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_variogram_thumb.png 13 | :alt: Estimate a Variogram 14 | 15 | :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 16 | 17 | .. raw:: html 18 | 19 |
20 | 21 | .. only:: not html 22 | 23 | * :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 24 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 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 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.variogram.examples: -------------------------------------------------------------------------------- 1 | 2 | 3 | Examples using ``hydrobox.geostat.variogram`` 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | 6 | .. raw:: html 7 | 8 |
9 | 10 | .. only:: html 11 | 12 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_variogram_thumb.png 13 | :alt: Estimate a Variogram 14 | 15 | :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 16 | 17 | .. raw:: html 18 | 19 |
20 | 21 | .. only:: not html 22 | 23 | * :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 24 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.gridsearch.examples: -------------------------------------------------------------------------------- 1 | 2 | 3 | Examples using ``hydrobox.geostat.gridsearch`` 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | 6 | .. raw:: html 7 | 8 |
9 | 10 | .. only:: html 11 | 12 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_gridsearch_thumb.png 13 | :alt: GridSearch optimization 14 | 15 | :ref:`sphx_glr_auto_examples_geostat_plot_gridsearch.py` 16 | 17 | .. raw:: html 18 | 19 |
20 | 21 | .. only:: not html 22 | 23 | * :ref:`sphx_glr_auto_examples_geostat_plot_gridsearch.py` 24 | -------------------------------------------------------------------------------- /doc/gen_modules/backreferences/hydrobox.geostat.ordinary_kriging.examples: -------------------------------------------------------------------------------- 1 | 2 | 3 | Examples using ``hydrobox.geostat.ordinary_kriging`` 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | 6 | .. raw:: html 7 | 8 |
9 | 10 | .. only:: html 11 | 12 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_ordinary_kriging_thumb.png 13 | :alt: Ordinary Kriging 14 | 15 | :ref:`sphx_glr_auto_examples_geostat_plot_ordinary_kriging.py` 16 | 17 | .. raw:: html 18 | 19 |
20 | 21 | .. only:: not html 22 | 23 | * :ref:`sphx_glr_auto_examples_geostat_plot_ordinary_kriging.py` 24 | -------------------------------------------------------------------------------- /hydrobox/plotting/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Plotting routines 3 | ----------------- 4 | 5 | Some of the tools, which have results plot may call a 6 | common interface of the `hydrobox.plotting` submodule. 7 | These interfacing functions in turn will either call 8 | a matplotlib, bokeh or plotly implementation. 9 | 10 | This is primarily implemented for convenience. The 11 | usecase in V-FOR-WaTer, the context at which this 12 | library is developed is to have a pythonic tool able to 13 | handle matplotlib plots, but also get interactive HTML 14 | versions of such by using bokeh or plotly. 15 | 16 | .. warning:: 17 | 18 | This feature is experimental and may be completely or 19 | partly deprecated. Either bokeh or plotly may be removed 20 | on any version < 1.0.0 in favor of the other. 21 | 22 | """ 23 | from ._backend import plotting_backend, plot_function_loader 24 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | import sys 3 | 4 | if sys.version_info < (3, 3): 5 | sys.exit('Python < 3.3 is not supported') 6 | 7 | with open('requirements.txt') as fs: 8 | REQUIREMENTS = fs.read().strip().split('\n') 9 | 10 | with open('VERSION.txt') as fs: 11 | VERSION = fs.read().strip() 12 | 13 | with open('classifiers.txt') as fs: 14 | CLASSIFIERS = fs.read().strip().split('\n') 15 | 16 | 17 | def readme(): 18 | with open('README.md') as fs: 19 | return fs.read() 20 | 21 | setup(name='hydrobox', 22 | version=VERSION, 23 | license='MIT', 24 | description='Hydrological toolbox build on top of scipy and pandas', 25 | long_description=readme(), 26 | classifiers=CLASSIFIERS, 27 | author='Mirko Maelicke', 28 | author_email='mirko.maelicke@kit.edu', 29 | install_requires=REQUIREMENTS, 30 | test_suite='nose.collector', 31 | tests_require=['nose'], 32 | packages=find_packages(), 33 | include_package_data=True, 34 | zip_safe=False 35 | ) -------------------------------------------------------------------------------- /doc/auto_examples/geostat/sg_execution_times.rst: -------------------------------------------------------------------------------- 1 | 2 | :orphan: 3 | 4 | .. _sphx_glr_auto_examples_geostat_sg_execution_times: 5 | 6 | Computation times 7 | ================= 8 | **00:15.624** total execution time for **auto_examples_geostat** files: 9 | 10 | +-----------------------------------------------------------------------------------------------+-----------+--------+ 11 | | :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` (``plot_variogram.py``) | 00:15.624 | 0.0 MB | 12 | +-----------------------------------------------------------------------------------------------+-----------+--------+ 13 | | :ref:`sphx_glr_auto_examples_geostat_plot_gridsearch.py` (``plot_gridsearch.py``) | 00:00.000 | 0.0 MB | 14 | +-----------------------------------------------------------------------------------------------+-----------+--------+ 15 | | :ref:`sphx_glr_auto_examples_geostat_plot_ordinary_kriging.py` (``plot_ordinary_kriging.py``) | 00:00.000 | 0.0 MB | 16 | +-----------------------------------------------------------------------------------------------+-----------+--------+ 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 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 | -------------------------------------------------------------------------------- /hydrobox/geostat/typing.py: -------------------------------------------------------------------------------- 1 | from typing import Union, Callable, Literal 2 | import numpy as np 3 | 4 | # some typings 5 | Estimator = Union[ 6 | Literal['matheron','cressie', 'dowd''genton', 'entropy', 'minmax', 'percentile'], 7 | Callable[[np.ndarray], float] 8 | ] 9 | 10 | Model = Union[ 11 | Literal['spherical', 'exponential', 'gaussian', 'matern', 'cubic', 'stable'], 12 | Callable[[float, float], float], 13 | Callable[[float, float, float], float], 14 | Callable[[float, float, float, float], float] 15 | ] 16 | 17 | DistFunc = Literal[ 18 | 'braycurtis', 'canberra', 'chebyshev', 'cityblock', 'correlation', 'cosine', 'dice', 19 | 'euclidean', 'hamming', 'jaccard', 'jensenshannon', 'kulsinski', 'mahalanobis', 20 | 'matching', 'minkowski', 'rogerstanimoto', 'russellrao', 'seuclidean', 21 | 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule'], 22 | 23 | BinFunc = Literal['even', 'uniform', 'sqrt', 'scott', 'sturge', 'kmean', 'ward', 'fd', 'doane'] 24 | 25 | FitMethod = Literal['trf', 'lm', 'ml', 'custom'] 26 | 27 | FitSigma = Union[None, np.ndarray, Literal['linear', 'sqrt', 'sq', 'exp']] 28 | 29 | Maxlag = Union[None, Literal['mean', 'median'], int, float] -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. HydroBox documentation master file, created by 2 | sphinx-quickstart on Tue May 4 09:33:00 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to HydroBox 7 | =================== 8 | 9 | .. note:: 10 | Major parts of the toolbox are currently re-written. Most interfaces of 11 | any function of version < 0.2 will most likely not work anymore. 12 | The aim is to produce a unified interface for hydrobox. 13 | Secondly, hydrobox is mainly pushed to reuse other Python packages within 14 | this scope, instead of re-implementing functions that are already there. 15 | 16 | .. toctree:: 17 | :hidden: 18 | :maxdepth: 1 19 | :caption: Contents: 20 | 21 | toolboxes/index 22 | auto_examples/index 23 | 24 | Installation 25 | ============ 26 | 27 | PyPI 28 | ---- 29 | 30 | Install hydrobox from the Python Pachage Index like: 31 | 32 | .. code-block:: bash 33 | 34 | pip install hydrobox 35 | 36 | Github 37 | ------ 38 | 39 | You can install hydrobox from source like: 40 | 41 | .. code-block:: bash 42 | 43 | git clone git@github.com:vforwater/hydrobox 44 | cd hydrobox 45 | pip install -e . -------------------------------------------------------------------------------- /hydrobox/plotting/variogram.py: -------------------------------------------------------------------------------- 1 | from skgstat.plotting import backend 2 | from skgstat import Variogram 3 | 4 | def __plot(variogram: Variogram, plot_type: str, **kwargs): 5 | # always suppress sho 6 | kwargs['show'] = False 7 | 8 | # get the figure 9 | if plot_type == 'plot': 10 | fig = variogram.plot(**kwargs) 11 | elif plot_type == 'distance_difference': 12 | fig = variogram.distance_difference_plot(**kwargs) 13 | elif plot_type == 'location_trend': 14 | fig = variogram.location_trend(**kwargs) 15 | elif plot_type == 'scattergram': 16 | fig = variogram.scattergram(**kwargs) 17 | else: 18 | raise ValueError(f"Plot type '{plot_type}' not supported.") 19 | 20 | return fig 21 | 22 | 23 | def _plot_matplotlib(func_args, plot_args): 24 | # set matplotlib backend 25 | backend('matplotlib') 26 | 27 | # get the variogram 28 | variogram = func_args['variogram'] 29 | plot_type = func_args.get('plot_type', 'plot') 30 | 31 | return __plot(variogram, plot_type, **plot_args) 32 | 33 | 34 | def _plot_plotly(func_args, plot_args): 35 | # set matplotlib backend 36 | backend('plotly') 37 | 38 | # get the variogram 39 | variogram = func_args['variogram'] 40 | plot_type = func_args.get('plot_type', 'plot') 41 | 42 | return __plot(variogram, plot_type, **plot_args) 43 | -------------------------------------------------------------------------------- /hydrobox/discharge/indices.py: -------------------------------------------------------------------------------- 1 | """ 2 | Common indices frequently used to describe discharge measurements in a single 3 | coefficient. 4 | 5 | """ 6 | import numpy as np 7 | import pandas as pd 8 | 9 | 10 | def richards_baker(x): 11 | r"""Richards-Baker Flashiness Index 12 | 13 | Calculates the Richards-Baker Flashiness index (RB Index), which is a 14 | extension of the Richards Pathlengh index. In contrast to the Pathlength 15 | of a signal, the R-B Index is relative to the total discharge and 16 | independend of the chosen unit. 17 | 18 | Parameters 19 | ---------- 20 | x : numpy.ndarray, pd.Series 21 | The discharge input values. 22 | 23 | Returns 24 | ------- 25 | numpy.ndarray 26 | 27 | Notes 28 | ----- 29 | The Richards-Baker Flashiness Index [2]_ is defined as: 30 | 31 | .. math:: 32 | 33 | {RBI} = \frac{\sum_{i=1}^{n}|q_i - q_{i-1}|}{\sum_{i=1}^{n} q_i} 34 | 35 | 36 | 37 | References 38 | ---------- 39 | .. [2] Baker D.B., P. Richards, T.T. Loftus, J.W. Kramer. A new 40 | flashiness index: characteristics and applications to midwestern 41 | rivers and streams. JAWRA Journal of the American Water Resources 42 | Association, 40(2), 503-522, 2004. 43 | 44 | """ 45 | # convert Series 46 | if isinstance(x, pd.Series): 47 | x = x.values 48 | 49 | nominator = np.sum(np.fromiter( 50 | (np.abs(x[i] - x[i -1]) for i in range(1,len(x))), 51 | dtype=x.dtype)) 52 | 53 | return nominator / np.sum(x[1:]) 54 | -------------------------------------------------------------------------------- /examples/geostat/plot_ordinary_kriging.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ordinary Kriging 3 | ================ 4 | 5 | With the help of a variogram that describes spatial properties of 6 | a sample, the sample can be interpolated. 7 | 8 | """ 9 | from time import time 10 | import plotly 11 | import hydrobox 12 | from hydrobox.data import pancake 13 | from hydrobox.plotting import plotting_backend 14 | plotting_backend('plotly') 15 | 16 | #%% 17 | # Load sample data from the data sub-module 18 | 19 | df = pancake() 20 | 21 | #%% 22 | # Estimate a exponential variogram again. More details are given in the 23 | # :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` example. 24 | 25 | vario = hydrobox.geostat.variogram( 26 | coordinates=df[['x', 'y']].values, 27 | values=df.z.values, 28 | model='exponential', 29 | bin_func='kmeans', 30 | n_lags=25, 31 | return_type='object' 32 | ) 33 | 34 | #%% 35 | # Run ordinary kriging on a 100x100 grid. In this run, the result is 36 | # directly plotted. Other return types are ``'grid'``, to return the 37 | # resulting interpolated grid and kriging error grid, or ``'object'`` 38 | # to return the :class:`Krige ` class. This class 39 | # is already parameterized, but the interpolation was not yet performed. 40 | # This is most helpful if other grid should be constructed. 41 | 42 | t1 = time() 43 | fig = hydrobox.geostat.ordinary_kriging( 44 | variogram=vario, 45 | grid_resolution=100, 46 | exact=True, 47 | cond_err='nugget', 48 | return_type='plot' 49 | ) 50 | t2 = time() 51 | 52 | print('Took: %2f sec' % (t2 - t1)) 53 | 54 | # show the plot 55 | plotly.io.show(fig) -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_ordinary_kriging.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ordinary Kriging 3 | ================ 4 | 5 | With the help of a variogram that describes spatial properties of 6 | a sample, the sample can be interpolated. 7 | 8 | """ 9 | from time import time 10 | import plotly 11 | import hydrobox 12 | from hydrobox.data import pancake 13 | from hydrobox.plotting import plotting_backend 14 | plotting_backend('plotly') 15 | 16 | #%% 17 | # Load sample data from the data sub-module 18 | 19 | df = pancake() 20 | 21 | #%% 22 | # Estimate a exponential variogram again. More details are given in the 23 | # :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` example. 24 | 25 | vario = hydrobox.geostat.variogram( 26 | coordinates=df[['x', 'y']].values, 27 | values=df.z.values, 28 | model='exponential', 29 | bin_func='kmeans', 30 | n_lags=25, 31 | return_type='object' 32 | ) 33 | 34 | #%% 35 | # Run ordinary kriging on a 100x100 grid. In this run, the result is 36 | # directly plotted. Other return types are ``'grid'``, to return the 37 | # resulting interpolated grid and kriging error grid, or ``'object'`` 38 | # to return the :class:`Krige ` class. This class 39 | # is already parameterized, but the interpolation was not yet performed. 40 | # This is most helpful if other grid should be constructed. 41 | 42 | t1 = time() 43 | fig = hydrobox.geostat.ordinary_kriging( 44 | variogram=vario, 45 | grid_resolution=100, 46 | exact=True, 47 | cond_err='nugget', 48 | return_type='plot' 49 | ) 50 | t2 = time() 51 | 52 | print('Took: %2f sec' % (t2 - t1)) 53 | 54 | # show the plot 55 | plotly.io.show(fig) -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: Test and docs 2 | 3 | on: push 4 | 5 | jobs: 6 | test: 7 | name: Test 8 | runs-on: ubuntu-18.04 9 | 10 | 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@master 14 | 15 | - name: Install Python 16 | uses: actions/setup-python@master 17 | with: 18 | python-version: 3.8 19 | 20 | - name: Install Hydrobox 21 | run: pip3 install -e . 22 | 23 | - name: Install PyTest 24 | run: pip install pytest pytest-cov pytest-depends 25 | 26 | - name: Test 27 | run: pytest --cov-config=.coveragerc --cov=./ --cov-report=xml 28 | 29 | - name: Upload coverage 30 | uses: codecov/codecov-action@master 31 | with: 32 | file: ./coverage.xml 33 | 34 | docs: 35 | name: Build docs 36 | runs-on: ubuntu-18.04 37 | 38 | steps: 39 | - name: Checkout 40 | uses: actions/checkout@master 41 | 42 | - name: Install Python 43 | uses: actions/setup-python@master 44 | with: 45 | python-version: 3.8 46 | 47 | - name: Install Hydrobox 48 | run: pip3 install -e . 49 | 50 | - name: Install Doc requirements 51 | run: pip install sphinx pydata_sphinx_theme sphinx-gallery sphinx_autodoc_typehints 52 | 53 | - name: Build docs 54 | run: | 55 | cd doc 56 | make html 57 | 58 | - name: Deploy 59 | uses: JamesIves/github-pages-deploy-action@4.1.1 60 | with: 61 | branch: gh-pages 62 | folder: doc/_build/html 63 | 64 | 65 | -------------------------------------------------------------------------------- /hydrobox/tests/test_geostat.py: -------------------------------------------------------------------------------- 1 | from hydrobox import data 2 | import hydrobox 3 | import plotly.graph_objects as go 4 | import skgstat as skg 5 | from sklearn.model_selection import GridSearchCV 6 | 7 | 8 | def test_variogram(): 9 | """Test the return types""" 10 | # get data 11 | df = data.pancake() 12 | hydrobox.plotting_backend('plotly') 13 | 14 | for t, type_ in zip(('object', 'describe', 'plot'), (skg.Variogram, dict, go.Figure)): 15 | vario = hydrobox.geostat.variogram( 16 | df[['x', 'y']].values, 17 | df.z.values, 18 | return_type=t 19 | ) 20 | 21 | assert isinstance(vario, type_) 22 | 23 | 24 | def test_gridsearch(): 25 | """Test Gridsearch with explicit param_grid""" 26 | # create the grid 27 | param_grid={'model': ('spherical', 'gaussian', 'stable')} 28 | 29 | # get data 30 | df = data.pancake() 31 | 32 | gs = hydrobox.geostat.gridsearch( 33 | param_grid=param_grid, 34 | coordinates=df[['x', 'y']].values, 35 | values=df.z.values, 36 | n_lags=25, 37 | return_type='object' 38 | ) 39 | 40 | assert isinstance(gs, GridSearchCV) 41 | 42 | def test_gridsearch_variogram(): 43 | """Test Gridsearch with variogram passed""" 44 | df = data.pancake() 45 | # create the grid 46 | param_grid={'fit_method': ('trf', 'lm', 'ml')} 47 | vario = hydrobox.geostat.variogram( 48 | df[['x', 'y']].values, 49 | df.z.values, 50 | n_lags=15, 51 | return_type='object' 52 | ) 53 | gs = hydrobox.geostat.gridsearch( 54 | param_grid, 55 | variogram=vario, 56 | return_type='best_param' 57 | ) 58 | 59 | assert isinstance(gs, dict) -------------------------------------------------------------------------------- /hydrobox/geostat/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Geostatistical Toolbox 3 | ---------------------- 4 | 5 | This toolbox collects all functions needed to run different geostatistical 6 | tasks. Variogram analysis can be done with :func:`variogram `, 7 | which wraps the scikit-gstat Variogram class. 8 | 9 | Variogram estimation 10 | ~~~~~~~~~~~~~~~~~~~~ 11 | 12 | There are two major functions to estimate variograms. The :func:`variogram ` 13 | function and the :func:`gridsearch `, which will select optimal 14 | variogram parameters, based on a cross-validated score. 15 | 16 | .. minigallery:: hydrobox.geostat.variogram hydrobox.geostat.gridsearch 17 | :add-heading: Variogram examples 18 | 19 | Content of :py:mod:`hydrobox.geostat`: 20 | 21 | .. autosummary:: 22 | :toctree: gen_modules/ 23 | :template: module.rst 24 | 25 | variogram 26 | gridsearch 27 | 28 | Kriging 29 | ~~~~~~~ 30 | 31 | Kriging can be performed, after a variogram was estimated. the :class:`Variogram ` 32 | is exported to gstools and one of the :class:`Krige ` classes will be used for 33 | kriging. 34 | 35 | .. minigallery:: hydrobox.geostat.simple_kriging hydrobox.geostat.ordinary_kriging hydrobox.geostat.universal_kriging hydrobox.geostat.ext_drift_kriging 36 | :add-heading: Kriging examples 37 | 38 | .. autosummary:: 39 | :toctree: gen_modules/ 40 | :template: module.rst 41 | 42 | simple_kriging 43 | ordinary_kriging 44 | universal_kriging 45 | ext_drift_kriging 46 | 47 | """ 48 | from .variogram import variogram 49 | from .gridsearch import gridsearch 50 | from .kriging import ordinary_kriging, simple_kriging, universal_kriging, ext_drift_kriging -------------------------------------------------------------------------------- /.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 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | # Project specific 104 | # ignore PyCharm project folder 105 | .idea 106 | 107 | # ignore coverage.py html output 108 | cover 109 | 110 | # ignore IPython sphinx directive savefig 111 | doc/_build 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HydroBox 2 | 3 | 4 | ![PyPI](https://img.shields.io/pypi/v/hydrobox?color=green&logo=pypi&style=flat-square) 5 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/vforwater/hydrobox?logo=github&style=flat-square) 6 | ![GitHub commit checks state](https://img.shields.io/github/checks-status/vforwater/hydrobox/main?label=build%20status&logo=github&style=flat-square) 7 | [![DOI](https://zenodo.org/badge/129882492.svg)](https://zenodo.org/badge/latestdoi/129882492) 8 | 9 | ## Description 10 | 11 | **The HydroBox is mainly a toolbox used in the [V-FOR-WaTer](https://vforwater.de) Project. It will be expanded to serve general hydrological data exploration with a future release.** 12 | 13 | The HydroBox package is a toolbox for hydrological data analysis developed at the [Chair of Hydrology](https://hyd.iwg.kit.edu/english/index.php) at the 14 | [Karlsruhe Institute of Technology (KIT)](https://kit.edu/english/index.php). 15 | 16 | The full documentation can be found at: https://vforwater.github.io/hydrobox 17 | 18 | HydroBox has several submodules called toolboxes, which are a collection of functions and classes for specific purposes. As of this writing, the toolboxes are: 19 | 20 | * `geostat` for geostatistics. Mainly implemented through `scikit-gstat` and `gstools` 21 | 22 | In development are: 23 | 24 | * `uncertainty_framwork` for uncertainty analysis 25 | * `bridget` for evapotranspiration tools 26 | 27 | ## Citation 28 | 29 | If you use the package in other software or for publications, please cite it like: 30 | 31 | > Mirko Mälicke, 2021. VForWaTer/hydrobox: Version 0.2. doi:10.5281/zenodo.4774860 32 | 33 | Be aware that the dependencies of hydrobox require a citation as well. The (non-exhaustive) list of packages that you must cite are: 34 | 35 | * scipy, matplotlib, numpy - for all toolboxes 36 | * plotly - for the `plotly` plotting backend 37 | * scikit-gstat, gstools - for the `hydrobox.geostat` toolbox 38 | -------------------------------------------------------------------------------- /hydrobox/preprocessing/union.py: -------------------------------------------------------------------------------- 1 | """ 2 | Collects convenient methods for combining multiple data sets into a single one. 3 | This is typically a pandas.DataFrame then. 4 | """ 5 | import pandas as pd 6 | 7 | 8 | def merge(*x, dropna=False): 9 | r"""Merge multiple data sets. 10 | 11 | This method is a general tool for combining multiple data sources into a 12 | single structure. It can be used as a preprocessing step in case the next 13 | chained tool does only accept a single input data set, but can handle 14 | multi-dimensional data. 15 | For conveniently wrapping around a single dimension data set, it will 16 | return x as it is if len(x) == 1. 17 | 18 | Parameters 19 | ---------- 20 | x : pd.Series 21 | Input series. All series have to share an Index. If the type of the 22 | index is different, a ValueError will be raised. In case an Index 23 | value is missing on one of the Series, it will be filled with a NaN 24 | value. 25 | dropna : bool, optional 26 | If dropna is True, all indices with at least **one** NaN will be 27 | dropped. 28 | 29 | Returns 30 | ------- 31 | pandas.DataFrame 32 | 33 | Notes 34 | ----- 35 | 36 | At the current state merge does only accept ``pandas.Series``. 37 | A ``pandas.DataFrame`` with len(x) columns is returned. 38 | 39 | """ 40 | # check if only one series was passed 41 | if len(x) == 1: 42 | return x[0] 43 | elif len(x) == 0: 44 | return None 45 | 46 | # convert x from tuple to list 47 | x = list(x) 48 | 49 | # check the indices to be of same kind. 50 | dtype = type(x[0].index) 51 | if not all([isinstance(series.index, dtype) for series in x]): 52 | raise ValueError( 53 | 'At least one data set was not of type %s.' % str(dtype)) 54 | 55 | # build the first DataFrame 56 | df = pd.concat(x, axis=1) 57 | 58 | # if dropna was given, remove NaN values 59 | if dropna: 60 | df.dropna(axis=0, how='any', inplace=True) 61 | 62 | return df 63 | -------------------------------------------------------------------------------- /hydrobox/plotting/_backend.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helper functions for getting and setting the plotting backend. 3 | 4 | You can use this function to get or set the current 5 | plotting backend. 6 | 7 | """ 8 | import importlib 9 | 10 | ALLOWED_BACKENDS = ['matplotlib', 'bokeh', 'plotly'] 11 | AVAILABLE_BACKENDS = [] 12 | 13 | # check which one is available 14 | for be in ALLOWED_BACKENDS: 15 | try: 16 | exec('import %s' % be) 17 | AVAILABLE_BACKENDS.append(be) 18 | except ModuleNotFoundError: 19 | continue 20 | 21 | 22 | def plotting_backend(backend=None): 23 | """ 24 | Set a new or get the current plotting backend. 25 | 26 | Parameters 27 | ---------- 28 | backend : str, None 29 | If `None` the current plotting backend will be returned. 30 | If string, the plotting backend will be set to the given string. 31 | 32 | Raises 33 | ------ 34 | ValueError : If `backend` is a string but not in ['matplotlib', 'bokeh', 'plotly'] 35 | AttributeError : If `backend` is neither str or None 36 | 37 | """ 38 | # need to import at runtime to avoid circular imports 39 | import hydrobox 40 | 41 | if backend is None: 42 | return hydrobox.__plot_backend__ 43 | elif isinstance(backend, str): 44 | if backend not in ALLOWED_BACKENDS: 45 | raise ValueError('backend has to be one of [%s]' % ','.join(ALLOWED_BACKENDS)) 46 | elif backend not in AVAILABLE_BACKENDS: 47 | raise ValueError('Seems like %s is not installed' % backend) 48 | else: 49 | hydrobox.__plot_backend__ = backend 50 | else: 51 | raise AttributeError('backend has to be None or a string.') 52 | 53 | 54 | def plot_function_loader(caller_name, backend=None): 55 | """ 56 | Helper function 57 | 58 | This function can be used to load plotting functions 59 | in case they follow the naming specification 60 | """ 61 | # load module 62 | module_name = 'hydrobox.plotting.%s' % caller_name 63 | try: 64 | mod_ref = importlib.import_module(module_name) 65 | except ModuleNotFoundError: 66 | raise AttributeError('%s does not have a plotting routine' % caller_name) 67 | 68 | # load function 69 | backend = plotting_backend() 70 | function_name = '_plot_%s' % backend 71 | 72 | if hasattr(mod_ref, function_name): 73 | function = getattr(mod_ref, function_name) 74 | else: 75 | raise AttributeError('%s has no plotting routine for %s-backend' % (caller_name, backend)) 76 | 77 | return function 78 | 79 | -------------------------------------------------------------------------------- /hydrobox/geostat/variogram.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import skgstat as skg 3 | import gstools as gs 4 | 5 | from hydrobox.geostat import typing 6 | from hydrobox.plotting import plot_function_loader 7 | 8 | 9 | def variogram( 10 | coordinates: np.ndarray, 11 | values: np.ndarray, 12 | estimator: typing.Estimator = 'matheron', 13 | model: typing.Model = 'spherical', 14 | dist_func: typing.DistFunc = 'euclidean', 15 | bin_func: typing.BinFunc = 'even', 16 | fit_method: typing.FitMethod = 'trf', 17 | fit_sigma: typing.FitSigma = None, 18 | use_nugget: bool = False, 19 | maxlag: typing.Maxlag = None, 20 | n_lags: typing.Union[int, None] = 10, 21 | return_type: typing.Literal['object', 'describe', 'plot', 'distance_difference', 'location_trend', 'scattergram'] = 'object', 22 | **kwargs 23 | ) -> skg.Variogram: 24 | """ 25 | Uses scikit-gstat to estimate a Variogram. 26 | Refer to the :class:`Variogram ` class 27 | to learn about the different Parameters. 28 | 29 | Parameters 30 | ---------- 31 | return_type : str 32 | Specify how the Variogram instance should be returned. Object will 33 | return the actual instance. 'describe' is the dictionary output 34 | generated by the class, which is serializable. All other options 35 | return the different plot types 36 | 37 | Returns 38 | ------- 39 | variogram : skgstat.Variogram 40 | If the return type is `'object'` 41 | plot : plotly.Figure, matplotlib.pyplot.Figure 42 | If the return type is one of the plots 43 | description : dict 44 | If the return type is `'describe'` 45 | 46 | """ 47 | # create the variogram 48 | v = skg.Variogram( 49 | coordinates=coordinates, 50 | values=values, 51 | estimator=estimator, 52 | model=model, 53 | dist_func=dist_func, 54 | bin_func=bin_func, 55 | fit_method=fit_method, 56 | fit_sigma=fit_sigma, 57 | use_nugget=use_nugget, 58 | maxlag=maxlag, 59 | n_lags=n_lags, 60 | **kwargs 61 | ) 62 | 63 | if return_type == 'object': 64 | return v 65 | elif return_type == 'describe': 66 | return v.describe(short=False, flat=False) 67 | 68 | # otherwise create a plot 69 | pfunc = plot_function_loader('variogram') 70 | fig = pfunc( 71 | func_args=dict( 72 | variogram=v, 73 | plot_type=return_type 74 | ), 75 | plot_args=kwargs 76 | ) 77 | return fig 78 | 79 | 80 | -------------------------------------------------------------------------------- /hydrobox/plotting/kriging.py: -------------------------------------------------------------------------------- 1 | try: 2 | import matplotlib.pyplot as plt 3 | except ModuleNotFoundError: 4 | pass 5 | 6 | try: 7 | import plotly.graph_objects as go 8 | from plotly.subplots import make_subplots 9 | except ModuleNotFoundError: 10 | pass 11 | 12 | 13 | def _plot_matplotlib(func_args, plot_args): 14 | # build the figure 15 | fig, axes = plt.subplots(1, 2, figsize=plot_args.get('figsize', (12, 6))) 16 | 17 | # data can be one or two dimensional 18 | field = func_args['field'] 19 | sigma = func_args['sigma'] 20 | variogram = func_args['variogram'] 21 | 22 | if field.ndim == 1: 23 | # plot the lines 24 | axes[0].plot(field) 25 | axes[1].plot(sigma) 26 | 27 | else: 28 | # plot the im 29 | m1 = axes[0].imshow(field, origin='lower', cmap=plot_args.get('cmap', 'terrain')) 30 | m2 = axes[1].imshow(sigma, origin='lower', cmap=plot_args.get('sigma_cmap', 'hot')) 31 | plt.colorbar(m1, ax=axes[0]) 32 | plt.colorbar(m2, ax=axes[1]) 33 | 34 | # label 35 | axes[0].set_title('Kriging Grid') 36 | axes[1].set_title('Kriging Error') 37 | plt.tight_layout() 38 | 39 | return fig 40 | 41 | 42 | def _plot_plotly(func_args, plot_args): 43 | 44 | # get the data 45 | field = func_args['field'] 46 | sigma = func_args['sigma'] 47 | variogram = func_args['variogram'] 48 | 49 | if field.ndim == 1: 50 | fig = go.Figure() 51 | 52 | # build only one figure with error bars 53 | fig.add_trace( 54 | go.Scatter( 55 | x=range(field.flatten().size), 56 | y=field.flatten(), 57 | mode='lines+markers', 58 | marker=dict( 59 | size=5 60 | ), 61 | error_y=dict( 62 | type='data', 63 | array=sigma.flatten(), 64 | visible=True 65 | ) 66 | ) 67 | ) 68 | # return the figure 69 | return fig 70 | 71 | # if this point is reached, it's a 2D field 72 | if plot_args.get('surface', False): 73 | fig = make_subplots(1, 2, specs=[[{'type': 'surface'}, {'type': 'surface'}]]) 74 | Trace = go.Surface 75 | else: 76 | fig = make_subplots(1, 2) 77 | Trace = go.Heatmap 78 | 79 | # add the field 80 | fig.add_trace( 81 | Trace(z=field, colorscale=plot_args.get('colorscale', 'Earth_r')), 82 | 1, 1 83 | ) 84 | 85 | # add sigma 86 | fig.add_trace( 87 | Trace(z=sigma, colorscale=plot_args.get('sigma_colorscale', 'thermal')), 88 | 1, 2 89 | ) 90 | 91 | return fig 92 | -------------------------------------------------------------------------------- /hydrobox/plotting/flow_duration_curve.py: -------------------------------------------------------------------------------- 1 | """ 2 | """ 3 | import numpy as np 4 | try: 5 | import matplotlib.pyplot as plt 6 | except ModuleNotFoundError: 7 | # TODO here a global var can indicate that importing failed 8 | pass 9 | try: 10 | from bokeh.plotting import figure, Figure 11 | except ModuleNotFoundError: 12 | # TODO here a global var can indicate that importing failed 13 | pass 14 | 15 | 16 | def _plot_matplotlib(func_args, plot_args): 17 | # parse func-args 18 | non_exceeding = func_args.get('non_exceeding', False) 19 | log = func_args.get('log', False) 20 | x = func_args['x'] 21 | y = func_args['y'] 22 | 23 | # handle matplotlib figure 24 | ax = func_args.get('figure') 25 | if ax is None: 26 | fig, ax = plt.subplots(1, 1) 27 | else: 28 | fig = ax.get_figure() 29 | 30 | # set defaults 31 | plot_args.setdefault('linestyle', '-') 32 | plot_args.setdefault('color', 'b') 33 | 34 | # plot 35 | ax.plot(x, y, **plot_args) 36 | 37 | ax.set_xlabel('discharge [m3/s]') 38 | ax.set_ylabel('%sexceeding prob.' % ('non-' if non_exceeding else '')) 39 | 40 | # log, log scale 41 | if log: 42 | ax.loglog() 43 | else: 44 | ax.set_ylim((-0.05, 1.1)) 45 | ax.set_xlim(np.nanmin(x) * 0.98, np.nanmax(x) * 1.02) 46 | ax.set_title('%sFDC' % ('loglog ' if log else '')) 47 | ax.grid(which='both' if log else 'major') 48 | 49 | return fig 50 | 51 | def _plot_bokeh(func_args, plot_args): 52 | # parse func-args 53 | non_exceeding = func_args.get('non_exceeding', False) 54 | log = func_args.get('log', False) 55 | x = func_args['x'] 56 | y = func_args['y'] 57 | 58 | # plotting args 59 | plot_args.setdefault('line_color', 'navy') 60 | plot_args.setdefault('line_width', 3) 61 | 62 | fig = func_args.get('figure') 63 | if fig is None: 64 | # some of the plot_args should go into figure 65 | args = dict() 66 | 67 | for k,v in plot_args.items(): 68 | if hasattr(Figure, k): 69 | args[k] = v 70 | del plot_args[k] 71 | 72 | # handle log-log 73 | if log: 74 | args.setdefault('x_axis_type', 'log') 75 | args.setdefault('y_axis_type', 'log') 76 | else: 77 | args.setdefault('x_range', (-0.05, 1.1)) 78 | args.setdefault('y_range', (np.nanmin(x) * 0.98, np.nanmax(x) * 1.02)) 79 | args.setdefault('title', 'Flow duration curve') 80 | 81 | fig = figure(**args) 82 | 83 | # plot 84 | fig.line(x, y, **plot_args) 85 | 86 | fig.xaxis.axis_label = 'discharge [m3/s]' 87 | fig.yaxis.axis_label = '%sexceeding prob.' % ('non-' if non_exceeding else '') 88 | 89 | return fig 90 | 91 | -------------------------------------------------------------------------------- /doc/auto_examples/index.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | 4 | 5 | .. _sphx_glr_auto_examples: 6 | 7 | Hydrobox Examples 8 | ================= 9 | 10 | This gallery collects example scripts for most functions in hydrobox. 11 | 12 | .. raw:: html 13 | 14 |
15 | 16 | 17 | 18 | .. _sphx_glr_auto_examples_geostat: 19 | 20 | Geostatistics Toolbox 21 | --------------------- 22 | 23 | The following examples demonstrate the usage of the geostatistics toolbox. 24 | 25 | 26 | .. raw:: html 27 | 28 |
29 | 30 | .. only:: html 31 | 32 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_ordinary_kriging_thumb.png 33 | :alt: Ordinary Kriging 34 | 35 | :ref:`sphx_glr_auto_examples_geostat_plot_ordinary_kriging.py` 36 | 37 | .. raw:: html 38 | 39 |
40 | 41 | 42 | .. toctree:: 43 | :hidden: 44 | 45 | /auto_examples/geostat/plot_ordinary_kriging 46 | 47 | .. raw:: html 48 | 49 |
50 | 51 | .. only:: html 52 | 53 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_variogram_thumb.png 54 | :alt: Estimate a Variogram 55 | 56 | :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` 57 | 58 | .. raw:: html 59 | 60 |
61 | 62 | 63 | .. toctree:: 64 | :hidden: 65 | 66 | /auto_examples/geostat/plot_variogram 67 | 68 | .. raw:: html 69 | 70 |
71 | 72 | .. only:: html 73 | 74 | .. figure:: /auto_examples/geostat/images/thumb/sphx_glr_plot_gridsearch_thumb.png 75 | :alt: GridSearch optimization 76 | 77 | :ref:`sphx_glr_auto_examples_geostat_plot_gridsearch.py` 78 | 79 | .. raw:: html 80 | 81 |
82 | 83 | 84 | .. toctree:: 85 | :hidden: 86 | 87 | /auto_examples/geostat/plot_gridsearch 88 | .. raw:: html 89 | 90 |
91 | 92 | 93 | 94 | .. only :: html 95 | 96 | .. container:: sphx-glr-footer 97 | :class: sphx-glr-footer-gallery 98 | 99 | 100 | .. container:: sphx-glr-download sphx-glr-download-python 101 | 102 | :download:`Download all examples in Python source code: auto_examples_python.zip ` 103 | 104 | 105 | 106 | .. container:: sphx-glr-download sphx-glr-download-jupyter 107 | 108 | :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` 109 | 110 | 111 | .. only:: html 112 | 113 | .. rst-class:: sphx-glr-signature 114 | 115 | `Gallery generated by Sphinx-Gallery `_ 116 | -------------------------------------------------------------------------------- /examples/geostat/plot_variogram.py: -------------------------------------------------------------------------------- 1 | """ 2 | Estimate a Variogram 3 | ==================== 4 | 5 | Use the geostatistics toolbox to estimate a variogram and use one of the many 6 | plots. These plots help to understand the spatial properties of a variogram, 7 | and finally, the :class:`Variogram ` object itself can be 8 | returned and used in one of the Kriging routines. 9 | 10 | """ 11 | from pprint import pprint 12 | import plotly 13 | import hydrobox 14 | from hydrobox.data import pancake 15 | from hydrobox.plotting import plotting_backend 16 | plotting_backend('plotly') 17 | 18 | # %% 19 | # Load sample data from the data sub-module 20 | 21 | df = pancake() 22 | 23 | # %% 24 | # Estimate a variogram using a exponential model and 25 distance lags 25 | # that are derived from a KMeans cluster algorithm 26 | # Here, we use the describe output option to get a dictionary of 27 | # all variogram parameters 28 | 29 | vario = hydrobox.geostat.variogram( 30 | coordinates=df[['x', 'y']].values, 31 | values=df.z.values, 32 | model='exponential', 33 | bin_func='kmeans', 34 | n_lags=25, 35 | return_type='describe' 36 | ) 37 | # print 38 | pprint(vario) 39 | 40 | #%% 41 | # There are various return types, one of them is the plot. 42 | # This is the main plotting tool for variogram instances 43 | fig = hydrobox.geostat.variogram( 44 | coordinates=df[['x', 'y']].values, 45 | values=df.z.values, 46 | model='exponential', 47 | bin_func='kmeans', 48 | n_lags=25, 49 | return_type='plot' 50 | ) 51 | 52 | # show the figure 53 | plotly.io.show(fig) 54 | 55 | #%% 56 | # Alternatively you can return the :class:`Variogram ` 57 | # object itself and use all the different settings and methods directly. 58 | 59 | v = hydrobox.geostat.variogram( 60 | coordinates=df[['x', 'y']].values, 61 | values=df.z.values, 62 | model='exponential', 63 | bin_func='kmeans', 64 | n_lags=25, 65 | return_type='object' 66 | ) 67 | 68 | pprint(v) 69 | 70 | #%% 71 | # The :class:`Variogram ` has a plotting method for 72 | # all point pairs at their separating distances. It is available as a 73 | # return type, but can also be called directly: 74 | fig = v.distance_difference_plot() 75 | 76 | plotly.io.show(fig) 77 | 78 | #%% 79 | # The variogram instance has a lot of quality measures to judge the goodness 80 | # of fit for the theoretical model. They are implemented as properties and can 81 | # be used like attribtues, while being always up to date if the variogram is mutated. 82 | # Another helpful method is :func:`cross_validate `. 83 | # This will run a leave-one-out cross validation by interpolating the missing point for 84 | # all points. This is especially useful in cases, where a theoretical model fits well, 85 | # but the spatial properties are not well captured. 86 | 87 | # calculate the rmse of the model 88 | print(f"{v.model.__name__} RMSE: {v.rmse}") 89 | 90 | # get the cross-validation time 91 | from time import time 92 | t1 = time() 93 | rmse = v.cross_validate() 94 | t2 = time() 95 | print('Cross-validated RMSE: %.2f (took: %2fs)' % (rmse, t2 - t1)) 96 | -------------------------------------------------------------------------------- /hydrobox/stats/rolling.py: -------------------------------------------------------------------------------- 1 | """Rolling statistics 2 | 3 | Helper functions to apply rolling statistics to input data. 4 | 5 | """ 6 | import pandas as pd 7 | import numpy as np 8 | 9 | 10 | def moving_window(x, window_size=5, window_type=None, func='nanmean'): 11 | r"""Moving window statistics 12 | 13 | Applies a moving window function to the input data. Each of the grouped 14 | windows will be aggregated into a resulting time series. 15 | 16 | Parameters 17 | ---------- 18 | x : ``pandas.Series``, ``pandas.DataFrame`` 19 | Input data. The data should have a ``pandas.DatetimeIndex`` in order 20 | to produce meaningful results. However, this is not needed and will 21 | technically work on different indexed data. 22 | window_size : int 23 | The specified number of values will be grouped into a window. This 24 | parameter might have different behavior in case the window_type is 25 | not `None`. 26 | window_type : str, default=None 27 | If `None`, an even spaced window will be used and shifted by one for 28 | each group. Else, a window constructing class can be specified. 29 | Possible constructors are specified in ``pandas.DataFrame.rolling``. 30 | func : str 31 | Aggregating function for calculating the new window value. It has to 32 | be importable from ``numpy``, accept various input values and return 33 | only a single value like ``numpy.std`` or ``numpy.median``. 34 | 35 | Returns 36 | ------- 37 | pandas.Series 38 | pandas.DataFrame 39 | 40 | Notes 41 | ----- 42 | 43 | Be aware that most window types (if window_type is not None) do only 44 | work with either ``numpy.sum`` or ``numpy.mean``. 45 | 46 | Furthermore, most windows cannot work with the 'nan' versions of 47 | numpy aggregating function. Therefore in case window_type is None, any 48 | 'nan' will be removed from the func string. In case you want to force this 49 | behaviour, wrap the numpy function into a ``lambda``. 50 | 51 | Examples 52 | -------- 53 | This way, you can prevent the replacement of a np.nan* function: 54 | 55 | >>> moving_window(x, func=lambda x: np.nanmean(x)) 56 | array([NaN, NaN, NaN, 4.7445, 4.784 ... 6.34532]) 57 | 58 | """ 59 | # remove NaNs from the function name if a window_type was set 60 | if window_type is not None and isinstance(func, str): 61 | func = func.replace('nan', '') 62 | 63 | # get the function or load it from numpy 64 | if callable(func): 65 | f = func 66 | else: 67 | try: 68 | f = getattr(np, func) 69 | except AttributeError: 70 | raise ValueError( 71 | 'The function %s cannot be imported from numpy.' % func) 72 | 73 | # apply and return 74 | try: 75 | return x.rolling(window=window_size, win_type=window_type).aggregate(f) 76 | except AttributeError as e: 77 | raise AttributeError('This did not work. Maybe the func %s is not \ 78 | allowed for this window type?\n original Error: \ 79 | %s.' % (func, str(e))) 80 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_variogram.py: -------------------------------------------------------------------------------- 1 | """ 2 | Estimate a Variogram 3 | ==================== 4 | 5 | Use the geostatistics toolbox to estimate a variogram and use one of the many 6 | plots. These plots help to understand the spatial properties of a variogram, 7 | and finally, the :class:`Variogram ` object itself can be 8 | returned and used in one of the Kriging routines. 9 | 10 | """ 11 | from pprint import pprint 12 | import plotly 13 | import hydrobox 14 | from hydrobox.data import pancake 15 | from hydrobox.plotting import plotting_backend 16 | plotting_backend('plotly') 17 | 18 | # %% 19 | # Load sample data from the data sub-module 20 | 21 | df = pancake() 22 | 23 | # %% 24 | # Estimate a variogram using a exponential model and 25 distance lags 25 | # that are derived from a KMeans cluster algorithm 26 | # Here, we use the describe output option to get a dictionary of 27 | # all variogram parameters 28 | 29 | vario = hydrobox.geostat.variogram( 30 | coordinates=df[['x', 'y']].values, 31 | values=df.z.values, 32 | model='exponential', 33 | bin_func='kmeans', 34 | n_lags=25, 35 | return_type='describe' 36 | ) 37 | # print 38 | pprint(vario) 39 | 40 | #%% 41 | # There are various return types, one of them is the plot. 42 | # This is the main plotting tool for variogram instances 43 | fig = hydrobox.geostat.variogram( 44 | coordinates=df[['x', 'y']].values, 45 | values=df.z.values, 46 | model='exponential', 47 | bin_func='kmeans', 48 | n_lags=25, 49 | return_type='plot' 50 | ) 51 | 52 | # show the figure 53 | plotly.io.show(fig) 54 | 55 | #%% 56 | # Alternatively you can return the :class:`Variogram ` 57 | # object itself and use all the different settings and methods directly. 58 | 59 | v = hydrobox.geostat.variogram( 60 | coordinates=df[['x', 'y']].values, 61 | values=df.z.values, 62 | model='exponential', 63 | bin_func='kmeans', 64 | n_lags=25, 65 | return_type='object' 66 | ) 67 | 68 | pprint(v) 69 | 70 | #%% 71 | # The :class:`Variogram ` has a plotting method for 72 | # all point pairs at their separating distances. It is available as a 73 | # return type, but can also be called directly: 74 | fig = v.distance_difference_plot() 75 | 76 | plotly.io.show(fig) 77 | 78 | #%% 79 | # The variogram instance has a lot of quality measures to judge the goodness 80 | # of fit for the theoretical model. They are implemented as properties and can 81 | # be used like attribtues, while being always up to date if the variogram is mutated. 82 | # Another helpful method is :func:`cross_validate `. 83 | # This will run a leave-one-out cross validation by interpolating the missing point for 84 | # all points. This is especially useful in cases, where a theoretical model fits well, 85 | # but the spatial properties are not well captured. 86 | 87 | # calculate the rmse of the model 88 | print(f"{v.model.__name__} RMSE: {v.rmse}") 89 | 90 | # get the cross-validation time 91 | from time import time 92 | t1 = time() 93 | rmse = v.cross_validate() 94 | t2 = time() 95 | print('Cross-validated RMSE: %.2f (took: %2fs)' % (rmse, t2 - t1)) 96 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'HydroBox' 21 | copyright = '2021, Mirko Mälicke' 22 | author = 'Mirko Mälicke' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '0.2.0' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinx.ext.napoleon', 35 | 'sphinx.ext.autodoc', 36 | 'sphinx_autodoc_typehints', 37 | 'sphinx.ext.autosummary', 38 | 'sphinx.ext.intersphinx', 39 | 'sphinx_gallery.gen_gallery', 40 | 'sphinx.ext.todo' 41 | ] 42 | 43 | # Add any paths that contain templates here, relative to this directory. 44 | templates_path = ['_templates'] 45 | 46 | # List of patterns, relative to source directory, that match files and 47 | # directories to ignore when looking for source files. 48 | # This pattern also affects html_static_path and html_extra_path. 49 | exclude_patterns = [] 50 | 51 | 52 | # -- Options for HTML output ------------------------------------------------- 53 | 54 | # The theme to use for HTML and HTML Help pages. See the documentation for 55 | # a list of builtin themes. 56 | # 57 | html_theme = 'pydata_sphinx_theme' 58 | 59 | html_theme_options = { 60 | 'github_url': 'https://github.com/vforwater/hydrobox', 61 | } 62 | 63 | # Add any paths that contain custom static files (such as style sheets) here, 64 | # relative to this directory. They are copied after the builtin static files, 65 | # so a file named "default.css" will overwrite the builtin "default.css". 66 | html_static_path = ['_static'] 67 | 68 | # intesphinx 69 | intersphinx_mapping = { 70 | 'python': ('https://docs.python.org/3', None), 71 | 'sklearn': ('http://scikit-learn.org/stable', None), 72 | 'numpy': ('http://docs.scipy.org/doc/numpy', None), 73 | 'skgstat': ('https://mmaelicke.github.io/scikit-gstat', None), 74 | 'gstools': ('https://geostat-framework.readthedocs.io/projects/gstools/en/latest', None) 75 | } 76 | 77 | from plotly.io._sg_scraper import plotly_sg_scraper 78 | image_scrapers = ('matplotlib', plotly_sg_scraper,) 79 | 80 | import sphinx_gallery 81 | 82 | # Sphinx Gallery config 83 | sphinx_gallery_conf = { 84 | 'examples_dirs': '../examples', 85 | 'gallery_dirs': 'auto_examples', 86 | 'backreferences_dir': 'gen_modules/backreferences', 87 | 'doc_module': ('hydrobox',), 88 | 'image_scrapers': image_scrapers, 89 | } 90 | 91 | autosummary_generate = True 92 | -------------------------------------------------------------------------------- /hydrobox/plotting/regime.py: -------------------------------------------------------------------------------- 1 | """ 2 | """ 3 | import numpy as np 4 | import colorcet as cc 5 | try: 6 | import matplotlib.pyplot as plt 7 | except ModuleNotFoundError: 8 | # TODO here a global var can indicate that importing failed 9 | pass 10 | try: 11 | from bokeh.plotting import figure, Figure 12 | except ModuleNotFoundError: 13 | # TODO here a global var can indicate that importing failed 14 | pass 15 | 16 | MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 17 | 18 | 19 | def _plot_matplotlib(func_args, plot_args): 20 | # get the df with data 21 | df = func_args['df'] 22 | 23 | # load the correct cmap 24 | cm = getattr(cc.cm, func_args['cmap']) 25 | 26 | # handle matplotlib figure 27 | ax = func_args.get('figure') 28 | if ax is None: 29 | fig, ax = plt.subplots(1, 1) 30 | else: 31 | fig = ax.get_figure() 32 | 33 | # set plot defaults 34 | plot_args.setdefault('lw', 3) 35 | plot_args.setdefault('linestyle', '-') 36 | 37 | 38 | # check if there are quantiles 39 | if len(df.columns) > 1: 40 | # build the colormap 41 | n = int((len(df.columns) - 1) / 2) 42 | cmap = [cm(1. * _ / n) for _ in range(n)] 43 | cmap = np.concatenate((cmap, cmap[::-1])) 44 | 45 | # plot 46 | for i in range(len(df.columns) - 2, 1, -1): 47 | ax.fill_between(df.index, df.iloc[:, i], df.iloc[:, i - 1], 48 | interpolate=True, color=cmap[i - 1]) 49 | 50 | # plot the main aggregate 51 | if 'color' not in plot_args.keys(): 52 | plot_args['color'] = cm(0.0) 53 | ax.plot(df.index, df.iloc[:, 0], **plot_args) 54 | ax.set_xlim(0, 12) 55 | plt.xticks(df.index, MONTHS, rotation=45) 56 | 57 | return fig 58 | 59 | 60 | def _plot_bokeh(func_args, plot_args): 61 | # get the df with data 62 | df = func_args['df'] 63 | 64 | # load the correct cmap 65 | cm = getattr(cc, func_args['cmap']) 66 | 67 | # get figure 68 | fig = func_args.get('figure') 69 | 70 | if fig is None: 71 | # some of the plot_args should go into figure 72 | args = dict() 73 | 74 | for k,v in plot_args.items(): 75 | if hasattr(Figure, k): 76 | args[k] = v 77 | del plot_args[k] 78 | 79 | # set some defaults 80 | args.setdefault('title', 'Hydrological Regime') 81 | 82 | fig = figure(**args) 83 | 84 | # plot the percentiles at first 85 | if len(df.columns) > 1: 86 | n = int((len(df.columns) - 1) / 2) 87 | cmap = [cm[_] for _ in range(0, len(cm), int(len(cm) / n))] 88 | cmap = np.concatenate((cmap, cmap[::-1])) 89 | 90 | # plot 91 | for i in range(len(df.columns) - 2, 1, -1): 92 | fig.varea( 93 | x=df.index, y1=df.iloc[:, i], y2=df.iloc[:, i - 1], 94 | fill_color=cmap[i-1], fill_alpha=0.9 95 | ) 96 | 97 | # plot the main regime 98 | if 'color' not in plot_args.keys(): 99 | plot_args['color'] = cm[n] 100 | 101 | fig.line(df.index, df.iloc[:,0], **plot_args) 102 | 103 | # set the axis labels 104 | fig.xaxis.major_label_orientation = 45 105 | fig.xaxis.major_label_overrides = {i:m for i,m in enumerate(MONTHS)} 106 | 107 | return fig -------------------------------------------------------------------------------- /examples/geostat/plot_gridsearch.py: -------------------------------------------------------------------------------- 1 | """ 2 | GridSearch optimization 3 | ======================= 4 | 5 | The SciKit-GStat package can be connected to scikit-learn i.e. to use 6 | the model optimization sub-package. In this example, different options 7 | are compared and cross-validated. 8 | The Interface has two different options to evaluate a variogram model fit: 9 | 10 | * goodness of fit measures of the spatial model itself 11 | * cross-validation of the variogram by interpolating the observation points 12 | 13 | Both options can use the RMSE, MSE and MAE as a metric. 14 | 15 | """ 16 | import plotly 17 | import plotly.graph_objects as go 18 | import hydrobox 19 | from hydrobox.data import pancake 20 | from hydrobox.plotting import plotting_backend 21 | plotting_backend('plotly') 22 | 23 | #%% 24 | # Load sample data from the data sub-module 25 | 26 | df = pancake() 27 | 28 | #%% 29 | # First, a Variogram is estimated, which will fix all arguments that 30 | # should not be evaluated by the Grid Search. 31 | 32 | vario = hydrobox.geostat.variogram( 33 | coordinates=df[['x', 'y']].values, 34 | values=df.z.values, 35 | maxlag=500, 36 | bin_func='kmeans', 37 | return_type='object' 38 | ) 39 | 40 | #%% 41 | # The next step is to create a parameter grid, which specifies the 42 | # value space for each parameter that should be checked. 43 | # Here, we will try all combinations of different models and lag classes. 44 | 45 | param_grid = { 46 | 'model': ('spherical', 'exponential', 'matern'), 47 | 'n_lags': (15, 20, 25, 30, 35) 48 | } 49 | 50 | #%% 51 | # First the model fit itself is evaluated and only the best parameter 52 | # set will be returned 53 | 54 | best_param = hydrobox.geostat.gridsearch( 55 | param_grid=param_grid, 56 | variogram=vario, 57 | coordinates=None, # must be set if variogram is None 58 | values=None, # must be set if variogram is None 59 | score='rmse', # default 60 | cross_validate=False, # evaluate model fit, 61 | n_jobs=-1, # use parallel mode 62 | return_type='best_param' 63 | ) 64 | 65 | print(best_param) 66 | 67 | #%% 68 | # It is also possible to return the underlying 69 | # :class:`GridSearchCV ` instance. 70 | # This class holds way more information than just the best parameter. 71 | 72 | # reun the same Gridsearch, return the object 73 | clf = hydrobox.geostat.gridsearch( 74 | param_grid=param_grid, 75 | variogram=vario, 76 | coordinates=None, # must be set if variogram is None 77 | values=None, # must be set if variogram is None 78 | score='rmse', # default 79 | cross_validate=False, # evaluate model fit, 80 | n_jobs=-1, # use parallel mode 81 | return_type='object' 82 | ) 83 | 84 | # get the scores and their std 85 | scores = clf.cv_results_['mean_test_score'] 86 | scores_std = clf.cv_results_['std_test_score'] 87 | x = list(range(len(scores))) 88 | 89 | #%% 90 | # Plot the result 91 | fig = go.Figure() 92 | fig.add_trace( 93 | go.Scatter(x=x, y=scores, mode='lines', line_color='#A3ACF7', name='RMSE score') 94 | ) 95 | fig.add_trace( 96 | go.Scatter(x=x, y=scores + scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE + std') 97 | ) 98 | fig.add_trace( 99 | go.Scatter(x=x, y=scores - scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE - std') 100 | ) 101 | fig.update_layout( 102 | template='plotly_white' 103 | ) 104 | 105 | # show the plot 106 | plotly.io.show(fig) -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_gridsearch.py: -------------------------------------------------------------------------------- 1 | """ 2 | GridSearch optimization 3 | ======================= 4 | 5 | The SciKit-GStat package can be connected to scikit-learn i.e. to use 6 | the model optimization sub-package. In this example, different options 7 | are compared and cross-validated. 8 | The Interface has two different options to evaluate a variogram model fit: 9 | 10 | * goodness of fit measures of the spatial model itself 11 | * cross-validation of the variogram by interpolating the observation points 12 | 13 | Both options can use the RMSE, MSE and MAE as a metric. 14 | 15 | """ 16 | import plotly 17 | import plotly.graph_objects as go 18 | import hydrobox 19 | from hydrobox.data import pancake 20 | from hydrobox.plotting import plotting_backend 21 | plotting_backend('plotly') 22 | 23 | #%% 24 | # Load sample data from the data sub-module 25 | 26 | df = pancake() 27 | 28 | #%% 29 | # First, a Variogram is estimated, which will fix all arguments that 30 | # should not be evaluated by the Grid Search. 31 | 32 | vario = hydrobox.geostat.variogram( 33 | coordinates=df[['x', 'y']].values, 34 | values=df.z.values, 35 | maxlag=500, 36 | bin_func='kmeans', 37 | return_type='object' 38 | ) 39 | 40 | #%% 41 | # The next step is to create a parameter grid, which specifies the 42 | # value space for each parameter that should be checked. 43 | # Here, we will try all combinations of different models and lag classes. 44 | 45 | param_grid = { 46 | 'model': ('spherical', 'exponential', 'matern'), 47 | 'n_lags': (15, 20, 25, 30, 35) 48 | } 49 | 50 | #%% 51 | # First the model fit itself is evaluated and only the best parameter 52 | # set will be returned 53 | 54 | best_param = hydrobox.geostat.gridsearch( 55 | param_grid=param_grid, 56 | variogram=vario, 57 | coordinates=None, # must be set if variogram is None 58 | values=None, # must be set if variogram is None 59 | score='rmse', # default 60 | cross_validate=False, # evaluate model fit, 61 | n_jobs=-1, # use parallel mode 62 | return_type='best_param' 63 | ) 64 | 65 | print(best_param) 66 | 67 | #%% 68 | # It is also possible to return the underlying 69 | # :class:`GridSearchCV ` instance. 70 | # This class holds way more information than just the best parameter. 71 | 72 | # reun the same Gridsearch, return the object 73 | clf = hydrobox.geostat.gridsearch( 74 | param_grid=param_grid, 75 | variogram=vario, 76 | coordinates=None, # must be set if variogram is None 77 | values=None, # must be set if variogram is None 78 | score='rmse', # default 79 | cross_validate=False, # evaluate model fit, 80 | n_jobs=-1, # use parallel mode 81 | return_type='object' 82 | ) 83 | 84 | # get the scores and their std 85 | scores = clf.cv_results_['mean_test_score'] 86 | scores_std = clf.cv_results_['std_test_score'] 87 | x = list(range(len(scores))) 88 | 89 | #%% 90 | # Plot the result 91 | fig = go.Figure() 92 | fig.add_trace( 93 | go.Scatter(x=x, y=scores, mode='lines', line_color='#A3ACF7', name='RMSE score') 94 | ) 95 | fig.add_trace( 96 | go.Scatter(x=x, y=scores + scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE + std') 97 | ) 98 | fig.add_trace( 99 | go.Scatter(x=x, y=scores - scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE - std') 100 | ) 101 | fig.update_layout( 102 | template='plotly_white' 103 | ) 104 | 105 | # show the plot 106 | plotly.io.show(fig) -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_ordinary_kriging.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "%matplotlib inline" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "\n# Ordinary Kriging\n\nWith the help of a variogram that describes spatial properties of \na sample, the sample can be interpolated. \n" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "collapsed": false 26 | }, 27 | "outputs": [], 28 | "source": [ 29 | "from time import time\nimport plotly\nimport hydrobox\nfrom hydrobox.data import pancake\nfrom hydrobox.plotting import plotting_backend\nplotting_backend('plotly')" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "Load sample data from the data sub-module\n\n" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": { 43 | "collapsed": false 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "df = pancake()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "Estimate a exponential variogram again. More details are given in the \n`sphx_glr_auto_examples_geostat_plot_variogram.py` example.\n\n" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": { 61 | "collapsed": false 62 | }, 63 | "outputs": [], 64 | "source": [ 65 | "vario = hydrobox.geostat.variogram(\n coordinates=df[['x', 'y']].values,\n values=df.z.values,\n model='exponential',\n bin_func='kmeans',\n n_lags=25,\n return_type='object'\n)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "Run ordinary kriging on a 100x100 grid. In this run, the result is \ndirectly plotted. Other return types are ``'grid'``, to return the \nresulting interpolated grid and kriging error grid, or ``'object'``\nto return the :class:`Krige ` class. This class \nis already parameterized, but the interpolation was not yet performed.\nThis is most helpful if other grid should be constructed.\n\n" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": { 79 | "collapsed": false 80 | }, 81 | "outputs": [], 82 | "source": [ 83 | "t1 = time()\nfig = hydrobox.geostat.ordinary_kriging(\n variogram=vario,\n grid_resolution=100,\n exact=True,\n cond_err='nugget',\n return_type='plot'\n)\nt2 = time()\n\nprint('Took: %2f sec' % (t2 - t1))\n\n# show the plot\nplotly.io.show(fig)" 84 | ] 85 | } 86 | ], 87 | "metadata": { 88 | "kernelspec": { 89 | "display_name": "Python 3", 90 | "language": "python", 91 | "name": "python3" 92 | }, 93 | "language_info": { 94 | "codemirror_mode": { 95 | "name": "ipython", 96 | "version": 3 97 | }, 98 | "file_extension": ".py", 99 | "mimetype": "text/x-python", 100 | "name": "python", 101 | "nbconvert_exporter": "python", 102 | "pygments_lexer": "ipython3", 103 | "version": "3.8.5" 104 | } 105 | }, 106 | "nbformat": 4, 107 | "nbformat_minor": 0 108 | } -------------------------------------------------------------------------------- /hydrobox/geostat/gridsearch.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Tuple, Any, Literal 2 | import skgstat as skg 3 | from sklearn.model_selection import GridSearchCV 4 | import numpy as np 5 | 6 | 7 | def gridsearch( 8 | param_grid: Dict[str, Tuple], 9 | variogram: skg.Variogram = None, 10 | coordinates: np.ndarray = None, 11 | values: np.ndarray = None, 12 | score: Literal['rmse', 'mse', 'mae'] = 'rmse', 13 | cross_validate: bool = True, 14 | n_jobs=-1, 15 | return_type: Literal['object', 'best_param'] = 'object', 16 | **kwargs 17 | ) -> Dict[str, Any]: 18 | """ 19 | Automated GridSerarch for best variogram parameters. 20 | Uses :class:`GridSearchCV ` to 21 | find the best parameter set. 22 | 23 | .. todo:: 24 | with scikit-gstat 0.6, remove the cross_validate check. 25 | 26 | Parameters 27 | ---------- 28 | param_grid : dict 29 | List of parameters that should be used to form the grid. 30 | Each key has to be a valid argument to :class:`Variogram ` 31 | along with a list of valid options to try. 32 | variogram : skgstat.Variogram 33 | Variogram instance that should be used to find more suitable 34 | parameters. If given, coordinates, values and kwargs will be 35 | ignored 36 | coordinates : numpy.ndarray 37 | Array of coordinates. Mandatory if variogram is None. 38 | values : numpy.ndarray 39 | Array of values. Mandatory if variogram is None. 40 | score : str 41 | Score to find the best parameter set. Has to be one of 42 | ['rmse', 'mse', 'mae'] 43 | cross_validate : bool 44 | If True (default) the score will be applied to a leave-one-out 45 | cross-validation of a Kriging using the current Variogram. 46 | If False, the model fit to the experimental variogra, will be scored. 47 | .. note:: 48 | Needs at least `scikit-gstat>=0.5.4`. 49 | n_jobs : int 50 | Will be passed down to :class:`GridSearchCV ` 51 | return_type : str 52 | Either `'object'`, to return the GridSerachCV object or 53 | `'best_param'` to return a dictionary of the best params. 54 | 55 | 56 | Returns 57 | ------- 58 | gridSearch : sklearn.model_selection.GridSearchCV 59 | if return type is `'object'` 60 | best_params : dict 61 | if return type is `'best_param'` 62 | 63 | Raises 64 | ------ 65 | AttributeError : 66 | if neither a :class:`Variogram ` or both 67 | coordinates and values are given 68 | 69 | See Also 70 | -------- 71 | skgstat.interface.VariogramEstimator 72 | sklearn.model_selection.GridSearchCV 73 | 74 | """ 75 | if variogram is None and (coordinates is None or values is None): 76 | raise AttributeError('Either a Variogram or the coorinates, values and kwargs needs to be set') 77 | 78 | # extract the parameters 79 | if variogram is not None: 80 | coordinates = variogram.coordinates 81 | values = variogram.values 82 | kwargs.update(variogram.describe().get('params')) 83 | 84 | # handle cross-validate 85 | _, skg_m, skg_p = skg.__version__.split('.') 86 | if int(skg_m) > 5 or int(skg_p) >= 4: # pragma: no cover 87 | kwargs['cross_validate'] = cross_validate 88 | 89 | # initialize the estimator 90 | estimator = skg.interfaces.VariogramEstimator( 91 | use_score=score, 92 | **kwargs 93 | ) 94 | 95 | # inistialize the GridSearch 96 | gs = GridSearchCV(estimator, param_grid, cv=5, n_jobs=n_jobs) 97 | 98 | # run 99 | gs_fit = gs.fit(coordinates, values) 100 | 101 | if return_type.lower() == 'object': 102 | return gs_fit 103 | elif return_type.lower() == 'best_param': 104 | return gs_fit.best_params_ 105 | 106 | -------------------------------------------------------------------------------- /hydrobox/preprocessing/scale.py: -------------------------------------------------------------------------------- 1 | """ 2 | The scale module combines low-level aggregation functionality for time series 3 | data. The single functions operate on single time series instances. 4 | All functions aiming on aggregating multi-dimensional data or multiple time 5 | series are have a preceding 'm' in their function name. 6 | """ 7 | from datetime import datetime 8 | 9 | import numpy as np 10 | import pandas as pd 11 | 12 | 13 | def aggregate(x, by, func='mean'): 14 | """Time series aggregation 15 | 16 | This function version will only operate on a single ``pandas.Series`` or 17 | ``pandas.DataFrame`` instance. It has to be indexed by a 18 | `pandas.DatetimeIndex`. The input data will be aggregated to the given 19 | frequency by passing a `pandas.Grouper` conform string argument 20 | specifying the desired period like: '1M' for one month or '3Y-Sep' for 21 | three years starting at the first of October. 22 | 23 | 24 | Parameters 25 | ---------- 26 | x: ``pandas.Series``, ``pandas.DataFrame`` 27 | The input data, will be aggregated over the index. 28 | by : string 29 | Specifies the desired temporal resolution. Will be passed as 30 | ``freq`` argument of a ``pandas.Grouper`` object for grouping the 31 | data into the new resolution. 32 | If by is ``None``, the whole Series will be aggregated to only one 33 | value. The same applies to ``by='all'``. 34 | func : string 35 | Function identifier used for aggregation. Has to be importable from 36 | ``numpy``. The function must accept n input values and aggregate them 37 | to only a single one. 38 | 39 | Returns 40 | ------- 41 | pandas.Series : 42 | if x was of type ``pandas.Series`` 43 | pandas.DataFrame : 44 | if c was of type ``pandas.DataFrame`` 45 | 46 | """ 47 | # check for being a time series 48 | if not isinstance(x.index, pd.DatetimeIndex) \ 49 | and not (by is None or by == 'all'): 50 | raise ValueError('The data has to be indexed by a DatetimeIndex.') 51 | 52 | if by is not None and by == 'all': 53 | by = None 54 | 55 | # get the function 56 | if callable(func): 57 | f = func 58 | else: 59 | try: 60 | f = getattr(np, func) 61 | except AttributeError: 62 | raise ValueError('The function %s cannot be imported. the \ 63 | aggregation function has to be importable \ 64 | from numpy.' % func) 65 | 66 | if by is None: 67 | return x.aggregate(f) 68 | else: 69 | return x.groupby(pd.Grouper(freq=by)).aggregate(f) 70 | 71 | 72 | def cut_period(x, start, stop): 73 | """Truncate Time series 74 | 75 | Truncates a ``pandas.Series`` or ``pandas.DataFrame`` to the given 76 | period. The start and stop parameter need to be either a string or a 77 | ``datetime.datetime``, which will then be converted. Returns the 78 | truncated time series. 79 | 80 | Parameters 81 | ---------- 82 | x : ``pandas.Series``, ``pandas.DataFrame`` 83 | The input data, will be truncated 84 | start : string, datetime 85 | Begin of truncation. Can be a ``datetime.datetime`` or a string. 86 | If a string is passed, it has to use the format 'YYYYMMDDhhmmss', 87 | where the time component 'hhmmss' can be omitted. 88 | stop : string, datetime, 89 | End of truncation. Can be a ``datetime.datetime`` or a string. 90 | If a string is passed, it has to use the format 'YYYYMMDDhhmmss', 91 | where the time component 'hhmmss' can be omitted. 92 | 93 | """ 94 | # check for being a time series 95 | if not isinstance(x.index, pd.DatetimeIndex): 96 | raise ValueError('The data has to be indexed by a DatetimeIndex.') 97 | 98 | if isinstance(start, datetime): 99 | start = start.strftime('%Y%m%d%H%M%S') 100 | if isinstance(stop, datetime): 101 | stop = stop.strftime('%Y%m%d%H%M%S') 102 | 103 | return x[start:stop].copy() 104 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_ordinary_kriging.rst: -------------------------------------------------------------------------------- 1 | 2 | .. DO NOT EDIT. 3 | .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. 4 | .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: 5 | .. "auto_examples/geostat/plot_ordinary_kriging.py" 6 | .. LINE NUMBERS ARE GIVEN BELOW. 7 | 8 | .. only:: html 9 | 10 | .. note:: 11 | :class: sphx-glr-download-link-note 12 | 13 | Click :ref:`here ` 14 | to download the full example code 15 | 16 | .. rst-class:: sphx-glr-example-title 17 | 18 | .. _sphx_glr_auto_examples_geostat_plot_ordinary_kriging.py: 19 | 20 | 21 | Ordinary Kriging 22 | ================ 23 | 24 | With the help of a variogram that describes spatial properties of 25 | a sample, the sample can be interpolated. 26 | 27 | .. GENERATED FROM PYTHON SOURCE LINES 9-16 28 | 29 | .. code-block:: default 30 | 31 | from time import time 32 | import plotly 33 | import hydrobox 34 | from hydrobox.data import pancake 35 | from hydrobox.plotting import plotting_backend 36 | plotting_backend('plotly') 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | .. GENERATED FROM PYTHON SOURCE LINES 17-18 46 | 47 | Load sample data from the data sub-module 48 | 49 | .. GENERATED FROM PYTHON SOURCE LINES 18-21 50 | 51 | .. code-block:: default 52 | 53 | 54 | df = pancake() 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | .. GENERATED FROM PYTHON SOURCE LINES 22-24 64 | 65 | Estimate a exponential variogram again. More details are given in the 66 | :ref:`sphx_glr_auto_examples_geostat_plot_variogram.py` example. 67 | 68 | .. GENERATED FROM PYTHON SOURCE LINES 24-34 69 | 70 | .. code-block:: default 71 | 72 | 73 | vario = hydrobox.geostat.variogram( 74 | coordinates=df[['x', 'y']].values, 75 | values=df.z.values, 76 | model='exponential', 77 | bin_func='kmeans', 78 | n_lags=25, 79 | return_type='object' 80 | ) 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | .. GENERATED FROM PYTHON SOURCE LINES 35-41 90 | 91 | Run ordinary kriging on a 100x100 grid. In this run, the result is 92 | directly plotted. Other return types are ``'grid'``, to return the 93 | resulting interpolated grid and kriging error grid, or ``'object'`` 94 | to return the :class:`Krige ` class. This class 95 | is already parameterized, but the interpolation was not yet performed. 96 | This is most helpful if other grid should be constructed. 97 | 98 | .. GENERATED FROM PYTHON SOURCE LINES 41-55 99 | 100 | .. code-block:: default 101 | 102 | 103 | t1 = time() 104 | fig = hydrobox.geostat.ordinary_kriging( 105 | variogram=vario, 106 | grid_resolution=100, 107 | exact=True, 108 | cond_err='nugget', 109 | return_type='plot' 110 | ) 111 | t2 = time() 112 | 113 | print('Took: %2f sec' % (t2 - t1)) 114 | 115 | # show the plot 116 | plotly.io.show(fig) 117 | 118 | 119 | .. raw:: html 120 | :file: images/sphx_glr_plot_ordinary_kriging_001.html 121 | 122 | 123 | .. rst-class:: sphx-glr-script-out 124 | 125 | Out: 126 | 127 | .. code-block:: none 128 | 129 | Took: 2.842178 sec 130 | 131 | 132 | 133 | 134 | 135 | .. rst-class:: sphx-glr-timing 136 | 137 | **Total running time of the script:** ( 0 minutes 6.564 seconds) 138 | 139 | 140 | .. _sphx_glr_download_auto_examples_geostat_plot_ordinary_kriging.py: 141 | 142 | 143 | .. only :: html 144 | 145 | .. container:: sphx-glr-footer 146 | :class: sphx-glr-footer-example 147 | 148 | 149 | 150 | .. container:: sphx-glr-download sphx-glr-download-python 151 | 152 | :download:`Download Python source code: plot_ordinary_kriging.py ` 153 | 154 | 155 | 156 | .. container:: sphx-glr-download sphx-glr-download-jupyter 157 | 158 | :download:`Download Jupyter notebook: plot_ordinary_kriging.ipynb ` 159 | 160 | 161 | .. only:: html 162 | 163 | .. rst-class:: sphx-glr-signature 164 | 165 | `Gallery generated by Sphinx-Gallery `_ 166 | -------------------------------------------------------------------------------- /hydrobox/data/sample_sr.csv: -------------------------------------------------------------------------------- 1 | x,y,z 2 | 94,20,-0.39444438053747594 3 | 82,37,-2.283663062708473 4 | 43,13,-0.5462130280740465 5 | 78,42,-3.681383697834789 6 | 50,28,0.5045382784070095 7 | 20,74,-1.5041741384342935 8 | 71,88,1.3503808134843678 9 | 7,9,-1.1638796197023304 10 | 24,69,-0.34051346127283 11 | 77,28,-1.1920728498239048 12 | 71,17,-1.2669163335465252 13 | 29,74,-0.7427182051736556 14 | 49,59,0.48750491266151463 15 | 100,12,-2.962001584534514 16 | 5,52,-1.9117585922891978 17 | 16,82,-0.8417505208808288 18 | 16,17,-1.4281827604814472 19 | 88,58,0.7782599543685997 20 | 52,49,0.1786421715317022 21 | 63,85,0.7522280061388416 22 | 26,13,-0.7991250342467555 23 | 19,36,0.6432892058776345 24 | 36,79,-1.5280696290326905 25 | 57,97,-0.8259657245833522 26 | 62,99,-0.06959396015894331 27 | 32,30,0.8022020533234546 28 | 39,59,-0.05292820972410184 29 | 29,90,-1.0204864471818211 30 | 99,32,-0.6091409530661445 31 | 44,6,0.22039696575581752 32 | 43,58,0.4599801140437183 33 | 85,39,-2.31679305625176 34 | 70,54,0.5223039952706272 35 | 91,79,-0.3759977848107796 36 | 72,73,0.7416405213029846 37 | 26,14,-0.7804675204942965 38 | 74,27,-1.0553595338690305 39 | 95,81,-0.7486241434516918 40 | 57,64,1.7616136632222261 41 | 91,89,0.04677627985012556 42 | 16,15,-1.7478697007635944 43 | 43,64,0.16499520258020345 44 | 51,23,0.7437586449805585 45 | 48,15,-0.7098517053077216 46 | 44,62,0.6186416952805267 47 | 89,87,-0.16867483733838862 48 | 75,44,-3.514204440866991 49 | 28,60,-2.7366690143837133 50 | 40,15,-1.1281865226107042 51 | 93,11,-3.118152626954697 52 | 15,63,-1.2690922003864293 53 | 88,29,-0.18836588223815826 54 | 2,23,0.6799045629833986 55 | 46,96,0.21739536724147307 56 | 65,3,-1.4592660391212884 57 | 88,37,-1.107244883929112 58 | 65,95,0.2275609725399672 59 | 41,7,-0.2496356070766711 60 | 25,80,-1.1211940215729022 61 | 21,27,-0.09661807637216241 62 | 91,12,-2.406230668399388 63 | 32,81,-1.3500805459402252 64 | 65,83,0.5888676370398311 65 | 72,27,-0.9654962013539982 66 | 31,80,-1.456316317242763 67 | 34,77,-1.5715611436569268 68 | 75,52,-0.9936717510754695 69 | 83,57,-0.3972504171528985 70 | 53,54,0.9579444554514525 71 | 5,48,-0.9110466214925685 72 | 63,37,-1.668719852071336 73 | 52,88,0.30155665085569183 74 | 52,80,-0.11393389488718508 75 | 88,59,0.9498500062624038 76 | 82,40,-2.8630741280292114 77 | 88,97,-0.5724965644599087 78 | 16,39,0.3509623844845141 79 | 50,30,0.30712552582481484 80 | 94,10,-3.2346378326811025 81 | 32,38,0.4552089340350225 82 | 44,24,-0.7574018163971681 83 | 49,69,1.2356342827899252 84 | 80,28,-1.0178539036303835 85 | 44,97,0.04065055111399368 86 | 9,72,-1.5862874790244033 87 | 62,83,0.713159046633232 88 | 55,87,1.0014195983263146 89 | 73,88,0.9887212215545849 90 | 74,77,0.8412936419422302 91 | 41,10,-0.47373270525578615 92 | 80,70,0.1989277467301741 93 | 84,91,0.4362331855173341 94 | 19,41,0.008772448868853477 95 | 74,95,0.21200274251186702 96 | 53,77,-0.44142991018893873 97 | 77,71,0.3737558041580218 98 | 26,80,-1.3080066480679053 99 | 60,29,-0.8604750005960811 100 | 87,66,0.4825254242707143 101 | 49,26,0.2699907908494049 102 | 58,7,-1.7509555878489427 103 | 83,34,-1.9690554078818678 104 | 98,71,-0.3072215482324351 105 | 19,33,0.8195543425614512 106 | 69,37,-0.9869471073868279 107 | 77,16,-0.3032695851580103 108 | 17,5,-1.2189964119667087 109 | 12,3,-0.27257057240043464 110 | 36,10,-0.39356133696987433 111 | 60,92,0.8447638349149216 112 | 87,26,0.04083935755339871 113 | 42,88,-0.6016648813493206 114 | 95,68,-0.6153052578521497 115 | 26,73,0.10972407867717388 116 | 75,87,0.4837705304898816 117 | 8,72,-1.5017658843299335 118 | 72,38,-2.1548409371968544 119 | 91,53,-0.29640401021767016 120 | 17,43,-0.19065596156743903 121 | 78,44,-3.470794267709495 122 | 47,80,-0.15092944771479289 123 | 44,90,-0.2891096089347041 124 | 14,73,-1.6282848473826248 125 | 1,99,-2.7485938529435496 126 | 89,52,-1.0444974789331405 127 | 44,88,-0.23148281964714834 128 | 56,6,-1.2489821829912962 129 | 70,64,-0.1985023790465692 130 | 40,85,-0.6119284650766149 131 | 46,21,-1.0575872709845917 132 | 41,39,-0.49010823408513315 133 | 45,93,-0.14813508543192433 134 | 8,46,-0.6957694579956841 135 | 29,41,0.2925915080992926 136 | 32,98,-1.6807270769546596 137 | 80,100,-1.8149269806059642 138 | 65,94,0.4077290290404864 139 | 26,63,-1.475875594477606 140 | 49,6,0.05498998205253869 141 | 56,48,-0.22702813291513896 142 | 22,92,-0.8249706202797014 143 | 56,35,-0.9263564590999971 144 | 66,26,-0.8561138896895382 145 | 48,67,1.2573632103954488 146 | 100,75,0.06842200444814739 147 | 81,75,0.5473099797622492 148 | 33,49,-1.0321496503984102 149 | 27,99,-1.8838634225902282 150 | 85,68,0.4802607641737733 151 | 82,71,0.3196478743792045 152 | 80,82,0.5695006144567061 153 | 65,13,-1.06228576338799 154 | 96,76,-0.3524376227895107 155 | 2,74,0.5690909889388418 156 | 85,31,-1.246452342132829 157 | 4,33,-0.7953412470737332 158 | 67,50,0.5625661264080491 159 | 55,83,0.24351590040811572 160 | 15,38,0.36411193448911594 161 | 71,100,-0.4536559855457971 162 | 83,1,0.07933936128007926 163 | 88,45,-2.7457207428781283 164 | 39,95,0.23219385937063947 165 | 25,6,-0.2788122287793571 166 | 100,49,0.23626716108476928 167 | 44,86,-0.09441530966039002 168 | 18,92,-1.0357957584175066 169 | 89,36,-0.38685322915900544 170 | 7,35,-1.0239078717951824 171 | 63,46,-0.34438971963090154 172 | 22,84,0.23396407807136554 173 | 68,34,-0.903632978192785 174 | 96,11,-3.434910889878696 175 | 87,38,-1.785802886697303 176 | 29,79,-1.5565194005756282 177 | 83,59,0.6088959380848571 178 | 82,99,-1.5779406861904615 179 | 65,17,-1.7956575523376384 180 | 11,54,-1.5236653807493452 181 | 70,100,-0.4958109890037088 182 | 89,27,0.08154828239071249 183 | 59,70,0.8365371624753974 184 | 57,19,-1.070650685896748 185 | 14,47,-0.8417245700628229 186 | 77,1,0.37906792145208323 187 | 64,6,-1.8521839941654208 188 | 81,29,-1.224269671546148 189 | 78,97,-0.6538359282489696 190 | 98,48,-0.20965379737882728 191 | 13,16,-0.24930407680322653 192 | 53,92,0.4209881693233034 193 | 82,7,0.19664362382501466 194 | 6,56,-1.9742588680541977 195 | 15,51,-1.1446294699147188 196 | 90,76,-0.6174841523716045 197 | 24,11,-1.4410912136779468 198 | 70,15,-1.3418968539974467 199 | 42,82,-0.037885272206712395 200 | 88,40,-2.0035919907455177 201 | 85,88,0.12049021523462489 202 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_variogram.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "%matplotlib inline" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "\n# Estimate a Variogram\n\nUse the geostatistics toolbox to estimate a variogram and use one of the many\nplots. These plots help to understand the spatial properties of a variogram,\nand finally, the :class:`Variogram ` object itself can be\nreturned and used in one of the Kriging routines.\n" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "collapsed": false 26 | }, 27 | "outputs": [], 28 | "source": [ 29 | "from pprint import pprint\nimport plotly\nimport hydrobox\nfrom hydrobox.data import pancake\nfrom hydrobox.plotting import plotting_backend\nplotting_backend('plotly')" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "Load sample data from the data sub-module\n\n" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": { 43 | "collapsed": false 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "df = pancake()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "Estimate a variogram using a exponential model and 25 distance lags\nthat are derived from a KMeans cluster algorithm\nHere, we use the describe output option to get a dictionary of \nall variogram parameters\n\n" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": { 61 | "collapsed": false 62 | }, 63 | "outputs": [], 64 | "source": [ 65 | "vario = hydrobox.geostat.variogram(\n coordinates=df[['x', 'y']].values,\n values=df.z.values,\n model='exponential',\n bin_func='kmeans',\n n_lags=25,\n return_type='describe'\n)\n# print\npprint(vario)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "There are various return types, one of them is the plot.\nThis is the main plotting tool for variogram instances\n\n" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": { 79 | "collapsed": false 80 | }, 81 | "outputs": [], 82 | "source": [ 83 | "fig = hydrobox.geostat.variogram(\n coordinates=df[['x', 'y']].values,\n values=df.z.values,\n model='exponential',\n bin_func='kmeans',\n n_lags=25,\n return_type='plot'\n)\n\n# show the figure\nplotly.io.show(fig)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "Alternatively you can return the :class:`Variogram `\nobject itself and use all the different settings and methods directly.\n\n" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": false 98 | }, 99 | "outputs": [], 100 | "source": [ 101 | "v = hydrobox.geostat.variogram(\n coordinates=df[['x', 'y']].values,\n values=df.z.values,\n model='exponential',\n bin_func='kmeans',\n n_lags=25,\n return_type='object'\n)\n\npprint(v)" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "The :class:`Variogram ` has a plotting method for\nall point pairs at their separating distances. It is available as a \nreturn type, but can also be called directly:\n\n" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": false 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "fig = v.distance_difference_plot() \n\nplotly.io.show(fig)" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "The variogram instance has a lot of quality measures to judge the goodness\nof fit for the theoretical model. They are implemented as properties and can\nbe used like attribtues, while being always up to date if the variogram is mutated.\nAnother helpful method is :func:`cross_validate `.\nThis will run a leave-one-out cross validation by interpolating the missing point for \nall points. This is especially useful in cases, where a theoretical model fits well,\nbut the spatial properties are not well captured. \n\n" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": { 133 | "collapsed": false 134 | }, 135 | "outputs": [], 136 | "source": [ 137 | "# calculate the rmse of the model\nprint(f\"{v.model.__name__} RMSE: {v.rmse}\")\n\n# get the cross-validation time\nfrom time import time\nt1 = time()\nrmse = v.cross_validate()\nt2 = time()\nprint('Cross-validated RMSE: %.2f (took: %2fs)' % (rmse, t2 - t1))" 138 | ] 139 | } 140 | ], 141 | "metadata": { 142 | "kernelspec": { 143 | "display_name": "Python 3", 144 | "language": "python", 145 | "name": "python3" 146 | }, 147 | "language_info": { 148 | "codemirror_mode": { 149 | "name": "ipython", 150 | "version": 3 151 | }, 152 | "file_extension": ".py", 153 | "mimetype": "text/x-python", 154 | "name": "python", 155 | "nbconvert_exporter": "python", 156 | "pygments_lexer": "ipython3", 157 | "version": "3.8.5" 158 | } 159 | }, 160 | "nbformat": 4, 161 | "nbformat_minor": 0 162 | } -------------------------------------------------------------------------------- /hydrobox/utils/decorators.py: -------------------------------------------------------------------------------- 1 | """ 2 | These decorators can be used to annotate the tool functions. 3 | Most decorators will check the argument types or input data. 4 | """ 5 | from functools import wraps 6 | 7 | 8 | def accept(**types): 9 | """ 10 | Decorator used to define accepted argument types for the toolbox functions. 11 | 12 | Usage 13 | ----- 14 | 15 | .. code-block:: python 16 | 17 | @accept(foo=str, bar=(int,float)) 18 | def f(foo, bar): 19 | pass 20 | 21 | :param types: arguments to the decorated function and the allowed types 22 | :return: decorated function 23 | """ 24 | def decorator(f): 25 | # dig down to the original wrapped function in case more than one decorator was used 26 | _f = f 27 | while hasattr(_f, '__wrapped__'): 28 | _f = getattr(_f, '__wrapped__') 29 | 30 | # get the code, name and argnames 31 | code = _f.__code__ 32 | fname = _f.__name__ 33 | names = code.co_varnames[:code.co_argcount] 34 | 35 | @wraps(f) 36 | def decorated(*args, **kwargs): 37 | for argname, argtype in types.items(): 38 | # check for argnames in kwargs 39 | if argname in kwargs: 40 | argval = kwargs.get(argname) 41 | else: 42 | try: 43 | argval = args[names.index(argname)] 44 | except IndexError: 45 | # TODO: Turn this into a develop level log 46 | #print('DevelWarning: arg %s not passed by function %s. (Maybe default?).' % (argname, fname)) 47 | continue 48 | 49 | # check type 50 | if argtype == 'callable': 51 | if not callable(argval): 52 | raise TypeError('%s(...): arg %s: type is %s, but shall be callable.' % (fname, argname, type(argval))) 53 | else: 54 | continue 55 | 56 | elif argval is None: 57 | if not (argtype == 'None' or (isinstance(argtype, (list, tuple)) and 'None' in argtype)): 58 | raise TypeError('%s(...): arg %s: is None, must be %s.' %(fname, argname, argtype)) 59 | else: 60 | continue 61 | 62 | # check if there is a None in argtype 63 | if isinstance(argtype, (tuple, list)) and 'None' in argtype: 64 | argtype = list(argtype) 65 | argtype.remove('None') 66 | argtype = tuple(argtype) 67 | 68 | # check if there is a 'callable' in argtype 69 | if isinstance(argtype, (tuple, list)) and 'callable' in argtype: 70 | argtype = list(argtype) 71 | argtype.remove('callable') 72 | argtype = tuple(argtype) 73 | # this is a special case 74 | if not isinstance(argval, argtype) and not callable(argval): 75 | raise TypeError("{0}(...); arg {1}: is not callable or of type {2}".format(fname, argname, argtype)) 76 | else: 77 | continue 78 | 79 | if not isinstance(argval, argtype): 80 | raise TypeError("%s(...): arg %s: type is %s, must be %s." % 81 | (fname, argname, type(argval), argtype)) 82 | 83 | # all checkes passed 84 | return f(*args, **kwargs) 85 | return decorated 86 | return decorator 87 | 88 | 89 | def enforce(**types): 90 | """ 91 | Decorator used to define enforcing of argument type casts for the toolbox functions. 92 | 93 | In case a cast on one of the arguments raises a :py:class: `ValueError`, the cast will be ignored. 94 | Therefore it might make sense to combine a enforce decorator with a :py:func: `hydrobox.utils.decorators.accept` 95 | decorator in order to accept only the enforced type. In this case the 96 | :py:func: `hydrobox.utils.decorators.accept` decorator raises a :py:class: `ValueError`. 97 | 98 | Usage 99 | ----- 100 | 101 | .. code-block:: python 102 | 103 | @accept(foo=str) 104 | def f(foo): 105 | return 'Result: %s' % foo 106 | 107 | The f function can now be called and foo will be casted to a string 108 | 109 | .. code-block:: python 110 | 111 | a = f(5) 112 | print(type(a)) 113 | 114 | .. code-block:: bash 115 | 116 | >> 117 | 118 | :param types: arguments to the decorated function and the desired types 119 | :return: decorated function 120 | """ 121 | def decorator(f): 122 | # dig down to the original wrapped function in case more than one decorator was used 123 | _f = f 124 | while hasattr(_f, '__wrapped__'): 125 | _f = getattr(_f, '__wrapped__') 126 | 127 | # get the code, name and argnames 128 | code = _f.__code__ 129 | fname = _f.__name__ 130 | names = code.co_varnames[:code.co_argcount] 131 | 132 | @wraps(f) 133 | def decorated(*args, **kwargs): 134 | def caster(value, destination): 135 | try: 136 | return destination(value) 137 | except (ValueError, Exception): 138 | # TODO: On develop log note that the cast failed 139 | return value 140 | 141 | # turn args into a list 142 | args = list(args) 143 | 144 | # cast all defined types 145 | for argname, argtype in types.items(): 146 | if argname in kwargs: 147 | argval = kwargs.get(argname) 148 | kwargs.update({argname: caster(argval, argtype)}) 149 | else: 150 | try: 151 | index = names.index(argname) 152 | args[index] = caster(args[index], argtype) 153 | except IndexError: 154 | # TODO: Turn this into a develop level log 155 | continue 156 | 157 | return f(*args, **kwargs) 158 | return decorated 159 | return decorator 160 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_gridsearch.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "%matplotlib inline" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "\n# GridSearch optimization\n\nThe SciKit-GStat package can be connected to scikit-learn i.e. to use\nthe model optimization sub-package. In this example, different options\nare compared and cross-validated.\nThe Interface has two different options to evaluate a variogram model fit:\n\n* goodness of fit measures of the spatial model itself\n* cross-validation of the variogram by interpolating the observation points\n\nBoth options can use the RMSE, MSE and MAE as a metric.\n" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "collapsed": false 26 | }, 27 | "outputs": [], 28 | "source": [ 29 | "import plotly\nimport plotly.graph_objects as go\nimport hydrobox\nfrom hydrobox.data import pancake\nfrom hydrobox.plotting import plotting_backend\nplotting_backend('plotly')" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "Load sample data from the data sub-module\n\n" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": { 43 | "collapsed": false 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "df = pancake()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "First, a Variogram is estimated, which will fix all arguments that\nshould not be evaluated by the Grid Search.\n\n" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": { 61 | "collapsed": false 62 | }, 63 | "outputs": [], 64 | "source": [ 65 | "vario = hydrobox.geostat.variogram(\n coordinates=df[['x', 'y']].values,\n values=df.z.values,\n maxlag=500,\n bin_func='kmeans',\n return_type='object'\n)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "The next step is to create a parameter grid, which specifies the\nvalue space for each parameter that should be checked.\nHere, we will try all combinations of different models and lag classes.\n\n" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": { 79 | "collapsed": false 80 | }, 81 | "outputs": [], 82 | "source": [ 83 | "param_grid = {\n 'model': ('spherical', 'exponential', 'matern'),\n 'n_lags': (15, 20, 25, 30, 35)\n}" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "First the model fit itself is evaluated and only the best parameter\nset will be returned\n\n" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": false 98 | }, 99 | "outputs": [], 100 | "source": [ 101 | "best_param = hydrobox.geostat.gridsearch(\n param_grid=param_grid,\n variogram=vario,\n coordinates=None, # must be set if variogram is None\n values=None, # must be set if variogram is None\n score='rmse', # default\n cross_validate=False, # evaluate model fit,\n n_jobs=-1, # use parallel mode\n return_type='best_param'\n)\n\nprint(best_param)" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "It is also possible to return the underlying \n:class:`GridSearchCV ` instance.\nThis class holds way more information than just the best parameter.\n\n" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": false 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "# reun the same Gridsearch, return the object\nclf = hydrobox.geostat.gridsearch(\n param_grid=param_grid,\n variogram=vario,\n coordinates=None, # must be set if variogram is None\n values=None, # must be set if variogram is None\n score='rmse', # default\n cross_validate=False, # evaluate model fit,\n n_jobs=-1, # use parallel mode\n return_type='object'\n)\n\n# get the scores and their std\nscores = clf.cv_results_['mean_test_score']\nscores_std = clf.cv_results_['std_test_score']\nx = list(range(len(scores)))" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "Plot the result\n\n" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": { 133 | "collapsed": false 134 | }, 135 | "outputs": [], 136 | "source": [ 137 | "fig = go.Figure()\nfig.add_trace(\n go.Scatter(x=x, y=scores, mode='lines', line_color='#A3ACF7', name='RMSE score')\n)\nfig.add_trace(\n go.Scatter(x=x, y=scores + scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE + std')\n)\nfig.add_trace(\n go.Scatter(x=x, y=scores - scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE - std')\n)\nfig.update_layout(\n template='plotly_white'\n)\n\n# show the plot\nplotly.io.show(fig)" 138 | ] 139 | } 140 | ], 141 | "metadata": { 142 | "kernelspec": { 143 | "display_name": "Python 3", 144 | "language": "python", 145 | "name": "python3" 146 | }, 147 | "language_info": { 148 | "codemirror_mode": { 149 | "name": "ipython", 150 | "version": 3 151 | }, 152 | "file_extension": ".py", 153 | "mimetype": "text/x-python", 154 | "name": "python", 155 | "nbconvert_exporter": "python", 156 | "pygments_lexer": "ipython3", 157 | "version": "3.8.5" 158 | } 159 | }, 160 | "nbformat": 4, 161 | "nbformat_minor": 0 162 | } -------------------------------------------------------------------------------- /hydrobox/stats/regression.py: -------------------------------------------------------------------------------- 1 | """Regression Module 2 | 3 | Common tools for calculating linear regression and produce scatter plots. 4 | 5 | """ 6 | from itertools import product 7 | 8 | from scipy.stats import linregress 9 | import matplotlib.pyplot as plt 10 | import numpy as np 11 | 12 | from hydrobox.toolbox import merge 13 | 14 | 15 | def linear_regression(*x, df=None, plot=False, ax=None, notext=False): 16 | """Linear Regression tool 17 | 18 | This tool can be used for a number of regression related tasks. It can 19 | calculate a linear regression between two observables and also return a 20 | scatter plot including the regression parameters and function. 21 | 22 | In case more than two ``Series`` or ``arrays`` are passed, they will be 23 | merged into a ``DataFrame`` and a linear regression between all 24 | combinations will be calculated and potted if desired. 25 | 26 | Parameters 27 | ---------- 28 | x : pandas.Series, numpy.ndarray 29 | If df is None, at least two Series or arrays have to be passed. If 30 | more are passed, a multi output will be produced. 31 | df : pandas.DataFrame 32 | If df is set, all x occurrences will be ignored. DataFrame of the 33 | input to be used for calculating the linear regression, 34 | This attribute can be useful, whenever a multi input to x does not 35 | get merged correctly. Note that linear_regression will only use the 36 | DataFrame.data array and ignore all other structural elements. 37 | plot : bool 38 | If True, the function will output a matplotlib Figure or plot into an 39 | existing instance. If False (default) the data used for the plots 40 | will be returned. 41 | ax : matplotlib.Axes.Axessubplot 42 | Has to be a single matplotlib Axes instance if two data sets are 43 | passed or a list of Axes if more than two data sets are passed. 44 | notext : bool 45 | If True, the output of the fitting parameters as a text into the plot 46 | will be suppressed. This setting is ignored, is plot is set to False. 47 | 48 | Returns 49 | ------- 50 | matplotlib.Figure 51 | numpy.ndarray 52 | 53 | Notes 54 | ----- 55 | 56 | If plot is True and ax is not None, the number of passed Axes has to match 57 | the total combinations between the data sets. This is 58 | 59 | .. math:: N^2 60 | 61 | where N is the length of x, or the length of df.columns. 62 | 63 | .. warning:: 64 | 65 | This function does just calculate a linear regression. It handles a 66 | multi input recursively and has some data wrangling overhead. If you are 67 | seeking a fast linear regression tool, use the scipy.stats.linregress 68 | function directly. 69 | 70 | """ 71 | # combine all inputs 72 | if df is None: 73 | df = merge(*x, dropna=True) 74 | 75 | if len(df.columns) == 2: 76 | slope, intercept, rvalue, pvalue, stderr = linregress(df.values[:, 0], 77 | df.values[:, 1]) 78 | 79 | # calculate regression 80 | reg = dict(slope=slope, intercept=intercept, rvalue=rvalue, 81 | pvalue=pvalue, stderr=stderr) 82 | 83 | # return data 84 | if not plot: 85 | return reg 86 | 87 | # return plot 88 | else: # pragma: no cover 89 | # build the ax if necessary 90 | if ax is None: 91 | fig, ax = plt.subplots(1, 1, figsize=(6, 6)) 92 | else: 93 | fig = ax.get_figure() 94 | 95 | ax.scatter(df.values[:, 0], df.values[:, 1], 25, marker='.', 96 | color='blue') 97 | if not notext: 98 | ax.text(0.05, 0.95, 99 | '\n'.join( 100 | ['%s: %.2f' % (k, v) for k, v in reg.items()]), 101 | ha='left', va='top', transform=ax.transAxes 102 | ) 103 | x = df.values[:, 0] 104 | y = x * reg['slope'] + reg['intercept'] 105 | ax.plot(x, y, '-g') 106 | 107 | return fig 108 | 109 | # more than two are given, call recursively 110 | else: 111 | # get the number of data sets 112 | n = len(df.columns) 113 | 114 | # create a plot 115 | if plot: # pragma: no cover 116 | if ax is None: 117 | fig, axes = plt.subplots(n, n, figsize=(n * 5, n * 5), 118 | sharex=True, sharey=True) 119 | else: 120 | axes = ax 121 | fig = axes.flatten()[0].get_figure() 122 | # make sure there are enough AxesSubplots 123 | assert len(axes.flatten()) == n * n 124 | 125 | # call linear regression for all combinations 126 | for i, col_names in zip( 127 | range(n * n), 128 | product(df.columns, df.columns) 129 | ): 130 | if col_names[0] == col_names[1]: 131 | # TODO: as soon as implemented, use the histogram tool here 132 | continue 133 | linear_regression(df=df[[*col_names]], 134 | plot=True, ax=axes.flatten()[i], 135 | notext=notext) 136 | 137 | # return the whole figure 138 | plt.tight_layout() 139 | return fig 140 | 141 | else: 142 | p = product(df.columns, df.columns) 143 | 144 | # define a sorting function 145 | # before the .values method of the resulting dictionary was used, 146 | # but Python 3.5 and 3.6 return the dictionary with a different 147 | # order. therefore a explicit sorting function is needed 148 | def to_array(d): 149 | return [d['slope'], d['intercept'], d['rvalue'], 150 | d['pvalue'], d['stderr']] 151 | 152 | # old function, kept for reference 153 | # to_array = lambda d: np.array(list(d.values())) 154 | res = [to_array(linear_regression(df[[*n]])) for n in p] 155 | 156 | # build the results 157 | np_res = [np.array(el).reshape((n, n)) for el in zip(*res)] 158 | for el in np_res: 159 | np.fill_diagonal(el, np.NaN) 160 | 161 | # extract and return 162 | slope, intercept, rvalue, pvalue, stderr = np_res 163 | return slope, intercept, rvalue, pvalue, stderr 164 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_gridsearch.rst: -------------------------------------------------------------------------------- 1 | 2 | .. DO NOT EDIT. 3 | .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. 4 | .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: 5 | .. "auto_examples/geostat/plot_gridsearch.py" 6 | .. LINE NUMBERS ARE GIVEN BELOW. 7 | 8 | .. only:: html 9 | 10 | .. note:: 11 | :class: sphx-glr-download-link-note 12 | 13 | Click :ref:`here ` 14 | to download the full example code 15 | 16 | .. rst-class:: sphx-glr-example-title 17 | 18 | .. _sphx_glr_auto_examples_geostat_plot_gridsearch.py: 19 | 20 | 21 | GridSearch optimization 22 | ======================= 23 | 24 | The SciKit-GStat package can be connected to scikit-learn i.e. to use 25 | the model optimization sub-package. In this example, different options 26 | are compared and cross-validated. 27 | The Interface has two different options to evaluate a variogram model fit: 28 | 29 | * goodness of fit measures of the spatial model itself 30 | * cross-validation of the variogram by interpolating the observation points 31 | 32 | Both options can use the RMSE, MSE and MAE as a metric. 33 | 34 | .. GENERATED FROM PYTHON SOURCE LINES 16-23 35 | 36 | .. code-block:: default 37 | 38 | import plotly 39 | import plotly.graph_objects as go 40 | import hydrobox 41 | from hydrobox.data import pancake 42 | from hydrobox.plotting import plotting_backend 43 | plotting_backend('plotly') 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | .. GENERATED FROM PYTHON SOURCE LINES 24-25 53 | 54 | Load sample data from the data sub-module 55 | 56 | .. GENERATED FROM PYTHON SOURCE LINES 25-28 57 | 58 | .. code-block:: default 59 | 60 | 61 | df = pancake() 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | .. GENERATED FROM PYTHON SOURCE LINES 29-31 71 | 72 | First, a Variogram is estimated, which will fix all arguments that 73 | should not be evaluated by the Grid Search. 74 | 75 | .. GENERATED FROM PYTHON SOURCE LINES 31-40 76 | 77 | .. code-block:: default 78 | 79 | 80 | vario = hydrobox.geostat.variogram( 81 | coordinates=df[['x', 'y']].values, 82 | values=df.z.values, 83 | maxlag=500, 84 | bin_func='kmeans', 85 | return_type='object' 86 | ) 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | .. GENERATED FROM PYTHON SOURCE LINES 41-44 96 | 97 | The next step is to create a parameter grid, which specifies the 98 | value space for each parameter that should be checked. 99 | Here, we will try all combinations of different models and lag classes. 100 | 101 | .. GENERATED FROM PYTHON SOURCE LINES 44-50 102 | 103 | .. code-block:: default 104 | 105 | 106 | param_grid = { 107 | 'model': ('spherical', 'exponential', 'matern'), 108 | 'n_lags': (15, 20, 25, 30, 35) 109 | } 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | .. GENERATED FROM PYTHON SOURCE LINES 51-53 119 | 120 | First the model fit itself is evaluated and only the best parameter 121 | set will be returned 122 | 123 | .. GENERATED FROM PYTHON SOURCE LINES 53-67 124 | 125 | .. code-block:: default 126 | 127 | 128 | best_param = hydrobox.geostat.gridsearch( 129 | param_grid=param_grid, 130 | variogram=vario, 131 | coordinates=None, # must be set if variogram is None 132 | values=None, # must be set if variogram is None 133 | score='rmse', # default 134 | cross_validate=False, # evaluate model fit, 135 | n_jobs=-1, # use parallel mode 136 | return_type='best_param' 137 | ) 138 | 139 | print(best_param) 140 | 141 | 142 | 143 | 144 | 145 | .. rst-class:: sphx-glr-script-out 146 | 147 | Out: 148 | 149 | .. code-block:: none 150 | 151 | {'model': 'spherical', 'n_lags': 35} 152 | 153 | 154 | 155 | 156 | .. GENERATED FROM PYTHON SOURCE LINES 68-71 157 | 158 | It is also possible to return the underlying 159 | :class:`GridSearchCV ` instance. 160 | This class holds way more information than just the best parameter. 161 | 162 | .. GENERATED FROM PYTHON SOURCE LINES 71-89 163 | 164 | .. code-block:: default 165 | 166 | 167 | # reun the same Gridsearch, return the object 168 | clf = hydrobox.geostat.gridsearch( 169 | param_grid=param_grid, 170 | variogram=vario, 171 | coordinates=None, # must be set if variogram is None 172 | values=None, # must be set if variogram is None 173 | score='rmse', # default 174 | cross_validate=False, # evaluate model fit, 175 | n_jobs=-1, # use parallel mode 176 | return_type='object' 177 | ) 178 | 179 | # get the scores and their std 180 | scores = clf.cv_results_['mean_test_score'] 181 | scores_std = clf.cv_results_['std_test_score'] 182 | x = list(range(len(scores))) 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | .. GENERATED FROM PYTHON SOURCE LINES 90-91 192 | 193 | Plot the result 194 | 195 | .. GENERATED FROM PYTHON SOURCE LINES 91-106 196 | 197 | .. code-block:: default 198 | 199 | fig = go.Figure() 200 | fig.add_trace( 201 | go.Scatter(x=x, y=scores, mode='lines', line_color='#A3ACF7', name='RMSE score') 202 | ) 203 | fig.add_trace( 204 | go.Scatter(x=x, y=scores + scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE + std') 205 | ) 206 | fig.add_trace( 207 | go.Scatter(x=x, y=scores - scores_std, mode='lines', line_color='#BAC1F2', fill='tonexty', name='RMSE - std') 208 | ) 209 | fig.update_layout( 210 | template='plotly_white' 211 | ) 212 | 213 | # show the plot 214 | plotly.io.show(fig) 215 | 216 | 217 | .. raw:: html 218 | :file: images/sphx_glr_plot_gridsearch_001.html 219 | 220 | 221 | 222 | 223 | 224 | 225 | .. rst-class:: sphx-glr-timing 226 | 227 | **Total running time of the script:** ( 1 minutes 23.717 seconds) 228 | 229 | 230 | .. _sphx_glr_download_auto_examples_geostat_plot_gridsearch.py: 231 | 232 | 233 | .. only :: html 234 | 235 | .. container:: sphx-glr-footer 236 | :class: sphx-glr-footer-example 237 | 238 | 239 | 240 | .. container:: sphx-glr-download sphx-glr-download-python 241 | 242 | :download:`Download Python source code: plot_gridsearch.py ` 243 | 244 | 245 | 246 | .. container:: sphx-glr-download sphx-glr-download-jupyter 247 | 248 | :download:`Download Jupyter notebook: plot_gridsearch.ipynb ` 249 | 250 | 251 | .. only:: html 252 | 253 | .. rst-class:: sphx-glr-signature 254 | 255 | `Gallery generated by Sphinx-Gallery `_ 256 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/plot_variogram.rst: -------------------------------------------------------------------------------- 1 | 2 | .. DO NOT EDIT. 3 | .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. 4 | .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: 5 | .. "auto_examples/geostat/plot_variogram.py" 6 | .. LINE NUMBERS ARE GIVEN BELOW. 7 | 8 | .. only:: html 9 | 10 | .. note:: 11 | :class: sphx-glr-download-link-note 12 | 13 | Click :ref:`here ` 14 | to download the full example code 15 | 16 | .. rst-class:: sphx-glr-example-title 17 | 18 | .. _sphx_glr_auto_examples_geostat_plot_variogram.py: 19 | 20 | 21 | Estimate a Variogram 22 | ==================== 23 | 24 | Use the geostatistics toolbox to estimate a variogram and use one of the many 25 | plots. These plots help to understand the spatial properties of a variogram, 26 | and finally, the :class:`Variogram ` object itself can be 27 | returned and used in one of the Kriging routines. 28 | 29 | .. GENERATED FROM PYTHON SOURCE LINES 11-18 30 | 31 | .. code-block:: default 32 | 33 | from pprint import pprint 34 | import plotly 35 | import hydrobox 36 | from hydrobox.data import pancake 37 | from hydrobox.plotting import plotting_backend 38 | plotting_backend('plotly') 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | .. GENERATED FROM PYTHON SOURCE LINES 19-20 48 | 49 | Load sample data from the data sub-module 50 | 51 | .. GENERATED FROM PYTHON SOURCE LINES 20-23 52 | 53 | .. code-block:: default 54 | 55 | 56 | df = pancake() 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | .. GENERATED FROM PYTHON SOURCE LINES 24-28 66 | 67 | Estimate a variogram using a exponential model and 25 distance lags 68 | that are derived from a KMeans cluster algorithm 69 | Here, we use the describe output option to get a dictionary of 70 | all variogram parameters 71 | 72 | .. GENERATED FROM PYTHON SOURCE LINES 28-40 73 | 74 | .. code-block:: default 75 | 76 | 77 | vario = hydrobox.geostat.variogram( 78 | coordinates=df[['x', 'y']].values, 79 | values=df.z.values, 80 | model='exponential', 81 | bin_func='kmeans', 82 | n_lags=25, 83 | return_type='describe' 84 | ) 85 | # print 86 | pprint(vario) 87 | 88 | 89 | 90 | 91 | 92 | .. rst-class:: sphx-glr-script-out 93 | 94 | Out: 95 | 96 | .. code-block:: none 97 | 98 | {'dist_func': 'euclidean', 99 | 'effective_range': 440.23387689607966, 100 | 'estimator': 'matheron', 101 | 'kwargs': {}, 102 | 'model': 'exponential', 103 | 'normalized_effective_range': 246442.01433239583, 104 | 'normalized_nugget': 0, 105 | 'normalized_sill': 2423777.7530702623, 106 | 'nugget': 0, 107 | 'params': {'bin_func': 'kmeans', 108 | 'dist_func': 'euclidean', 109 | 'estimator': 'matheron', 110 | 'fit_method': 'trf', 111 | 'fit_sigma': None, 112 | 'maxlag': None, 113 | 'model': 'exponential', 114 | 'n_lags': 25, 115 | 'normalize': False, 116 | 'use_nugget': False, 117 | 'verbose': False}, 118 | 'sill': 1556.8486609398685} 119 | 120 | 121 | 122 | 123 | .. GENERATED FROM PYTHON SOURCE LINES 41-43 124 | 125 | There are various return types, one of them is the plot. 126 | This is the main plotting tool for variogram instances 127 | 128 | .. GENERATED FROM PYTHON SOURCE LINES 43-55 129 | 130 | .. code-block:: default 131 | 132 | fig = hydrobox.geostat.variogram( 133 | coordinates=df[['x', 'y']].values, 134 | values=df.z.values, 135 | model='exponential', 136 | bin_func='kmeans', 137 | n_lags=25, 138 | return_type='plot' 139 | ) 140 | 141 | # show the figure 142 | plotly.io.show(fig) 143 | 144 | 145 | 146 | 147 | .. raw:: html 148 | :file: images/sphx_glr_plot_variogram_001.html 149 | 150 | 151 | 152 | 153 | 154 | .. GENERATED FROM PYTHON SOURCE LINES 56-58 155 | 156 | Alternatively you can return the :class:`Variogram ` 157 | object itself and use all the different settings and methods directly. 158 | 159 | .. GENERATED FROM PYTHON SOURCE LINES 58-70 160 | 161 | .. code-block:: default 162 | 163 | 164 | v = hydrobox.geostat.variogram( 165 | coordinates=df[['x', 'y']].values, 166 | values=df.z.values, 167 | model='exponential', 168 | bin_func='kmeans', 169 | n_lags=25, 170 | return_type='object' 171 | ) 172 | 173 | pprint(v) 174 | 175 | 176 | 177 | 178 | 179 | .. rst-class:: sphx-glr-script-out 180 | 181 | Out: 182 | 183 | .. code-block:: none 184 | 185 | < exponential Semivariogram fitted to 25 bins > 186 | 187 | 188 | 189 | 190 | .. GENERATED FROM PYTHON SOURCE LINES 71-74 191 | 192 | The :class:`Variogram ` has a plotting method for 193 | all point pairs at their separating distances. It is available as a 194 | return type, but can also be called directly: 195 | 196 | .. GENERATED FROM PYTHON SOURCE LINES 74-78 197 | 198 | .. code-block:: default 199 | 200 | fig = v.distance_difference_plot() 201 | 202 | plotly.io.show(fig) 203 | 204 | 205 | 206 | 207 | .. raw:: html 208 | :file: images/sphx_glr_plot_variogram_002.html 209 | 210 | 211 | 212 | 213 | 214 | .. GENERATED FROM PYTHON SOURCE LINES 79-86 215 | 216 | The variogram instance has a lot of quality measures to judge the goodness 217 | of fit for the theoretical model. They are implemented as properties and can 218 | be used like attribtues, while being always up to date if the variogram is mutated. 219 | Another helpful method is :func:`cross_validate `. 220 | This will run a leave-one-out cross validation by interpolating the missing point for 221 | all points. This is especially useful in cases, where a theoretical model fits well, 222 | but the spatial properties are not well captured. 223 | 224 | .. GENERATED FROM PYTHON SOURCE LINES 86-96 225 | 226 | .. code-block:: default 227 | 228 | 229 | # calculate the rmse of the model 230 | print(f"{v.model.__name__} RMSE: {v.rmse}") 231 | 232 | # get the cross-validation time 233 | from time import time 234 | t1 = time() 235 | rmse = v.cross_validate() 236 | t2 = time() 237 | print('Cross-validated RMSE: %.2f (took: %2fs)' % (rmse, t2 - t1)) 238 | 239 | 240 | 241 | 242 | .. rst-class:: sphx-glr-script-out 243 | 244 | Out: 245 | 246 | .. code-block:: none 247 | 248 | exponential RMSE: 39.91457083112962 249 | Cross-validated RMSE: 12.08 (took: 5.382931s) 250 | 251 | 252 | 253 | 254 | 255 | .. rst-class:: sphx-glr-timing 256 | 257 | **Total running time of the script:** ( 0 minutes 15.624 seconds) 258 | 259 | 260 | .. _sphx_glr_download_auto_examples_geostat_plot_variogram.py: 261 | 262 | 263 | .. only :: html 264 | 265 | .. container:: sphx-glr-footer 266 | :class: sphx-glr-footer-example 267 | 268 | 269 | 270 | .. container:: sphx-glr-download sphx-glr-download-python 271 | 272 | :download:`Download Python source code: plot_variogram.py ` 273 | 274 | 275 | 276 | .. container:: sphx-glr-download sphx-glr-download-jupyter 277 | 278 | :download:`Download Jupyter notebook: plot_variogram.ipynb ` 279 | 280 | 281 | .. only:: html 282 | 283 | .. rst-class:: sphx-glr-signature 284 | 285 | `Gallery generated by Sphinx-Gallery `_ 286 | -------------------------------------------------------------------------------- /hydrobox/data/pan_sample.csv: -------------------------------------------------------------------------------- 1 | x,y,z 2 | 102,435,190 3 | 348,270,218 4 | 106,71,162 5 | 188,20,208 6 | 102,121,229 7 | 466,214,132 8 | 330,458,165 9 | 87,372,203 10 | 99,359,165 11 | 151,130,184 12 | 149,308,207 13 | 257,343,194 14 | 491,413,171 15 | 293,385,152 16 | 191,443,106 17 | 276,160,221 18 | 459,313,99 19 | 21,252,196 20 | 235,344,209 21 | 48,474,196 22 | 58,169,126 23 | 475,187,137 24 | 463,270,124 25 | 189,445,105 26 | 174,445,142 27 | 50,363,209 28 | 54,243,200 29 | 319,130,234 30 | 484,306,114 31 | 134,20,216 32 | 328,166,217 33 | 273,387,150 34 | 88,315,217 35 | 13,241,201 36 | 264,345,191 37 | 52,385,202 38 | 339,91,238 39 | 366,443,138 40 | 454,427,153 41 | 263,430,190 42 | 34,205,143 43 | 80,419,196 44 | 49,359,210 45 | 387,1,227 46 | 389,53,231 47 | 105,259,214 48 | 309,476,167 49 | 190,401,189 50 | 217,43,227 51 | 161,201,212 52 | 445,483,159 53 | 269,350,197 54 | 303,270,212 55 | 455,461,150 56 | 214,251,192 57 | 189,295,162 58 | 212,207,179 59 | 236,337,194 60 | 366,52,223 61 | 279,409,173 62 | 216,251,177 63 | 187,379,191 64 | 492,40,160 65 | 156,14,222 66 | 300,64,245 67 | 344,326,129 68 | 8,343,199 69 | 128,491,189 70 | 135,471,188 71 | 62,138,197 72 | 498,80,184 73 | 391,162,214 74 | 418,288,136 75 | 378,260,216 76 | 489,230,110 77 | 40,27,216 78 | 134,200,171 79 | 327,267,218 80 | 417,32,229 81 | 47,406,195 82 | 61,215,103 83 | 292,98,225 84 | 171,359,172 85 | 213,474,130 86 | 34,448,187 87 | 226,100,176 88 | 430,461,157 89 | 130,256,215 90 | 4,217,218 91 | 254,397,179 92 | 358,282,187 93 | 392,206,211 94 | 14,345,199 95 | 41,379,209 96 | 460,178,200 97 | 62,351,201 98 | 230,240,179 99 | 51,95,225 100 | 387,221,208 101 | 484,406,174 102 | 230,236,178 103 | 142,170,178 104 | 28,35,218 105 | 12,159,193 106 | 326,186,221 107 | 242,85,194 108 | 283,65,243 109 | 169,44,215 110 | 61,440,190 111 | 133,283,218 112 | 27,107,218 113 | 43,339,203 114 | 285,445,175 115 | 330,127,228 116 | 347,472,153 117 | 230,189,189 118 | 224,384,174 119 | 376,282,165 120 | 445,120,221 121 | 115,460,197 122 | 232,258,224 123 | 358,197,216 124 | 455,410,165 125 | 136,317,203 126 | 164,224,225 127 | 306,233,197 128 | 171,151,167 129 | 462,314,95 130 | 373,159,215 131 | 95,471,189 132 | 232,179,206 133 | 112,317,216 134 | 496,441,147 135 | 51,267,191 136 | 294,385,152 137 | 386,112,226 138 | 100,112,170 139 | 439,80,225 140 | 186,112,185 141 | 1,129,215 142 | 219,53,215 143 | 342,484,164 144 | 223,224,181 145 | 384,402,122 146 | 125,129,179 147 | 52,171,118 148 | 217,159,220 149 | 197,415,184 150 | 246,323,191 151 | 438,202,188 152 | 183,122,187 153 | 400,254,213 154 | 293,279,211 155 | 324,371,134 156 | 97,197,129 157 | 469,394,181 158 | 239,143,198 159 | 96,200,141 160 | 123,186,145 161 | 325,463,166 162 | 348,258,218 163 | 147,251,216 164 | 442,419,109 165 | 402,345,97 166 | 450,146,211 167 | 147,351,196 168 | 198,307,207 169 | 488,416,171 170 | 423,127,221 171 | 38,337,202 172 | 359,128,229 173 | 266,475,184 174 | 440,472,159 175 | 433,150,216 176 | 414,477,151 177 | 297,98,229 178 | 262,251,181 179 | 143,345,189 180 | 111,499,184 181 | 59,368,204 182 | 1,384,203 183 | 303,253,213 184 | 139,452,179 185 | 36,159,181 186 | 8,232,211 187 | 98,146,141 188 | 303,207,221 189 | 130,403,202 190 | 151,53,181 191 | 119,160,161 192 | 407,115,223 193 | 74,112,189 194 | 455,419,163 195 | 421,103,227 196 | 339,253,211 197 | 226,111,196 198 | 472,98,228 199 | 152,348,204 200 | 401,383,110 201 | 365,337,110 202 | 193,309,201 203 | 162,207,225 204 | 444,168,207 205 | 483,160,199 206 | 67,288,204 207 | 397,276,218 208 | 303,403,143 209 | 383,391,115 210 | 134,194,167 211 | 400,127,220 212 | 32,175,175 213 | 459,442,158 214 | 370,469,134 215 | 374,21,233 216 | 237,157,193 217 | 37,229,204 218 | 364,50,222 219 | 437,263,212 220 | 282,26,243 221 | 225,276,230 222 | 285,96,215 223 | 283,366,172 224 | 447,480,155 225 | 452,316,101 226 | 303,146,223 227 | 3,34,222 228 | 191,48,226 229 | 16,171,211 230 | 219,157,199 231 | 476,45,189 232 | 372,5,230 233 | 98,379,211 234 | 232,36,235 235 | 279,348,157 236 | 496,301,109 237 | 180,94,197 238 | 98,187,130 239 | 480,115,198 240 | 190,252,221 241 | 468,415,162 242 | 470,160,195 243 | 255,322,187 244 | 127,17,221 245 | 280,489,171 246 | 222,53,216 247 | 57,322,202 248 | 359,173,218 249 | 279,113,192 250 | 287,430,202 251 | 341,150,205 252 | 449,126,218 253 | 154,489,184 254 | 385,473,127 255 | 272,103,200 256 | 416,392,115 257 | 298,245,216 258 | 175,38,216 259 | 476,169,203 260 | 246,25,222 261 | 354,305,148 262 | 408,407,115 263 | 12,315,202 264 | 390,312,141 265 | 35,172,155 266 | 19,320,202 267 | 263,493,160 268 | 399,141,220 269 | 459,370,148 270 | 470,142,207 271 | 91,353,157 272 | 321,287,179 273 | 214,446,131 274 | 341,50,232 275 | 152,185,170 276 | 62,189,109 277 | 124,149,182 278 | 313,57,241 279 | 341,304,166 280 | 179,169,187 281 | 325,270,223 282 | 53,490,187 283 | 443,100,223 284 | 480,263,118 285 | 52,59,193 286 | 491,107,185 287 | 4,102,192 288 | 195,261,209 289 | 364,479,129 290 | 371,349,95 291 | 46,354,205 292 | 310,423,145 293 | 307,143,225 294 | 268,369,199 295 | 123,105,152 296 | 157,146,166 297 | 144,119,173 298 | 318,274,217 299 | 91,57,187 300 | 438,345,105 301 | 228,473,159 302 | 116,317,214 303 | 278,126,221 304 | 392,395,131 305 | 128,57,168 306 | 121,0,217 307 | 238,289,209 308 | 95,125,165 309 | 117,47,203 310 | 88,487,187 311 | 236,372,156 312 | 384,271,218 313 | 188,486,177 314 | 191,446,97 315 | 68,277,204 316 | 348,246,208 317 | 450,75,225 318 | 153,143,170 319 | 434,484,166 320 | 85,184,137 321 | 284,461,142 322 | 219,68,206 323 | 46,496,181 324 | 93,237,218 325 | 445,499,152 326 | 452,203,139 327 | 399,217,209 328 | 473,431,156 329 | 340,38,235 330 | 99,288,194 331 | 253,221,139 332 | 356,22,236 333 | 249,9,209 334 | 245,324,173 335 | 99,289,193 336 | 179,222,226 337 | 393,249,216 338 | 146,441,185 339 | 95,256,213 340 | 324,492,158 341 | 3,15,216 342 | 279,335,149 343 | 246,257,213 344 | 496,475,138 345 | 383,159,219 346 | 474,339,146 347 | 151,395,183 348 | 177,162,178 349 | 379,32,239 350 | 416,444,121 351 | 178,426,188 352 | 100,267,223 353 | 322,64,240 354 | 416,167,205 355 | 329,42,238 356 | 43,284,208 357 | 396,11,218 358 | 94,301,212 359 | 385,252,213 360 | 498,241,172 361 | 34,214,194 362 | 336,89,241 363 | 263,92,216 364 | 409,457,133 365 | 89,417,196 366 | 114,104,150 367 | 390,195,208 368 | 313,113,225 369 | 492,74,183 370 | 412,375,105 371 | 419,216,203 372 | 276,248,181 373 | 163,393,170 374 | 356,456,142 375 | 407,191,206 376 | 226,176,200 377 | 98,495,185 378 | 35,465,183 379 | 496,486,147 380 | 95,151,133 381 | 150,189,173 382 | 223,36,232 383 | 267,368,198 384 | 182,12,212 385 | 278,216,143 386 | 354,360,105 387 | 285,272,203 388 | 368,61,229 389 | 83,367,197 390 | 216,341,208 391 | 396,186,205 392 | 18,176,216 393 | 99,395,211 394 | 444,232,161 395 | 402,75,229 396 | 264,454,182 397 | 283,205,175 398 | 222,383,172 399 | 51,338,200 400 | 366,143,219 401 | 372,68,230 402 | 98,395,210 403 | 24,435,189 404 | 378,468,134 405 | 483,52,194 406 | 150,143,170 407 | 56,38,207 408 | 108,180,128 409 | 41,185,129 410 | 422,397,109 411 | 222,121,180 412 | 132,162,164 413 | 214,220,184 414 | 234,330,190 415 | 145,238,225 416 | 75,8,225 417 | 73,441,191 418 | 491,400,177 419 | 252,229,140 420 | 6,173,214 421 | 140,167,172 422 | 169,392,180 423 | 433,282,128 424 | 121,193,148 425 | 4,28,222 426 | 164,421,182 427 | 338,135,226 428 | 495,364,195 429 | 320,341,132 430 | 499,144,196 431 | 326,216,218 432 | 300,131,225 433 | 291,69,247 434 | 251,414,187 435 | 274,444,176 436 | 363,181,214 437 | 166,90,168 438 | 201,345,210 439 | 18,38,221 440 | 125,450,194 441 | 172,140,206 442 | 241,219,145 443 | 125,57,169 444 | 147,475,180 445 | 455,316,101 446 | 382,360,87 447 | 422,0,202 448 | 386,460,131 449 | 347,189,218 450 | 190,368,195 451 | 408,311,147 452 | 416,421,106 453 | 116,133,168 454 | 57,43,203 455 | 172,159,175 456 | 172,316,204 457 | 302,148,223 458 | 79,373,201 459 | 212,202,171 460 | 251,228,144 461 | 163,226,229 462 | 146,19,225 463 | 440,401,110 464 | 46,232,188 465 | 304,13,229 466 | 142,414,196 467 | 0,372,192 468 | 53,373,206 469 | 258,143,228 470 | 470,440,152 471 | 458,11,176 472 | 329,223,215 473 | 271,455,165 474 | 357,459,140 475 | 407,155,213 476 | 372,7,231 477 | 121,347,171 478 | 163,89,160 479 | 135,185,166 480 | 315,177,218 481 | 27,219,207 482 | 356,40,227 483 | 227,191,198 484 | 410,446,109 485 | 144,200,168 486 | 416,211,196 487 | 460,219,122 488 | 239,412,186 489 | 396,45,235 490 | 34,252,196 491 | 389,81,230 492 | 370,255,211 493 | 196,302,191 494 | 408,449,123 495 | 9,311,203 496 | 285,241,197 497 | 250,364,193 498 | 4,118,218 499 | 288,373,170 500 | 64,145,212 501 | 223,238,179 502 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/sphx_glr_plot_gridsearch_001.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 | 7 | -------------------------------------------------------------------------------- /hydrobox/discharge/catchment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Common tools for diagnosic tools frequently used in catchment hydrology. 3 | 4 | """ 5 | from typing import Union, Optional, Any 6 | from matplotlib.axes import SubplotBase 7 | from matplotlib.pyplot import Figure 8 | import numpy as np 9 | import pandas as pd 10 | from datetime import datetime 11 | from scipy.stats import rankdata 12 | 13 | from hydrobox.plotting import plot_function_loader 14 | 15 | 16 | def flow_duration_curve( 17 | x: Union[np.ndarray, pd.Series], 18 | log: bool = True, 19 | plot: bool = True, 20 | non_exceeding:bool = True, 21 | ax: Optional[Union[SubplotBase, Any]] = None, 22 | **kwargs 23 | ) -> Union[np.ndarray, Figure]: 24 | """Calculate a flow duration curve 25 | 26 | Calculate flow duration curve from the discharge measurements. The 27 | function can either return a ``matplotlib`` plot or return the ordered ( 28 | non)-exceeding probabilities of the observations. These values can then 29 | be used in any external plotting environment. 30 | 31 | In case x.ndim > 1, the function will be called iteratively along axis 0. 32 | 33 | Parameters 34 | ---------- 35 | x : numpy.ndarray, pandas.Series 36 | Series of prefereably discharge measurements 37 | log : bool, default=True 38 | if `True` plot on loglog axis, ignored when plot is `False` 39 | plot : bool, default=True 40 | if `False` plotting will be suppressed and the resulting array will 41 | be returned 42 | non_exceeding : bool, default=True 43 | if `True` use non-exceeding probabilities 44 | ax : matplotlib.AxesSubplot | bokeh.Figure , default=None 45 | if not None, will plot into that AxesSubplot or Figure instance. 46 | .. note:: 47 | If you pass an object, be sure to set the correct plotting 48 | backend first. 49 | kwargs : kwargs, 50 | will be passed to the ``matplotlib.pyplot.plot`` function 51 | 52 | Returns 53 | ------- 54 | matplotlib.Figure : 55 | if `plot` was `True` 56 | numpy.ndarray : 57 | if `plot was `False` 58 | 59 | Notes 60 | ----- 61 | The probabilities are calculated using the Weibull empirical probability. 62 | Following [1]_, this probability can be calculated as: 63 | 64 | .. math:: p =m/(n + 1) 65 | 66 | where `m` is the rank of an observation in the ordered time series and 67 | `n` are the total observations. The increasion by one will prevent 0% 68 | and 100% probabilities. 69 | 70 | References 71 | ---------- 72 | .. [1] Sloto, R. a., & Crouse, M. Y. (1996). Hysep: a computer program 73 | for streamflow hydrograph separation and analysis. U.S. Geological 74 | Survey Water-Resources Investigations Report, 96(4040), 54. 75 | 76 | """ 77 | # omit the Series index 78 | if isinstance(x, pd.Series): 79 | x = x.values 80 | 81 | # if x has more than one dimension call this func recursive along axis=0 82 | if x.ndim > 1: 83 | # check if plot was None, then iterate along axis=0 84 | if not plot: 85 | return np.apply_along_axis(flow_duration_curve, 0, x, non_exceeding=non_exceeding, plot=False) 86 | else: 87 | # plot, if ax is None, create 88 | if ax is None: 89 | fig, ax = plt.subplots(1,1) 90 | last_ax = list(map(lambda x: flow_duration_curve(x, log=log, non_exceeding=non_exceeding, ax=ax), x.T))[-1] 91 | return last_ax 92 | 93 | # calculate the ranks 94 | ranks = rankdata(x, method='average') 95 | 96 | # calculate weibull pdf 97 | N = x.size 98 | 99 | # calculate probabilities 100 | p = np.fromiter(map(lambda r: r / (N + 1), ranks), dtype=np.float) 101 | 102 | # create sorting index 103 | if non_exceeding: 104 | index = np.argsort(p) 105 | else: 106 | index = np.argsort(p)[::-1] 107 | 108 | if not plot: 109 | return p[index] 110 | else: 111 | pfunc = plot_function_loader('flow_duration_curve') 112 | 113 | fig = pfunc(func_args=dict( 114 | x=x[index], 115 | y=p[index], 116 | non_exceeding=non_exceeding, 117 | log=log, 118 | figure=ax), 119 | plot_args=kwargs 120 | ) 121 | return fig 122 | 123 | 124 | def regime(x, percentiles=None, normalize=False, agg='nanmedian', plot=True, 125 | ax=None, cmap='blues', **kwargs): 126 | r"""Calculate hydrological regime 127 | 128 | Calculate a hydrological regime from discharge measurements. A regime is 129 | a annual overview, where all observations are aggregated across the 130 | month. Therefore it does only make sense to calculate a regime over more 131 | than one year with a temporal resolution higher than monthly. 132 | 133 | The regime can either be plotted or the calculated monthly aggreates can 134 | be returned (along with the quantiles, if any were calculated). 135 | 136 | Parameters 137 | ---------- 138 | x : pandas.Series 139 | The ``Series`` has to be indexed by a ``pandas.DatetimeIndex`` and 140 | hold the preferably discharge measurements. However, the methods 141 | does also work for other observables, if `agg` is adjusted. 142 | percentiles : int, list, numpy.ndarray, default=None 143 | percentiles can be used to calculate percentiles along with the main 144 | aggregate. The percentiles can either be set by an integer or a list. 145 | If an integer is passed, that many percentiles will be evenly spreaded 146 | between the 0th and 100th percentiles. A list can set the desired 147 | percentiles directly. 148 | normalize : bool, default=False 149 | If `True`, the regime will be normalized by the aggregate over all 150 | months. Then the numbers do not give the discharge itself, but the 151 | ratio of the monthly discharge to the overall discharge. 152 | agg : string, default='nanmedian' 153 | Define the function used for aggregation. Usually this will be 154 | 'mean' or 'median'. If there might be `NaN` values in the 155 | observations, the 'nan' prefixed functions can be used. In general, 156 | any aggregating function, which can be imported from ``numpy`` can 157 | be used. 158 | plot : bool, default=True 159 | if `False` plotting will be suppressed and the resulting 160 | ``pandas.DataFrame`` will be returned. In case `quantiles` was None, 161 | only the regime values will be returned as `numpy.ndarray` 162 | ax : matplotlib.AxesSubplot, default=None 163 | if not None, will plot into that AxesSubplot instance 164 | cmap : string, optional 165 | Specify a colormap for generating the Percentile areas is a smooth 166 | color gradient. This has to be a valid 167 | `colorcet colormap reference `_. 168 | Defaults to ``'Blue'``. 169 | color : string, optional 170 | Define the color of the main aggregate. If ``None``, the first color 171 | of the specified cmap will be used. 172 | lw : int, optinal 173 | linewidth parameter in pixel. Defaults to 3. 174 | linestyle : string, optional 175 | Any valid matplotlib linestyle definition is accepted. 176 | 177 | ``':'`` - dotted 178 | 179 | ``'-.'`` - dash-dotted 180 | 181 | ``'--'`` - dashed 182 | 183 | ``'-'`` - solid 184 | 185 | 186 | Returns 187 | ------- 188 | matplotlib.Figure : 189 | if `plot` was `True` 190 | pandas.DataFrame : 191 | if `plot` was `False` and `quantiles` are not None 192 | numpy.ndarray : 193 | if `plot` was `False` and `quantiles` is None 194 | 195 | Notes 196 | ----- 197 | 198 | In case the color argument is not passed it will default to the first 199 | color in the the specified colormap (cmap). You might want to overwrite 200 | this in case no percentiles are produced, as many colormaps range from 201 | light to dark colors and the first color might just default to while. 202 | 203 | """ 204 | if not isinstance(x.index, pd.DatetimeIndex): 205 | raise ValueError('Data has to be indexed by a pandas.DatetimeIndex.') 206 | 207 | # create the percentiles 208 | if isinstance(percentiles, int): 209 | percentiles = np.linspace(0, 100, percentiles + 1, endpoint=False)[1:] 210 | 211 | if callable(agg): 212 | f = agg 213 | else: 214 | try: 215 | f = getattr(np, agg) 216 | except AttributeError: 217 | raise ValueError('The function %s cannot be imported from numpy') 218 | 219 | # create month index 220 | idx = [int(datetime.strftime(_, '%m')) for _ in x.index] 221 | 222 | # aggregate the regime and set the index 223 | if isinstance(x, pd.Series): 224 | x = pd.DataFrame(index=x.index, data=x.values) 225 | df = x.groupby(idx).aggregate(f) 226 | df.set_index(np.unique(idx), inplace=True) 227 | 228 | # build percentiles 229 | if percentiles is not None: 230 | for q in percentiles: 231 | df['q%d' % q] = x.groupby(idx).aggregate( 232 | lambda v: np.nanpercentile(v, q)) 233 | 234 | # handle normalize 235 | if normalize: 236 | for col in df.columns: 237 | df[col] = df[col] / f(df[col]) 238 | 239 | if not plot: 240 | if len(df.columns) == 1: 241 | return df.values 242 | else: 243 | return df 244 | else: 245 | pfunc = plot_function_loader('regime') 246 | 247 | # check if a colormap was set 248 | fig = pfunc( 249 | func_args=dict(df=df, figure=ax, cmap=cmap), 250 | plot_args=kwargs 251 | ) 252 | 253 | return fig 254 | -------------------------------------------------------------------------------- /doc/auto_examples/geostat/images/sphx_glr_plot_variogram_001.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 | 7 | -------------------------------------------------------------------------------- /hydrobox/geostat/kriging.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union, Literal 2 | import numpy as np 3 | import skgstat as skg 4 | import plotly.graph_objects as go 5 | 6 | from hydrobox.plotting import plot_function_loader 7 | 8 | def _kriging( 9 | variogram: skg.Variogram, 10 | grid_resolution = None, 11 | return_type = 'plot', 12 | plot_kwargs = {}, 13 | **kwargs 14 | ) -> Union[List[np.ndarray], go.Figure]: 15 | """ 16 | Actual interface to gstools 17 | """ 18 | # get the kriging class 19 | krige = variogram.to_gs_krige(**kwargs) 20 | 21 | if return_type == 'object': 22 | return krige 23 | 24 | # build the grid 25 | if isinstance(grid_resolution, int): 26 | # get the coordinate ranges 27 | lower = np.min(variogram.coordinates, axis=0) 28 | upper = np.max(variogram.coordinates, axis=0) 29 | dims = [np.linspace(l, u, grid_resolution) for l, u in zip(lower, upper)] 30 | else: 31 | raise AttributeError('Right now, only integer grid_resolutions are supported.') 32 | 33 | # call structured 34 | field, sigma = krige.structured(dims) 35 | 36 | if return_type == 'grid': 37 | return (field, sigma) 38 | 39 | # return the plot 40 | if field.ndim > 2: 41 | raise ValueError('Plotting not supported for dim > 2.') 42 | 43 | pfunc = plot_function_loader('kriging') 44 | fig = pfunc( 45 | func_args=dict( 46 | variogram=variogram, 47 | field=field, 48 | sigma=sigma 49 | ), 50 | plot_args=plot_kwargs 51 | ) 52 | 53 | return fig 54 | 55 | 56 | def ordinary_kriging( 57 | variogram: skg.Variogram, 58 | grid_resolution: int, 59 | exact: bool = True, 60 | cond_err: Union[Literal['nugget'], float, list] = 'nugget', 61 | pseudo_inv: bool = True, 62 | pseudo_inv_type: Literal['pinv', 'pinv2', 'pinvh'] = 'pinv', 63 | return_type: Literal['object', 'plot', 'grid'] = 'plot', 64 | **kwargs 65 | ) -> Union[List[np.ndarray], go.Figure]: 66 | """ 67 | Use a scikit-gstat :class:`Variogram ` to estimate 68 | spatial properties of a sample. Uses this variogram to interpolate 69 | using kriging. The Kriging is done with the 70 | :class:`Ordinary ` class. Refer to the docs 71 | of :class:`Ordinary ` to learn about the 72 | parameters. 73 | 74 | .. note:: 75 | Right now, there are only very limited possibilities to specify 76 | an interpolation grid. Only setting the resolution of the result 77 | like: ``50x50`` is possible by passing the integer ``50``. 78 | More fine-grained control will be added with a future release. 79 | 80 | Parameters 81 | ---------- 82 | variogram : skgstat.Variogram 83 | Variogram used for kriging 84 | grid_resolution : int 85 | Resoultion of the interpolation grid. The resolution will be used 86 | in all input data dimensions, which can lead to non-quadratic 87 | grid cells. 88 | exact : bool 89 | If True (default), the input data will be matched exactly. 90 | Refer to :class:`Ordinary ` 91 | for more info. 92 | cond_err : str, float, list 93 | Measurement error, or variogram nugget. 94 | Refer to :class:`Ordinary ` 95 | for more info. 96 | pseudo_inv : bool 97 | If True, the Kriging is more robust, but also slower. 98 | Refer to :class:`Ordinary ` 99 | for more info. 100 | pseudo_inv_type : str 101 | Type of matrix inversion used if pseudo_inv is True. 102 | Refer to :class:`Ordinary ` 103 | for more info. 104 | return_type : str 105 | Specify how the result should be retuned. Can be the 106 | kriging class itself (``'object'``), the interpolated 107 | grid (``'grid'``) or a plot of the grid (``'plot'``). 108 | 109 | Returns 110 | ------- 111 | results : numpy.ndarray, numpy.ndarray 112 | Interpolation grid and kriging error grid 113 | fig : plotly.graph_objects.Figure, matplotlib.Figure 114 | Figure of the result plot. 115 | 116 | """ 117 | # build the kwargs 118 | args = dict( 119 | exact=exact, 120 | cond_err=cond_err, 121 | pseudo_inv=pseudo_inv, 122 | pseudo_inv_type=pseudo_inv_type 123 | ) 124 | 125 | # return the results 126 | return _kriging( 127 | variogram=variogram, 128 | grid_resolution=grid_resolution, 129 | return_type=return_type, 130 | plot_kwargs=kwargs, 131 | **args 132 | ) 133 | 134 | def simple_kriging( 135 | variogram: skg.Variogram, 136 | grid_resolution: int, 137 | mean: float, 138 | exact: bool = True, 139 | cond_err: Union[Literal['nugget'], float, list] = 'nugget', 140 | pseudo_inv: bool = True, 141 | pseudo_inv_type: Literal['pinv', 'pinv2', 'pinvh'] = 'pinv', 142 | 143 | return_type: Literal['object', 'plot', 'grid'] = 'plot', 144 | **kwargs 145 | ) -> Union[List[np.ndarray], go.Figure]: 146 | """ 147 | Use a scikit-gstat :class:`Variogram ` to estimate 148 | spatial properties of a sample. Uses this variogram to interpolate 149 | using kriging. The Kriging is done with the 150 | :class:`Simple ` class. Refer to the docs 151 | of :class:`Simple ` to learn about the 152 | parameters. 153 | 154 | For simple kriging you need to pass the real mean value of the 155 | field (not the sample) in order to work correctly. If that is not 156 | available, refer to :func:`ordinary_kriging `. 157 | 158 | .. note:: 159 | Right now, there are only very limited possibilities to specify 160 | an interpolation grid. Only setting the resolution of the result 161 | like: ``50x50`` is possible by passing the integer ``50``. 162 | More fine-grained control will be added with a future release. 163 | 164 | Parameters 165 | ---------- 166 | variogram : skgstat.Variogram 167 | Variogram used for kriging 168 | grid_resolution : int 169 | Resoultion of the interpolation grid. The resolution will be used 170 | in all input data dimensions, which can lead to non-quadratic 171 | grid cells. 172 | mean : float 173 | The mean value of the field, that has to be known a priori. 174 | If you pass bs here, you will interpolate bs. 175 | exact : bool 176 | If True (default), the input data will be matched exactly. 177 | Refer to :class:`Simple ` 178 | for more info. 179 | cond_err : str, float, list 180 | Measurement error, or variogram nugget. 181 | Refer to :class:`Simple ` 182 | for more info. 183 | pseudo_inv : bool 184 | If True, the Kriging is more robust, but also slower. 185 | Refer to :class:`Simple ` 186 | for more info. 187 | pseudo_inv_type : str 188 | Type of matrix inversion used if pseudo_inv is True. 189 | Refer to :class:`Simple ` 190 | for more info. 191 | return_type : str 192 | Specify how the result should be retuned. Can be the 193 | kriging class itself (``'object'``), the interpolated 194 | grid (``'grid'``) or a plot of the grid (``'plot'``). 195 | 196 | Returns 197 | ------- 198 | results : numpy.ndarray, numpy.ndarray 199 | Interpolation grid and kriging error grid 200 | fig : plotly.graph_objects.Figure, matplotlib.Figure 201 | Figure of the result plot. 202 | 203 | """ 204 | # build the kwargs 205 | args = dict( 206 | mean=mean, 207 | exact=exact, 208 | cond_err=cond_err, 209 | pseudo_inv=pseudo_inv, 210 | pseudo_inv_type=pseudo_inv_type 211 | ) 212 | 213 | # return the results 214 | return _kriging( 215 | variogram=variogram, 216 | grid_resolution=grid_resolution, 217 | return_type=return_type, 218 | plot_kwargs=kwargs, 219 | **args 220 | ) 221 | 222 | 223 | def universal_kriging( 224 | variogram: skg.Variogram, 225 | grid_resolution: int, 226 | drift_functions: Literal['linear', 'quadratic'], 227 | exact: bool = True, 228 | cond_err: Union[Literal['nugget'], float, list] = 'nugget', 229 | pseudo_inv: bool = True, 230 | pseudo_inv_type: Literal['pinv', 'pinv2', 'pinvh'] = 'pinv', 231 | 232 | return_type: Literal['object', 'plot', 'grid'] = 'plot', 233 | **kwargs 234 | ) -> Union[List[np.ndarray], go.Figure]: 235 | """ 236 | Use a scikit-gstat :class:`Variogram ` to estimate 237 | spatial properties of a sample. Uses this variogram to interpolate 238 | using kriging. The Kriging is done with the 239 | :class:`Universal ` class. Refer to the docs 240 | of :class:`Universal ` to learn about the 241 | parameters. 242 | 243 | For universal kriging you need to specify the interal drift term of 244 | the field. Then, this auto-regression will be taken into account 245 | for kriging. This is useful for fields, that acutally show a drift. 246 | If that is not the case, refer to 247 | :func:`ordinary_kriging ` or 248 | :func:`ext_drift_kriging ` for 249 | external drifts. 250 | 251 | .. note:: 252 | Right now, there are only very limited possibilities to specify 253 | an interpolation grid. Only setting the resolution of the result 254 | like: ``50x50`` is possible by passing the integer ``50``. 255 | More fine-grained control will be added with a future release. 256 | 257 | Parameters 258 | ---------- 259 | variogram : skgstat.Variogram 260 | Variogram used for kriging 261 | grid_resolution : int 262 | Resoultion of the interpolation grid. The resolution will be used 263 | in all input data dimensions, which can lead to non-quadratic 264 | grid cells. 265 | drift_functions : str 266 | The drift function used to perform regression kriging on the 267 | values of the sample. Can be either ``'linear'`` or ``'quadratic'``. 268 | Polynomials of higher order are currently only supported, if you use 269 | :class:`Universal ` directly. 270 | exact : bool 271 | If True (default), the input data will be matched exactly. 272 | Refer to :class:`Universal ` 273 | for more info. 274 | cond_err : str, float, list 275 | Measurement error, or variogram nugget. 276 | Refer to :class:`Universal ` 277 | for more info. 278 | pseudo_inv : bool 279 | If True, the Kriging is more robust, but also slower. 280 | Refer to :class:`Universal ` 281 | for more info. 282 | pseudo_inv_type : str 283 | Type of matrix inversion used if pseudo_inv is True. 284 | Refer to :class:`Universal ` 285 | for more info. 286 | return_type : str 287 | Specify how the result should be retuned. Can be the 288 | kriging class itself (``'object'``), the interpolated 289 | grid (``'grid'``) or a plot of the grid (``'plot'``). 290 | 291 | Returns 292 | ------- 293 | results : numpy.ndarray, numpy.ndarray 294 | Interpolation grid and kriging error grid 295 | fig : plotly.graph_objects.Figure, matplotlib.Figure 296 | Figure of the result plot. 297 | 298 | """ 299 | # build the kwargs 300 | args = dict( 301 | drift_functions=drift_functions, 302 | exact=exact, 303 | cond_err=cond_err, 304 | pseudo_inv=pseudo_inv, 305 | pseudo_inv_type=pseudo_inv_type 306 | ) 307 | 308 | # return the results 309 | return _kriging( 310 | variogram=variogram, 311 | grid_resolution=grid_resolution, 312 | return_type=return_type, 313 | plot_kwargs=kwargs, 314 | **args 315 | ) 316 | 317 | 318 | def ext_drift_kriging( 319 | variogram: skg.Variogram, 320 | grid_resolution: int, 321 | ext_drift: np.ndarray, 322 | exact: bool = True, 323 | cond_err: Union[Literal['nugget'], float, list] = 'nugget', 324 | pseudo_inv: bool = True, 325 | pseudo_inv_type: Literal['pinv', 'pinv2', 'pinvh'] = 'pinv', 326 | 327 | return_type: Literal['object', 'plot', 'grid'] = 'plot', 328 | **kwargs 329 | ) -> Union[List[np.ndarray], go.Figure]: 330 | """ 331 | Use a scikit-gstat :class:`Variogram ` to estimate 332 | spatial properties of a sample. Uses this variogram to interpolate 333 | using kriging. The Kriging is done with the 334 | :class:`ExtDrift ` class. Refer to the docs 335 | of :class:`ExtDrift ` to learn about the 336 | parameters. 337 | 338 | For external drift kriging you need to specify the external drift term of 339 | the field. Then, the regression between drift and sample will be taken 340 | into account for kriging. This is useful for fields, that are actually 341 | correlated to other fields, which are (more) available. 342 | If that is not the case, refer to 343 | :func:`ordinary_kriging ` for kriging 344 | without drift. 345 | 346 | .. note:: 347 | Right now, there are only very limited possibilities to specify 348 | an interpolation grid. Only setting the resolution of the result 349 | like: ``50x50`` is possible by passing the integer ``50``. 350 | More fine-grained control will be added with a future release. 351 | 352 | Parameters 353 | ---------- 354 | variogram : skgstat.Variogram 355 | Variogram used for kriging 356 | grid_resolution : int 357 | Resoultion of the interpolation grid. The resolution will be used 358 | in all input data dimensions, which can lead to non-quadratic 359 | grid cells. 360 | ext_drift : np.ndarray 361 | External drift values at the observation points 362 | exact : bool 363 | If True (default), the input data will be matched exactly. 364 | Refer to :class:`ExtDrift ` 365 | for more info. 366 | cond_err : str, float, list 367 | Measurement error, or variogram nugget. 368 | Refer to :class:`ExtDrift ` 369 | for more info. 370 | pseudo_inv : bool 371 | If True, the Kriging is more robust, but also slower. 372 | Refer to :class:`ExtDrift ` 373 | for more info. 374 | pseudo_inv_type : str 375 | Type of matrix inversion used if pseudo_inv is True. 376 | Refer to :class:`ExtDrift ` 377 | for more info. 378 | return_type : str 379 | Specify how the result should be retuned. Can be the 380 | kriging class itself (``'object'``), the interpolated 381 | grid (``'grid'``) or a plot of the grid (``'plot'``). 382 | 383 | Returns 384 | ------- 385 | results : numpy.ndarray, numpy.ndarray 386 | Interpolation grid and kriging error grid 387 | fig : plotly.graph_objects.Figure, matplotlib.Figure 388 | Figure of the result plot. 389 | 390 | """ 391 | # build the kwargs 392 | args = dict( 393 | ext_drift=ext_drift, 394 | exact=exact, 395 | cond_err=cond_err, 396 | pseudo_inv=pseudo_inv, 397 | pseudo_inv_type=pseudo_inv_type 398 | ) 399 | 400 | # return the results 401 | return _kriging( 402 | variogram=variogram, 403 | grid_resolution=grid_resolution, 404 | return_type=return_type, 405 | plot_kwargs=kwargs, 406 | **args 407 | ) 408 | -------------------------------------------------------------------------------- /hydrobox/data/sample_lr.csv: -------------------------------------------------------------------------------- 1 | x,y,z 2 | 94,20,0.17661322082829045 3 | 82,37,-0.3207010463901736 4 | 43,13,-1.5791608633401637 5 | 78,42,-0.12918176158773187 6 | 50,28,0.06193013878439768 7 | 20,74,-1.6374827765933684 8 | 71,88,-1.858503546615741 9 | 7,9,-2.2898204111891904 10 | 24,69,-1.3764931871575385 11 | 77,28,-0.51886478030234 12 | 71,17,-1.1181432792909387 13 | 29,74,-0.748229238419845 14 | 49,59,-0.6779915431776902 15 | 100,12,0.6980337958864397 16 | 5,52,-1.8623145942239685 17 | 16,82,-1.525733702020418 18 | 16,17,-2.235361716564011 19 | 88,58,-0.9473674557929835 20 | 52,49,-0.6218424486113452 21 | 63,85,-0.7137101006679549 22 | 26,13,-2.233203327988773 23 | 19,36,-2.7690793642446856 24 | 36,79,0.0885996449094657 25 | 57,97,-1.2891444652552995 26 | 62,99,-1.6955816715574992 27 | 32,30,-1.636720746148537 28 | 39,59,-0.6014147884625802 29 | 29,90,-0.3405554569305569 30 | 99,32,-1.0648224187732502 31 | 44,6,-1.780445089380506 32 | 43,58,-0.707720879391547 33 | 85,39,-0.2971655349137281 34 | 70,54,-0.562919352659155 35 | 91,79,-1.9355653555392103 36 | 72,73,-0.8608591121279774 37 | 26,14,-2.1637093061703965 38 | 74,27,-0.6562635968364894 39 | 95,81,-1.9809567707197226 40 | 57,64,-0.38711158283427416 41 | 91,89,-1.87401068011749 42 | 16,15,-2.2566753026598363 43 | 43,64,-0.18779952749791776 44 | 51,23,-0.24391077717583054 45 | 48,15,-1.0182932663054767 46 | 44,62,-0.3916939427844982 47 | 89,87,-1.9013742125644497 48 | 75,44,-0.12259321072147955 49 | 28,60,-1.2435869570024023 50 | 40,15,-1.6411211195497688 51 | 93,11,0.9901342952119029 52 | 15,63,-1.8971163726900049 53 | 88,29,-0.3906580021712931 54 | 2,23,-2.297950025708991 55 | 46,96,-0.5177499765223532 56 | 65,3,-0.6385024731290623 57 | 88,37,-0.43989363732161757 58 | 65,95,-1.615015156438801 59 | 41,7,-2.066419299383491 60 | 25,80,-1.1585321573984553 61 | 21,27,-2.3369205465026006 62 | 91,12,0.8747629151859433 63 | 32,81,-0.3357578212761244 64 | 65,83,-0.7916270264730879 65 | 72,27,-0.7166782020050888 66 | 31,80,-0.4456177296618178 67 | 34,77,-0.09253809790344958 68 | 75,52,-0.4944770605931659 69 | 83,57,-0.8842660134072124 70 | 53,54,-0.688018526555087 71 | 5,48,-1.9007745541601544 72 | 63,37,-0.036396820195912394 73 | 52,88,-0.11755753250379702 74 | 52,80,0.26083445224418955 75 | 88,59,-1.0235448405655787 76 | 82,40,-0.21308806967593508 77 | 88,97,-2.192149582082118 78 | 16,39,-2.57650062187516 79 | 50,30,0.08647437324546103 80 | 94,10,1.0438097256819132 81 | 32,38,-1.7634540702631607 82 | 44,24,-0.5655178353752265 83 | 49,69,0.10714984406004735 84 | 80,28,-0.4022423169385094 85 | 44,97,-0.3529837795434546 86 | 9,72,-1.493369502775304 87 | 62,83,-0.43023196900276084 88 | 55,87,-0.13966611700693143 89 | 73,88,-2.001203548269883 90 | 74,77,-1.2379156042029587 91 | 41,10,-1.9249687471386818 92 | 80,70,-1.1829197791574524 93 | 84,91,-2.0139814304259325 94 | 19,41,-2.648833447808755 95 | 74,95,-2.144917804214962 96 | 53,77,0.33511688709641435 97 | 77,71,-1.0958441907152565 98 | 26,80,-1.0484840863497462 99 | 60,29,-0.15746426177681877 100 | 87,66,-1.4554380448773045 101 | 49,26,-0.05826749235010553 102 | 58,7,-0.47144621640817697 103 | 83,34,-0.39094849493512274 104 | 98,71,-1.9237550851324507 105 | 19,33,-2.724482730994292 106 | 69,37,-0.19617085984139937 107 | 77,16,-0.6982227690277982 108 | 17,5,-2.679609599992811 109 | 12,3,-2.393815880403184 110 | 36,10,-2.200362886449826 111 | 60,92,-0.9653420438677074 112 | 87,26,-0.22706606640650318 113 | 42,88,-0.017394586984581628 114 | 95,68,-1.7949386705859134 115 | 26,73,-1.1494570516013114 116 | 75,87,-2.0476740998248477 117 | 8,72,-1.453241687219668 118 | 72,38,-0.2239143636791041 119 | 91,53,-0.5343666751715851 120 | 17,43,-2.470978552057021 121 | 78,44,-0.11886190567323107 122 | 47,80,0.29971188155784123 123 | 44,90,-0.14506121193081833 124 | 14,73,-1.6464001409249398 125 | 1,99,0.8621365077720762 126 | 89,52,-0.517258377611627 127 | 44,88,-0.0363550476333383 128 | 56,6,-0.4356724214414587 129 | 70,64,-0.7483161345237008 130 | 40,85,0.11266127425524186 131 | 46,21,-0.6348481212770275 132 | 41,39,-0.9151652582357036 133 | 45,93,-0.32709656867469084 134 | 8,46,-1.956116172182285 135 | 29,41,-2.0518284286335646 136 | 32,98,0.5108174703489414 137 | 80,100,-2.3718975366467783 138 | 65,94,-1.558318900246572 139 | 26,63,-1.3136947673080608 140 | 49,6,-1.0853779497566807 141 | 56,48,-0.4746929723443394 142 | 22,92,-0.050939348864365686 143 | 56,35,0.10521867373159269 144 | 66,26,-0.6878157094089083 145 | 48,67,-0.04724092238592936 146 | 100,75,-1.9502445541949465 147 | 81,75,-1.380494282386387 148 | 33,49,-1.37446193234031 149 | 27,99,0.7820546540086415 150 | 85,68,-1.397462150202891 151 | 82,71,-1.2858483945142325 152 | 80,82,-1.8152881183906717 153 | 65,13,-1.0749494112946858 154 | 96,76,-2.071341870001821 155 | 2,74,-1.1474806263319375 156 | 85,31,-0.3949454326592716 157 | 4,33,-2.0216392960998353 158 | 67,50,-0.3776767866561772 159 | 55,83,0.09336374628318461 160 | 15,38,-2.5498408545196662 161 | 71,100,-2.124660532422709 162 | 83,1,0.00753106904473122 163 | 88,45,-0.29848335196099796 164 | 39,95,-0.017715934399532784 165 | 25,6,-2.7799209048687734 166 | 100,49,-0.8099195511680906 167 | 44,86,0.07335949065343661 168 | 18,92,-0.02618846088130722 169 | 89,36,-0.49680436983084364 170 | 7,35,-2.087743834816001 171 | 63,46,-0.21817431581240973 172 | 22,84,-1.1700386981447077 173 | 68,34,-0.3061988541921356 174 | 96,11,1.0078034603595811 175 | 87,38,-0.38175987635970254 176 | 29,79,-0.6963000891333997 177 | 83,59,-0.981709233461278 178 | 82,99,-2.3483083534752787 179 | 65,17,-1.0499038793943516 180 | 11,54,-2.0803785700683717 181 | 70,100,-2.0839131681963616 182 | 89,27,-0.3176001715557155 183 | 59,70,0.055612810840010185 184 | 57,19,-0.6883903772704523 185 | 14,47,-2.1729197642131926 186 | 77,1,-0.5267518387415159 187 | 64,6,-0.7333618231393997 188 | 81,29,-0.3902969453115981 189 | 78,97,-2.2302849940746485 190 | 98,48,-0.7387425066645357 191 | 13,16,-2.2739593266738316 192 | 53,92,-0.5402081195779718 193 | 82,7,-0.2123184354314288 194 | 6,56,-1.8080489427304802 195 | 15,51,-2.2052121688938855 196 | 90,76,-1.8663876215638298 197 | 24,11,-2.417109991316271 198 | 70,15,-1.1805092648280848 199 | 42,82,0.2630835801096074 200 | 88,40,-0.373680890383314 201 | 85,88,-1.9428871090998012 202 | 10,71,-1.5196561538025293 203 | 23,88,-0.6562316524018308 204 | 98,73,-2.000726315288191 205 | 65,57,-0.6868317632131439 206 | 32,16,-1.8735371946700585 207 | 50,93,-0.5418013679886537 208 | 60,24,-0.4798449995240417 209 | 13,71,-1.6127038067606148 210 | 11,32,-2.4717564222383475 211 | 52,82,0.19495400241951066 212 | 54,66,-0.1673704661258293 213 | 39,41,-1.0884098541110165 214 | 95,32,-0.8090650853502542 215 | 31,13,-2.1201157878945995 216 | 88,18,0.41588964674209783 217 | 4,96,0.7992532380652542 218 | 43,31,-0.5503366257619469 219 | 26,17,-1.9899582693934583 220 | 38,73,0.2160606828095507 221 | 61,50,-0.39970101959180576 222 | 76,34,-0.4454865189856453 223 | 19,79,-1.6303187866323594 224 | 77,92,-2.163166980019689 225 | 77,98,-2.2465901175266922 226 | 43,26,-0.5811592080226924 227 | 27,44,-2.1659560829252635 228 | 83,37,-0.32736459067796686 229 | 87,44,-0.25946413563689963 230 | 10,32,-2.4009731778059358 231 | 99,81,-1.84711795069224 232 | 83,42,-0.170447818369019 233 | 46,42,-0.5598270985322223 234 | 95,31,-0.7854633078108808 235 | 74,35,-0.40003093809914714 236 | 17,11,-2.4055715871298533 237 | 72,95,-2.07321342744388 238 | 11,9,-2.378030753046553 239 | 20,96,0.6070206479774166 240 | 7,99,1.1549742981454196 241 | 80,91,-2.108705875301451 242 | 55,44,-0.33029033830123533 243 | 39,97,0.0869365336455864 244 | 85,66,-1.3447517859904923 245 | 77,58,-0.7596157342630092 246 | 63,28,-0.40013088372553773 247 | 13,85,-1.1694233617957366 248 | 16,34,-2.7083348507444938 249 | 40,50,-0.9975796979615644 250 | 80,14,-0.34663881702460553 251 | 47,16,-1.0272045496768052 252 | 100,77,-1.933338746114981 253 | 38,37,-1.19666485903018 254 | 88,49,-0.376030345473334 255 | 81,31,-0.4126154276943079 256 | 94,27,-0.5431767284514204 257 | 45,84,0.16637372642528714 258 | 47,2,-1.4629518756615267 259 | 61,58,-0.6693361835816842 260 | 97,14,0.7277068357623439 261 | 31,33,-1.784518372104861 262 | 68,28,-0.6484261059439498 263 | 92,71,-1.9091105207618067 264 | 58,25,-0.2990684187478496 265 | 27,23,-1.8509669330818217 266 | 32,67,-0.43981530630801824 267 | 54,36,0.07160993532756277 268 | 88,57,-0.8724587676276928 269 | 61,19,-0.8202804612468682 270 | 48,86,0.04737373834869518 271 | 65,45,-0.1603088069708744 272 | 42,46,-0.9030319241688518 273 | 75,23,-0.6996396596136966 274 | 3,94,0.5935545401356204 275 | 49,25,-0.119924124206507 276 | 83,98,-2.2962661247365572 277 | 55,68,0.005055518821373728 278 | 86,42,-0.24681158077717424 279 | 65,77,-0.31109737877072463 280 | 76,16,-0.8070442492571166 281 | 52,4,-0.7120755312685864 282 | 60,35,0.025353676484393836 283 | 3,44,-1.8841880519984286 284 | 44,22,-0.7109857890284509 285 | 90,64,-1.441133243180356 286 | 23,77,-1.4255213743863067 287 | 83,60,-1.0258471197761212 288 | 55,49,-0.5337726100012276 289 | 27,78,-0.9633024499031962 290 | 78,29,-0.48083268587573513 291 | 86,44,-0.22312828850070832 292 | 11,47,-2.0301206045123497 293 | 80,42,-0.13680844933323422 294 | 88,90,-1.9287367785011216 295 | 22,27,-2.2767585014155842 296 | 19,37,-2.7624806147649297 297 | 25,43,-2.3951643666403806 298 | 3,81,-1.0522323698108018 299 | 58,93,-0.9157170129985064 300 | 62,78,-0.06808766637252983 301 | 80,84,-1.9245503368082435 302 | 84,20,0.05197178054786278 303 | 7,92,0.25640730675505585 304 | 29,83,-0.6635008628255967 305 | 79,18,-0.42852333773414775 306 | 55,11,-0.6772572424783635 307 | 67,4,-0.8145840905452186 308 | 95,67,-1.7125262821861973 309 | 26,98,0.6988532821573911 310 | 69,98,-1.9829209172948892 311 | 52,21,-0.43413164518615915 312 | 41,31,-0.7894071008395798 313 | 1,32,-2.021082447595921 314 | 67,26,-0.7286519848015482 315 | 12,78,-1.6099048966492246 316 | 7,43,-1.9503287681291854 317 | 88,70,-1.6441213899982543 318 | 23,79,-1.3839146024857325 319 | 59,61,-0.6061669487715279 320 | 40,76,0.33647237902735977 321 | 99,93,-1.5131556276360314 322 | 4,61,-1.312841069859096 323 | 47,99,-0.7054180640384552 324 | 31,96,0.2957618701695621 325 | 67,79,-0.6816015728870042 326 | 18,23,-2.305234257266516 327 | 47,65,-0.2054151646239622 328 | 16,60,-2.0583054033899275 329 | 72,4,-0.9478750623013474 330 | 98,69,-1.8022541761504738 331 | 62,7,-0.6519758224492036 332 | 96,60,-0.9147423631400617 333 | 45,96,-0.4325546141387169 334 | 77,74,-1.2088699196705512 335 | 5,8,-2.194439503020854 336 | 35,70,-0.059516207326285375 337 | 97,41,-0.9469436721204711 338 | 97,67,-1.6674138401181522 339 | 45,19,-0.9075864481672704 340 | 45,78,0.36708512139085625 341 | 65,61,-0.748316957891198 342 | 58,97,-1.3413376504593888 343 | 89,53,-0.5736887108603895 344 | 1,40,-1.8799341171740838 345 | 84,42,-0.19021339943706572 346 | 41,46,-0.9493165165250845 347 | 32,96,0.27163824403899306 348 | 97,34,-0.9677459536912152 349 | 81,3,-0.28535499483789384 350 | 24,91,-0.2259835810942934 351 | 27,31,-2.0907366075979077 352 | 20,25,-2.2928609179030985 353 | 100,6,1.067384126216814 354 | 37,45,-1.1833548239475973 355 | 47,9,-1.315514618566741 356 | 22,58,-1.936113932900406 357 | 78,80,-1.6619949712899333 358 | 26,77,-1.1033306062531536 359 | 1,22,-2.3487546957332164 360 | 5,60,-1.48510109836679 361 | 22,17,-2.1084750910363876 362 | 71,39,-0.16659605253694498 363 | 70,17,-1.139012471863528 364 | 71,8,-1.1218376152974852 365 | 20,28,-2.4480672386179525 366 | 23,63,-1.610499822368222 367 | 61,34,-0.01828317470181351 368 | 10,60,-1.8785428385222194 369 | 63,11,-0.916863005355644 370 | 37,7,-2.332207067259491 371 | 64,89,-1.1438171215681223 372 | 29,29,-1.8519176365738326 373 | 46,84,0.15844410900332428 374 | 57,63,-0.45736648768143506 375 | 9,60,-1.8149892954947524 376 | 48,1,-1.3449425893591203 377 | 81,15,-0.1953620011462096 378 | 3,61,-1.2034451897431466 379 | 86,86,-1.9026864308593892 380 | 31,49,-1.5507323627899527 381 | 93,60,-1.0013008675210189 382 | 75,65,-0.886044305016085 383 | 89,5,0.6478414118880481 384 | 62,67,-0.3431391216275167 385 | 57,60,-0.5907989022911636 386 | 32,34,-1.7171286885541428 387 | 18,59,-2.0770792021233886 388 | 40,90,-0.08639875271252495 389 | 53,37,0.012997939662930585 390 | 40,97,0.013203527911123558 391 | 79,36,-0.356042452522373 392 | 37,46,-1.1647165176333263 393 | 61,40,-0.0547529676783714 394 | 99,82,-1.800638229375744 395 | 63,47,-0.2561718226661246 396 | 91,49,-0.42857777335179514 397 | 70,44,-0.12630305000354325 398 | 86,51,-0.47911901752063457 399 | 58,50,-0.46887219639213473 400 | 37,28,-1.2114636319137753 401 | 74,18,-0.9325395373565384 402 | 59,41,-0.11070353287488192 403 | 50,61,-0.5585685919820131 404 | 73,21,-0.8953220244754807 405 | 92,62,-1.2450189362445978 406 | 81,71,-1.2440186870693406 407 | 72,49,-0.32780406293231573 408 | 96,3,1.054319840949935 409 | 78,51,-0.46279424792813195 410 | 11,64,-1.7091771536050244 411 | 68,23,-0.9110161835295323 412 | 28,79,-0.823395549557471 413 | 60,48,-0.35456214936511354 414 | 76,6,-0.8615152042689993 415 | 24,73,-1.3678209248300819 416 | 13,7,-2.4515669549145724 417 | 4,3,-1.9498434591068001 418 | 7,53,-1.9290225738898186 419 | 12,7,-2.418516576259508 420 | 99,72,-1.9325668641061262 421 | 66,81,-0.7358032564110454 422 | 2,75,-1.1707297873798912 423 | 67,71,-0.420981565968635 424 | 94,30,-0.6913426735657044 425 | 73,97,-2.1361420384354397 426 | 59,92,-0.8829228787658867 427 | 82,72,-1.3083179436683112 428 | 19,92,-0.028828354963474023 429 | 69,5,-0.9638369921319903 430 | 67,28,-0.6128224198310096 431 | 79,89,-2.101636806194354 432 | 62,30,-0.22208337378938717 433 | 25,23,-1.9555335612504359 434 | 12,28,-2.5624736756175657 435 | 6,45,-1.9278542557900962 436 | 92,25,-0.2760868564813428 437 | 67,100,-1.9552508699403284 438 | 82,55,-0.7602476434380687 439 | 11,26,-2.5069910827523585 440 | 99,70,-1.8343681155255418 441 | 53,75,0.3552749480824071 442 | 49,73,0.3241301743686026 443 | 96,14,0.78289761078143 444 | 72,17,-1.0815041828102399 445 | 41,100,0.04213124501571175 446 | 45,88,-0.048093515823306454 447 | 99,16,0.32887973839150275 448 | 1,34,-1.9680331184997661 449 | 13,42,-2.2386113092934687 450 | 8,58,-1.853650829040446 451 | 43,28,-0.5383918545554864 452 | 72,69,-0.8038614480322568 453 | 21,17,-2.1353707762667185 454 | 80,86,-2.0046117471599034 455 | 71,97,-2.055967866773185 456 | 13,33,-2.578213319566314 457 | 61,13,-0.8810555940007759 458 | 12,87,-0.8426089055446344 459 | 79,8,-0.5811807367316317 460 | 23,86,-0.9092037573862705 461 | 31,47,-1.6316822461199156 462 | 54,2,-0.5417380967547616 463 | 44,19,-0.9872845795374234 464 | 49,75,0.357997087066144 465 | 73,77,-1.1612530511763641 466 | 8,73,-1.468353641733726 467 | 57,99,-1.4648346434962636 468 | 36,18,-1.5908363980043303 469 | 16,69,-1.6868599108054636 470 | 46,49,-0.826752683752012 471 | 69,10,-1.1595643593431566 472 | 99,91,-1.5068502733465463 473 | 37,52,-1.0455233936432196 474 | 76,78,-1.4347754493813079 475 | 70,46,-0.19017865664948308 476 | 91,64,-1.4521251539864188 477 | 19,47,-2.4037145669655398 478 | 40,10,-1.9989670407724591 479 | 66,19,-1.0262669276590644 480 | 7,46,-1.939853583864939 481 | 27,9,-2.504554859498235 482 | 19,48,-2.3716311464795954 483 | 2,52,-1.7060702157320724 484 | 95,71,-1.9742139843402908 485 | 92,72,-1.934879748125853 486 | 27,1,-3.0181060405737363 487 | 30,56,-1.2841282179990154 488 | 84,25,-0.19921755576101363 489 | 79,54,-0.6563564412172758 490 | 15,35,-2.6483938360699755 491 | 77,14,-0.735759456289288 492 | 41,98,-0.033625414188334646 493 | 22,49,-2.299453645239997 494 | 63,56,-0.6378721190276777 495 | 53,62,-0.4843086761189376 496 | 21,9,-2.5827204873043303 497 | 8,96,0.7946327615226626 498 | 52,2,-0.754913074602668 499 | 20,67,-1.6690371109347628 500 | 18,83,-1.4232192696269024 501 | 64,16,-1.0283709710489455 502 | 41,76,0.3644623684844036 503 | 48,79,0.3169191256645389 504 | 62,60,-0.7058589423367679 505 | 100,73,-1.9222564003535763 506 | 42,40,-0.832808464693552 507 | 7,78,-1.414982875357314 508 | 96,75,-2.0704780539929595 509 | 22,68,-1.545121905758538 510 | 42,19,-1.1483937846750991 511 | 35,51,-1.166306563550643 512 | 29,65,-0.8708666365676441 513 | 35,76,0.00722323097117239 514 | 47,23,-0.3813558808654251 515 | 83,99,-2.3588068406610763 516 | 30,77,-0.5811664980967979 517 | 4,43,-1.899153965375696 518 | 40,72,0.28324095177112796 519 | 86,60,-1.0905265086471922 520 | 68,6,-0.9766633246008862 521 | 33,59,-0.8196386861865608 522 | 30,44,-1.850673116613042 523 | 71,96,-2.0389408116947796 524 | 8,44,-1.967314326298686 525 | 31,38,-1.864777676695268 526 | 31,14,-2.0465441981219863 527 | 98,37,-1.0481313396199918 528 | 18,24,-2.347170022536147 529 | 79,42,-0.13197019430705736 530 | 1,92,0.38008376892995965 531 | 23,87,-0.7880517661770725 532 | 99,10,0.9398485442782152 533 | 32,63,-0.6181002624147119 534 | 98,97,-1.7072518247457567 535 | 8,5,-2.2368617974728298 536 | 32,52,-1.3339795788255935 537 | 95,51,-0.5028913235800136 538 | 92,67,-1.711462234964014 539 | 56,21,-0.5264511833890746 540 | 44,44,-0.7527344417279833 541 | 12,40,-2.2447363711366464 542 | 13,40,-2.3169290792000594 543 | 54,12,-0.7356217320781144 544 | 6,100,1.227254092127576 545 | 42,96,-0.17716294683257372 546 | 82,52,-0.5592924583984337 547 | 32,10,-2.3049674861935054 548 | 72,24,-0.8278308849032249 549 | 68,85,-1.345706748298969 550 | 97,60,-0.8969469937794285 551 | 45,18,-1.0051614878225805 552 | 56,14,-0.7698223750997265 553 | 84,19,0.09564099940832538 554 | 36,56,-0.8914996152478826 555 | 71,98,-2.0759821489316153 556 | 84,69,-1.3552281035654254 557 | 23,1,-3.068988921169429 558 | 15,48,-2.2160465399539913 559 | 87,29,-0.37124203872478323 560 | 63,57,-0.6735143611854157 561 | 59,3,-0.3543501580905018 562 | 57,9,-0.565262832513776 563 | 15,49,-2.2081468235848476 564 | 91,77,-1.9306317820850145 565 | 79,74,-1.2770316398817467 566 | 8,23,-2.383238581267964 567 | 77,100,-2.309611686602484 568 | 25,84,-0.9779716688959315 569 | 55,45,-0.3809195779762311 570 | 17,15,-2.2495875065847333 571 | 86,37,-0.37589885180134697 572 | 23,11,-2.428964593101172 573 | 61,67,-0.2928007964661541 574 | 100,96,-1.4970651554826153 575 | 17,25,-2.4354594071528624 576 | 57,75,0.3085251984517763 577 | 39,52,-0.9943127563121311 578 | 62,29,-0.27853393683917627 579 | 87,22,0.06457626208620026 580 | 97,48,-0.6829868870442757 581 | 61,53,-0.5102478245348054 582 | 28,36,-2.1641418798775667 583 | 51,57,-0.7224137994697368 584 | 79,88,-2.0814629285374298 585 | 71,60,-0.7249037118888615 586 | 90,94,-1.9804169242892842 587 | 81,89,-2.0520706532531685 588 | 22,30,-2.4439811903882873 589 | 55,97,-1.1851939708737174 590 | 22,75,-1.526750644082616 591 | 60,93,-1.061944517779756 592 | 9,65,-1.5431833522874623 593 | 65,79,-0.4445949808668536 594 | 4,1,-1.884632085685426 595 | 68,4,-0.8653764319806004 596 | 27,68,-1.0539526842953977 597 | 28,3,-2.8706516167100604 598 | 2,70,-0.9917407414894048 599 | 85,2,0.19624752616162078 600 | 10,99,1.1547223512811096 601 | 83,70,-1.3158679986819846 602 | --------------------------------------------------------------------------------