From 0690ef5ed1a7dc6ef30cda254719f651efed5447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20M=C3=A4licke?= Date: Fri, 13 Oct 2023 06:01:17 +0200 Subject: [PATCH] fix whitespace and end-of-file warnings --- .coveragerc | 4 +- .github/workflows/main.yml | 26 +- .gitignore | 2 +- Dockerfile | 2 +- Dockerfile.legacy | 6 +- MANIFEST.in | 2 +- README.rst | 4 +- RELEASE.md | 4 +- docs/Makefile | 2 +- docs/changelog.rst | 142 +++---- docs/getting_started.rst | 3 +- docs/index.rst | 7 +- docs/install.rst | 6 +- docs/reference/binning.rst | 3 +- docs/reference/data.rst | 2 +- docs/reference/estimator.rst | 2 +- docs/reference/kriging.rst | 2 +- docs/reference/metric_space.rst | 2 +- docs/reference/models.rst | 2 +- docs/reference/reference.rst | 2 +- docs/technical/direction.rst | 3 +- docs/technical/estimate_kriging.rst | 2 +- docs/technical/fitting.rst | 3 - docs/technical/technical.rst | 4 +- ...a_data_CosmicSense_JFC1_DE-Fen_SNdata.json | 26 +- docs/tutorials/data/tereno_fendt/tereno.json | 2 +- docs/tutorials/tutorial_01_getting_started.py | 14 +- docs/tutorials/tutorial_02_estimators.py | 52 +-- .../tutorials/tutorial_03_variogram_models.py | 36 +- docs/tutorials/tutorial_04_plotting.py | 73 ++-- docs/tutorials/tutorial_05_binning.py | 65 ++-- docs/tutorials/tutorial_06_gstools.py | 24 +- .../tutorial_07_maximum_likelihood_fit.py | 10 +- docs/userguide/introduction.rst | 8 +- docs/userguide/kriging.rst | 203 +++++----- docs/userguide/userguide.rst | 2 +- docs/userguide/variogram.rst | 366 +++++++++--------- requirements.txt | 2 +- requirements.unittest.3.6.txt | 2 +- requirements.unittest.3.7.txt | 2 +- requirements.unittest.3.8.txt | 2 +- skgstat/DirectionalVariogram.py | 6 +- skgstat/MetricSpace.py | 6 +- skgstat/SpaceTimeVariogram.py | 2 +- skgstat/Variogram.py | 2 +- skgstat/__version__.py | 2 +- skgstat/binning.py | 4 +- skgstat/data/__init__.py | 42 +- skgstat/data/samples/README.md | 2 +- skgstat/data/samples/meuse.txt | 2 +- skgstat/interfaces/gstools.py | 2 +- skgstat/interfaces/pykrige.py | 4 +- skgstat/models.py | 16 +- skgstat/plotting/__init__.py | 2 +- skgstat/plotting/stvariogram_plot3d.py | 2 +- skgstat/stmodels.py | 10 +- skgstat/tests/__init__.py | 2 +- skgstat/tests/test_binning.py | 2 +- skgstat/tests/test_cross_utility.py | 6 +- skgstat/tests/test_data_loader.py | 4 +- skgstat/tests/test_directionalvariogram.py | 4 +- skgstat/tests/test_interfaces.py | 4 +- skgstat/tests/test_kriging.py | 20 +- skgstat/tests/test_models.py | 2 +- skgstat/tests/test_plotting_backend.py | 2 +- skgstat/tests/test_stmodels.py | 10 +- skgstat/tests/test_util.py | 2 +- skgstat/tests/test_variogram.py | 48 +-- skgstat/util/__init__.py | 2 +- skgstat/util/cross_variogram.py | 2 +- skgstat/util/likelihood.py | 8 +- skgstat/util/shannon.py | 2 +- ...a_data_CosmicSense_JFC1_DE-Fen_SNdata.json | 26 +- tutorials/tereno_fendt/tereno.json | 2 +- 74 files changed, 684 insertions(+), 694 deletions(-) diff --git a/.coveragerc b/.coveragerc index 24efba7..1904344 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,12 +1,12 @@ [run] -omit = +omit = skgstat/tests/* skgstat/plotting/* docs/* setup.py [report] -exclude_lines = +exclude_lines = pragma: no cover def __repr__ def __str__ diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b902413..32ca7dd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,9 +13,9 @@ jobs: name: Run Unittest runs-on: ubuntu-20.04 strategy: - matrix: + matrix: python: ['3.6', '3.7', '3.8', '3.9', '3.10'] - + steps: - name: Checkout uses: actions/checkout@master @@ -24,7 +24,7 @@ jobs: with: python-version: ${{ matrix.python }} - name: Install SciKit-GStat - run: | + run: | pip3 install -r requirements.txt python3 setup.py install - name: Install PyTest requirements @@ -51,7 +51,7 @@ jobs: with: python-version: '3.8' - name: Install SciKit-GStat - run: | + run: | pip3 install -r requirements.txt python3 setup.py install - name: Install Sphinx requirements @@ -61,13 +61,13 @@ jobs: - name: Install pdflatex run: sudo apt install texlive-latex-extra texlive-latex-recommended texlive-fonts-recommended pandoc - name: make HTML & LaTeX docs - run: | + run: | cd docs - make html + make html make latex continue-on-error: true - name: compile LaTeX - run: | + run: | cd docs/_build/latex pdflatex -interaction=nonstopmode -halt-on-error SciKitGStat.tex cd ../.. @@ -79,7 +79,7 @@ jobs: target_branch: gh-pages build_dir: docs/_build/html env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} release: name: Create Github release @@ -101,7 +101,7 @@ jobs: name: Publish to PyPi runs-on: ubuntu-20.04 needs: test - if: startsWith(github.event.ref, 'refs/tags/v') + if: startsWith(github.event.ref, 'refs/tags/v') steps: - uses: actions/checkout@v3 @@ -119,13 +119,13 @@ jobs: uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 with: user: __token__ - password: ${{ secrets.PYPI_TOKEN }} - - ci_develop: + password: ${{ secrets.PYPI_TOKEN }} + + ci_develop: name: Print Github Context for Development runs-on: ubuntu-20.04 if: true - + steps: - name: Dump GitHub context env: diff --git a/.gitignore b/.gitignore index 80ecee0..bac6da2 100644 --- a/.gitignore +++ b/.gitignore @@ -113,4 +113,4 @@ container Playground.ipynb in_progress docs/auto_examples -docs/gen_modules \ No newline at end of file +docs/gen_modules diff --git a/Dockerfile b/Dockerfile index b4f5e80..ea611c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,4 +29,4 @@ RUN pip install jupyter # open port 8888 EXPOSE 8888 -CMD jupyter notebook --ip "0.0.0.0" \ No newline at end of file +CMD jupyter notebook --ip "0.0.0.0" diff --git a/Dockerfile.legacy b/Dockerfile.legacy index 13f30b1..5d74ce2 100644 --- a/Dockerfile.legacy +++ b/Dockerfile.legacy @@ -2,7 +2,7 @@ # use the minimal jupyter notebook FROM jupyter/minimal-notebook:ad3574d3c5c7 -# build tutorials folder +# build tutorials folder USER root RUN mkdir tutorials @@ -12,7 +12,7 @@ USER $NB_USER # copy the tutorials content COPY ./docs/tutorials ./tutorials -# install the latest version +# install the latest version COPY ./ ./scikit-gstat # use the latest @@ -20,7 +20,7 @@ RUN cd scikit-gstat && \ pip install . && \ cd .. -# the interfaces has two additional +# the interfaces has two additional # optional dependencies: pykrige and gstools RUN pip install pykrige gstools diff --git a/MANIFEST.in b/MANIFEST.in index 8b9a556..8ee1ba5 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,4 +8,4 @@ include .coveragerc include Dockerfile include Dockerfile.legacy graft skgstat/data/rf -graft skgstat/data/samples \ No newline at end of file +graft skgstat/data/samples diff --git a/README.rst b/README.rst index 0982b79..6cd6355 100644 --- a/README.rst +++ b/README.rst @@ -79,8 +79,8 @@ PyPI pip install scikit-gstat -**Note:** It can happen that the installation of numba or numpy is failing using pip. Especially on Windows systems. -Usually, a missing Dll (see eg. `#31 `_) or visual c++ redistributable is the reason. +**Note:** It can happen that the installation of numba or numpy is failing using pip. Especially on Windows systems. +Usually, a missing Dll (see eg. `#31 `_) or visual c++ redistributable is the reason. GIT: ^^^^ diff --git a/RELEASE.md b/RELEASE.md index bbf3fb3..a020ea6 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,6 +1,6 @@ # Scikit-GStat -SciKit-Gstat is a scipy-styled variogram estimation and analysis module for geostatistics. +SciKit-Gstat is a scipy-styled variogram estimation and analysis module for geostatistics. It includes classes for variogram estimation and ordinary kriging. More advanced use-cases like directional variograms and space-time variograms are included as well. @@ -26,4 +26,4 @@ or bibtex: URL = {https://gmd.copernicus.org/articles/15/2505/2022/}, DOI = {10.5194/gmd-15-2505-2022} } -``` \ No newline at end of file +``` diff --git a/docs/Makefile b/docs/Makefile index 1ab91c4..081fcab 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -17,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/changelog.rst b/docs/changelog.rst index 181fc58..0068704 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,7 +21,7 @@ Version 1.0.9 Version 1.0.8 ------------- -- [util] added :func:`cross_variograms ` for calculating cross-variograms for +- [util] added :func:`cross_variograms ` for calculating cross-variograms for all combinations of ``N`` input variables. Variograms are returned in a 2D List (matrix) with all primary variograms on the diagonal. - [util] added support for :class:`DirectionalVariogram ` in case azimuth, @@ -41,8 +41,8 @@ This is technically the same as the 1.0.5 as I screwed up and uploaded to PyPI w Version 1.0.5 ------------- -- [Variogram] The variogram now accepts 2D values in ``(n_samples, 2)`` shape. The second column will be - interpreted as a co-variable co-located to the observations and the Variogram then calculates the +- [Variogram] The variogram now accepts 2D values in ``(n_samples, 2)`` shape. The second column will be + interpreted as a co-variable co-located to the observations and the Variogram then calculates the **cross-variogram** for ``values[:, 0] ~ values[:, 1]`` Note that this only implements the basic calculation of cross-variograms. Utility functions and plotting still need to be updated. A tutorial will also be added in future. @@ -61,7 +61,7 @@ Version 1.0.3 ------------- - [Variogram] :func:`Variogram.pairwise_diffs ` wraps around old ``_diff`` and should be used instead of directly accessing ``_diff`` -- [Variogram] :func:`Variogram.model_residuals ` will replace +- [Variogram] :func:`Variogram.model_residuals ` will replace ``Variogram.residuals`` which has been deprecated Version 1.0.1 @@ -74,9 +74,9 @@ Version 1.0.1 Version 1.0.0 ============= - [plotting] the 3D surface plot is now handling the opacity settings correctly. -- [utils] the utils now include the likelihood submodule, which includes a +- [utils] the utils now include the likelihood submodule, which includes a :func:`get_likelihood ` function factory. - The returned function can be minimized using SciPy to perform maximum likelihood fits. + The returned function can be minimized using SciPy to perform maximum likelihood fits. Version 0.6.14 -------------- @@ -86,7 +86,7 @@ Version 0.6.14 Version 0.6.13 -------------- -- [docs] the sphinx recipe knitting a TeX file from docs is now ignored on fail +- [docs] the sphinx recipe knitting a TeX file from docs is now ignored on fail Reason is that the current build is too lage and any kind of buffer is overflowing - [docs] The jupyter notebook tutorials for the Docker image are now at root level. - [docs] The documentation tutorials are now sphinx-gallery builds of the notebook @@ -97,7 +97,7 @@ Version 0.6.13 Version 0.6.12 -------------- - [data] the dataset loader can now return pandas.DataFrame objects -- [Dockerfile] some cleanups for making future tutorials work. +- [Dockerfile] some cleanups for making future tutorials work. Version 0.6.11 -------------- @@ -108,7 +108,7 @@ Version 0.6.10 - [Variogram] The KMeans based binning function is now raising a value error if a ConvergenceWarning is found. The reason is, that the original settings for binning were not valid if KMeans did not converge and thus, the bins array might not be - in a well defined state. + in a well defined state. Version 0.6.9 ------------- @@ -122,19 +122,19 @@ Version 0.6.8 Version 0.6.7 ------------- - [RasterMetricSpace] a new class is introduced: :class:`RasterEquidistantMetricSpace `. - An instance can be passed as `coordinates`. It samples a given Raster image at concentric rings, to derive a + An instance can be passed as `coordinates`. It samples a given Raster image at concentric rings, to derive a more uniformly distributed distance matrix. Version 0.6.6 ------------- -- [Variogram] The automatic fitting of a theoretical variogram model is now optional. You can pass `None` as +- [Variogram] The automatic fitting of a theoretical variogram model is now optional. You can pass `None` as `fit_method` parameter, which will suppress the fitting. Version 0.6.5 ------------- -- [Variogram] now supports custom bin edges for the experimental variogram. :func:`Variogram.bins ` +- [Variogram] now supports custom bin edges for the experimental variogram. :func:`Variogram.bins ` now accepts a list or array of upper bin edges. -- [Variogram] has a new property called :func:`bin_count ` which returns the number of +- [Variogram] has a new property called :func:`bin_count ` which returns the number of point pairs within each lag class Version 0.6.4 @@ -143,10 +143,10 @@ Version 0.6.4 - [Kriging] `OrdinaryKriging._estimator ` handles the error variance matrix index now correctly. On error during kriging, the index was not incremented, which lead to malformed error variance field output. -Version 0.6.3 +Version 0.6.3 ------------- - [interfaces] If any of the gstools interfaces are used, the Variogram will call :func:`fit ` - without forcing a full preprocessing cycle. This fixes edge cases, where a parameter was mutated, but the fitting + without forcing a full preprocessing cycle. This fixes edge cases, where a parameter was mutated, but the fitting not performed before the instance was exported. This should only have happened in very rare occasions. - [data] added the meuse dataset from the R-package ``'sp'`` @@ -155,12 +155,12 @@ Version 0.6.2 - [Variogram] the fitting method is now implemented as :func:`Variogram.fit_method ` property. It will drop fitting parameters if the fit method is changed to something else than ``'manual'``. - [Variogram] If an invalid :func:`Variogram.fit_method ` is set, an - :class:`AttributeError` will instantly be raised. Beforehand it was only raised on the next call of + :class:`AttributeError` will instantly be raised. Beforehand it was only raised on the next call of :func:`fit ` Version 0.6.1 ------------- -- The Dockerfile was completely rewritten. A user can now specify the used Python version +- The Dockerfile was completely rewritten. A user can now specify the used Python version at build time of the docker image. - The Dockerfile is now part of the python package @@ -172,9 +172,9 @@ Version 0.6.0 it gets stable with Version 1.0 or 1.1 .. note:: - The current implementation of uncertainty propagation is not stable. It will be changed until + The current implementation of uncertainty propagation is not stable. It will be changed until version 0.7. The entry-point `obs_sigma` will stay stable and persist, but currently the uncertainty - propagation will not be updated and invalidated as the Variogram instance changes. + propagation will not be updated and invalidated as the Variogram instance changes. Version 0.5.6 ------------- @@ -190,13 +190,13 @@ Version 0.5.5 Version 0.5.4 ------------- -- [util] added a new `cross_validation` utility module to cross-validate variograms with leave-one-out Kriging +- [util] added a new `cross_validation` utility module to cross-validate variograms with leave-one-out Kriging cross validations. Version 0.5.3 ------------- - [MetricSpace] new class :class:`ProbabilisticMetricSpace ` that - extends the metric space by a stochastic element to draw samples from the input data, instead of using + extends the metric space by a stochastic element to draw samples from the input data, instead of using the full dataset. Version 0.5.2 @@ -208,14 +208,14 @@ Version 0.5.2 Version 0.5.1 ------------- -- [plotting] the spatio-temporal 2D and 3D plots now label the axis correctly. +- [plotting] the spatio-temporal 2D and 3D plots now label the axis correctly. - [plotting] fixed swapped plotting axes for spatio-temporal plots. Version 0.5.0 ------------- - [MetricSpace] A new class :class:`MetricSpace ` was introduced. This class can be passed to any class that accepted coordinates so far. This wrapper can be used to pre-calculate large distance - matrices and pass it to a lot of Variograms. + matrices and pass it to a lot of Variograms. - [MetricSpacePair] A new class :class:`MetricSpacePair ` was introduced. This is a pair of two :class:`MetricSpaces ` and pre-calculates all distances between the two spaces. This is i.e. used in Kriging to pre-calcualte all distance between the input coordinates and @@ -223,12 +223,12 @@ Version 0.5.0 Version 0.4.4 ------------- -- [models] the changes to :func:`matern ` introduced in `0.3.2` are reversed. +- [models] the changes to :func:`matern ` introduced in `0.3.2` are reversed. The Matérn model does not adapt the smoothness scaling to effective range anymore, as the behavior was too inconsistent. - [interface] minor bugfix of circular import in `variogram_estimator` interface - [models] :func:`matern(0, ...) ` now returns the nugget instead of `numpy.NaN` -- [models] :func:`stable(0, ...) ` now returns the nugget instead of `numpy.NaN` or a +- [models] :func:`stable(0, ...) ` now returns the nugget instead of `numpy.NaN` or a `ZeroDivisionError`. Version 0.4.3 @@ -241,7 +241,7 @@ Version 0.4.2 - [Variogram] :func:`bins ` now cases manual set bin edges automatically to a :func:`numpy.array`. - [Variogram] :func:`get_empirical ` returns the empirical variogram. - That is a tuple of the current :func:`bins ` and + That is a tuple of the current :func:`bins ` and :func:`experimental ` arrays, with the option to move the bin to the lag classes centers. @@ -264,15 +264,15 @@ Version 0.3.11 Version 0.3.10 -------------- -- [binning] added a median aggregation option to :func:`ward `. This can be - enabled by setting `binning_agg_func` to `'median'`. The cluster centroids will be derived from +- [binning] added a median aggregation option to :func:`ward `. This can be + enabled by setting `binning_agg_func` to `'median'`. The cluster centroids will be derived from the members median value, instead of mean value. -- [Variogram] added :func:`fit_method-'ml' ` - a maximum likelihood fitting +- [Variogram] added :func:`fit_method-'ml' ` - a maximum likelihood fitting procedure to fit the theoretical variogram to the experimental -- [Variogram] added :func:`fit_method-'manual' `. This is a manual fitting - method that takes the variogram parameters either at instantiation prefixed by `fit_`, or as - keyword arguments by :func:`fit `. -- [Variogram] the manual fitting method will preserve the previous parameters, if the Variogram was +- [Variogram] added :func:`fit_method-'manual' `. This is a manual fitting + method that takes the variogram parameters either at instantiation prefixed by `fit_`, or as + keyword arguments by :func:`fit `. +- [Variogram] the manual fitting method will preserve the previous parameters, if the Variogram was fitted before and the fitting parameters are not manually overwritten. @@ -288,25 +288,25 @@ Version 0.3.8 - [plotting] minor bugfixes in plotting routines (wrong arguments, pltting issues) - [docs] added a tutorial about plotting - [binning] added :func:`auto_derived_lags ` for a variety - of different methods that find a good estimate for either the number of lag classes or the - lag class width. These can be used by passing the method name as :func:`bin_func ` - parameter: Freedman-Diaconis (`'fd'`), Sturge's rule (`'sturges'`), Scott's rule (`'scott'`) and - Doane's extension to Sturge's rule (`'doane'`). + of different methods that find a good estimate for either the number of lag classes or the + lag class width. These can be used by passing the method name as :func:`bin_func ` + parameter: Freedman-Diaconis (`'fd'`), Sturge's rule (`'sturges'`), Scott's rule (`'scott'`) and + Doane's extension to Sturge's rule (`'doane'`). Uses `histogram_bin_edges ` internally. Version 0.3.7 ------------- - [Variogram] now accepts arbitrary kwargs. These can be used to further specify functional behavior - of the class. As of Version `0.3.7` this is used to pass arguments down to the - :func:`entropy ` and :func:`percentile ` + of the class. As of Version `0.3.7` this is used to pass arguments down to the + :func:`entropy ` and :func:`percentile ` estimators. -- [Variogram] the :func:`describe ` now adds the - :func:`init ` arguments by default to the output. The method can output +- [Variogram] the :func:`describe ` now adds the + :func:`init ` arguments by default to the output. The method can output the init params as a nested dict inside the output or flatten the output dict. Version 0.3.6 ------------- -.. warning:: +.. warning:: There is some potential breaking behaviour - [Variogram] some internal code cleanup. Removed some unnecessary loops @@ -314,30 +314,30 @@ Version 0.3.6 a recalculation of the lag groupings. So far they were kept untouches, which might result in old experimental variogram values for the changed instance. **This is a potential breaking change**. -- [Variogram] The :func:`lag_classes ` generator now yields empty - arrays for unoccupied lag classes. This will result in :class:`NaN ` values for the +- [Variogram] The :func:`lag_classes ` generator now yields empty + arrays for unoccupied lag classes. This will result in :class:`NaN ` values for the semi-variance. This is actually a bug-fix. **This is a potential breaking change** Version 0.3.5 ------------- -- [plotting] The :func:`location_trend ` can now add - trend model lines to the scatter plot for the `'plotly'` backend and calculate the +- [plotting] The :func:`location_trend ` can now add + trend model lines to the scatter plot for the `'plotly'` backend and calculate the R² for the trend model. - [Variogram] the *internal* attribute holding the name of the current distance function was renamed from `_dict_func` to `_dist_func_name` Version 0.3.4 ------------- -- [plotting] The :func:`scattergram ` +- [plotting] The :func:`scattergram ` functions color the plotted points with respect to the lag bin they - are originating from. For `matplotlib`, this coloring is suppressed, but can activated by + are originating from. For `matplotlib`, this coloring is suppressed, but can activated by passing the argument ``scattergram(single_color-False)``. Version 0.3.3 ------------- -- [plotting] a new submodule is introduced: :py:mod:`skgstat.plotting`. This contains all plotting functions. +- [plotting] a new submodule is introduced: :py:mod:`skgstat.plotting`. This contains all plotting functions. The plotting behavior is not changed, but using :func:`skgstat.plotting.backend`, the used plotting library can be switched from `matplotlib` to `plotly` - [stmodels] some code cleanup @@ -374,38 +374,38 @@ Version 0.2.8 - [Variogram] `harmonize` parameter is removed - [Variogram] Monotonization (old harmonize par) is available as a new theoretical model function. Can be used by setting `model-'harmonize'` -- [interfaces] gstools interface implemented. +- [interfaces] gstools interface implemented. :func:`gstools_cov_model ` - takes a :class:`skgstat.Variogram` instance and returns a **fitted** - `gstools.CovModel`. + takes a :class:`skgstat.Variogram` instance and returns a **fitted** + `gstools.CovModel`. Version 0.2.7 ------------- - [Kriging] Little performance gains due to code cleanup. -- [Variogram] The `normalize-True` default in `__init__` will change to +- [Variogram] The `normalize-True` default in `__init__` will change to `normalize-False` in a future version. A DeprecationWarning was included. -- [tests] The Variogram class fitting unit tests are now explicitly setting +- [tests] The Variogram class fitting unit tests are now explicitly setting the normalize parameter to handle the future deprecation. - [tests] More unittests were added to increase coverage -- [interfaces] The new submodule `skgstat.interfaces` is introduced. This - submodule collects interfacing classes to use skgstat classes with other +- [interfaces] The new submodule `skgstat.interfaces` is introduced. This + submodule collects interfacing classes to use skgstat classes with other Python modules. -- [interfaces] The first interfacing class is the - :class:`VariogramEstimator `. This - is a scikit-learn compatible `Estimator` class that can wrap a `Variogram`. +- [interfaces] The first interfacing class is the + :class:`VariogramEstimator `. This + is a scikit-learn compatible `Estimator` class that can wrap a `Variogram`. The intended usage is to find variogram hyper-parameters using `GridSearchCV`. This is also the only usecase covered in the unit tests. -- [interfaces] Implemented - :func:`pykrige_as_kwargs `. - Pass a :class:`Variogram ` object and a dict of parameters - is returned that can be passed to pykrige Kriging classes using the double +- [interfaces] Implemented + :func:`pykrige_as_kwargs `. + Pass a :class:`Variogram ` object and a dict of parameters + is returned that can be passed to pykrige Kriging classes using the double star operator. -- Added Dockerfile. You can now build a docker container with scikit-gstat +- Added Dockerfile. You can now build a docker container with scikit-gstat installed in a miniconda environment. On run, a jupyter server is exposed on Port 8888. In a future release, this server will serve tutorial notebooks. - [stmodels] small bugfix in product model -- [stmodels] removed variogram wrapper and added stvariogram wrapper to +- [stmodels] removed variogram wrapper and added stvariogram wrapper to correctly detect space and time lags Version 0.2.6 @@ -420,16 +420,16 @@ Version 0.2.6 the kriging matrix. - [OrdinaryKriging]: calculates the kriging variance along with the estimation itself. - The Kriging variance can be accessed after a call to - :func:`OrdinaryKriging.transform ` and can be - accessed through the `OrdinaryKriging.sigma` attribute. + The Kriging variance can be accessed after a call to + :func:`OrdinaryKriging.transform ` and can be + accessed through the `OrdinaryKriging.sigma` attribute. - [Variogram] deprecated :func:`Variogram.compiled_model `. Use :func:`Variogram.fitted_model ` instead. - [Variogram] added a new and much faster version of the parameterized model: :func:`Variogram.fitted_model ` -- [Variogram] minor change in the cubic model. This made the adaption of the - associated unit test necessary. +- [Variogram] minor change in the cubic model. This made the adaption of the + associated unit test necessary. Version 0.2.5 ------------- @@ -472,4 +472,4 @@ Version 0.2.1 Version 0.2.0 ------------- -- completely rewritten Variogram class compared to v0.1.8 \ No newline at end of file +- completely rewritten Variogram class compared to v0.1.8 diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 4d6f417..44ea949 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -58,7 +58,7 @@ step classes to `'uniform'` distribution in the lag classes. Mutating -------- -One of the main strenghs of :class:`Variogram ` is its +One of the main strenghs of :class:`Variogram ` is its ability to change arguments in place. Any dependent result or parameter will be invalidated and re-caluculated. You can i.e. increase the number of lag classes: @@ -76,4 +76,3 @@ You can i.e. increase the number of lag classes: Note, how the experimental variogram was updated and the model was fitted to the new data automatically. - diff --git a/docs/index.rst b/docs/index.rst index 47290c2..87bc612 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,7 @@ Welcome to SciKit GStat `Download the docs as PDF `_ -SciKit-Gstat is a scipy-styled analysis module for variogram analysis. +SciKit-Gstat is a scipy-styled analysis module for variogram analysis. The base class is called :class:`Variogram `, which is probably the only import needed. However, several other classes exist: @@ -17,8 +17,8 @@ only import needed. However, several other classes exist: * :class:`OrdinaryKriging ` for interpolation * :class:`MetricSpace ` for pre-computed spatial samples -The variogram classes have a similar interface and can compute experimental variograms -and fit theoretical variogram model functions. +The variogram classes have a similar interface and can compute experimental variograms +and fit theoretical variogram model functions. The module makes use of a rich selection of semi-variance estimators, variogram model functions and sptial binning functions, while being extensible at the same time. @@ -47,4 +47,3 @@ The code itself is published and has a DOI. It can be cited as: technical/technical reference/reference changelog - diff --git a/docs/install.rst b/docs/install.rst index e1870c4..0f096e5 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -43,12 +43,12 @@ Note ---- On Windows, you might run into problems installing all requirements -in a clean Python environment, especially if C++ redistributables are missing. +in a clean Python environment, especially if C++ redistributables are missing. This can happen i.e. on *bare* VMs and the compilation of libraries required by scipy, numpy or numba package are the ones failing. In these cases, install the libraries first, and then SciKit-GStat or move to -the conda-forge package +the conda-forge package .. code-block:: bash - conda install numpy, scipy, numba \ No newline at end of file + conda install numpy, scipy, numba diff --git a/docs/reference/binning.rst b/docs/reference/binning.rst index f46c255..3077fc9 100644 --- a/docs/reference/binning.rst +++ b/docs/reference/binning.rst @@ -3,7 +3,7 @@ Binning functions ================= SciKit-GStat implements a large amount of binning functions, -which can be used to spatially aggregate the distance matrix +which can be used to spatially aggregate the distance matrix into lag classes, or bins. There are a number of functions available, which usually accept more than one method identifier: @@ -20,4 +20,3 @@ more than one method identifier: .. autofunction:: skgstat.binning.ward .. autofunction:: skgstat.binning.stable_entropy_lags - diff --git a/docs/reference/data.rst b/docs/reference/data.rst index f39707a..278806d 100644 --- a/docs/reference/data.rst +++ b/docs/reference/data.rst @@ -12,4 +12,4 @@ Utility Functions ----------------- ..automodule:: skgstat.data._loader - :members: field, get_sample \ No newline at end of file + :members: field, get_sample diff --git a/docs/reference/estimator.rst b/docs/reference/estimator.rst index 613da11..ab65295 100644 --- a/docs/reference/estimator.rst +++ b/docs/reference/estimator.rst @@ -55,4 +55,4 @@ Percentile percentile of the given pairwise differences and does not bear any information about their variance. -.. autofunction:: skgstat.estimators.percentile \ No newline at end of file +.. autofunction:: skgstat.estimators.percentile diff --git a/docs/reference/kriging.rst b/docs/reference/kriging.rst index 88e80ce..6882a5c 100644 --- a/docs/reference/kriging.rst +++ b/docs/reference/kriging.rst @@ -5,4 +5,4 @@ Kriging Class .. autoclass:: skgstat.OrdinaryKriging :members: - .. automethod:: __init__ \ No newline at end of file + .. automethod:: __init__ diff --git a/docs/reference/metric_space.rst b/docs/reference/metric_space.rst index 3734ad1..7dc9440 100644 --- a/docs/reference/metric_space.rst +++ b/docs/reference/metric_space.rst @@ -18,4 +18,4 @@ MetricSpacePair :members: .. automethod:: __init__ - .. automethod:: find_closest \ No newline at end of file + .. automethod:: find_closest diff --git a/docs/reference/models.rst b/docs/reference/models.rst index 4349e7d..5ae25ee 100644 --- a/docs/reference/models.rst +++ b/docs/reference/models.rst @@ -40,4 +40,4 @@ Stable model Matérn model ~~~~~~~~~~~~ -.. autofunction:: skgstat.models.matern \ No newline at end of file +.. autofunction:: skgstat.models.matern diff --git a/docs/reference/reference.rst b/docs/reference/reference.rst index ec4c8d8..9434264 100644 --- a/docs/reference/reference.rst +++ b/docs/reference/reference.rst @@ -15,4 +15,4 @@ Code Reference kriging data metric_space - util \ No newline at end of file + util diff --git a/docs/technical/direction.rst b/docs/technical/direction.rst index 5a1cf46..5b13147 100644 --- a/docs/technical/direction.rst +++ b/docs/technical/direction.rst @@ -89,7 +89,7 @@ random coordinates, the visualization is shown below. @savefig dv1.png width=6in DV.pair_field(plt.gca()) - + The model can easily be changed, using the :func:`set_directional_model ` function: @@ -130,4 +130,3 @@ All other methods and attributes can be used in the same way. - :func:`DirectionalVariogram.bins ` - :func:`DirectionalVariogram._calc_groups ` - diff --git a/docs/technical/estimate_kriging.rst b/docs/technical/estimate_kriging.rst index 92cc255..116b5b8 100644 --- a/docs/technical/estimate_kriging.rst +++ b/docs/technical/estimate_kriging.rst @@ -108,4 +108,4 @@ quite obvious. plt.plot(x, y_c, '-b') @savefig krig_coarse.png width=7in - plt.plot(x, y_e2, '-g') \ No newline at end of file + plt.plot(x, y_e2, '-g') diff --git a/docs/technical/fitting.rst b/docs/technical/fitting.rst index c5af8ba..ee88a9f 100644 --- a/docs/technical/fitting.rst +++ b/docs/technical/fitting.rst @@ -226,6 +226,3 @@ variograms used so far. That's it. - - - diff --git a/docs/technical/technical.rst b/docs/technical/technical.rst index 31c345f..cccb595 100644 --- a/docs/technical/technical.rst +++ b/docs/technical/technical.rst @@ -3,8 +3,8 @@ Technical Notes =============== This chapter collects a number of technical advises for using scikit-gstat. -These examples either give details on the implementation or -guide a correct package usage. This are technical notes, no tutorials. +These examples either give details on the implementation or +guide a correct package usage. This are technical notes, no tutorials. The application of the shown examples might not make sense in every situation .. toctree:: diff --git a/docs/tutorials/data/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json b/docs/tutorials/data/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json index 5d6346a..56d8ebc 100644 --- a/docs/tutorials/data/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json +++ b/docs/tutorials/data/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json @@ -5,14 +5,14 @@ "Info": "These files are part of the dataset published with the data-paper mentioned below.", "cite-as": "Fersch, B., Francke, T., Heistermann, M., Schrön, M., Döpper, V., Jakobi, J. et. al (2020): A dense network of cosmic-ray neutron sensors for soilmoisture observation in a highly instrumented pre-alpine headwater catchment in Germany. Earth System Science Data. https://doi.org/10.5194/essd-2020-48" }, - + "Provider": { "Name": "Benjamin Fersch", "Institution": "KIT Campus Alpin", "Email": "fersch@kit.edu", - "Comment": "" + "Comment": "" }, - + "SpaceTimeCoverage": { "StartDate": "2019-05-01", "EndDate": "2019-07-31", @@ -23,14 +23,14 @@ "Elevation": "595 m ASL", "Weblink": "https://geoportal.bayern.de/bayernatlas/?zoom=15&lang=de&topic=ba&bgLayer=atkis&E=654197&N=5299736&catalogNodes=122,11&layers=luftbild&crosshair=marker" }, - + "Source": { "Name": "Benjamin Fersch", "Institution": "KIT Campus Alpin", "LinkToOriginalSource": "https://www.imk-ifu.kit.edu/tereno.php" }, - - + + "Variables": { "time": "time of measurement", "lat": "profile latitude coordinate", @@ -45,7 +45,7 @@ "T_a": "soil temperature (sensor group a)", "T_b": "soil temperature (sensor group b)" }, - + "Units": { "time": "minutes since 2019-05-01 00:00:00", "lat": "degree north", @@ -60,20 +60,20 @@ "T_a": "degree Celsius", "T_b": "degree Celsius" }, - + "SpatialReferenceSystem": { "Name": "WGS 84", - "EPSG": "4326" + "EPSG": "4326" }, - - + + "TemporalReferenceSystem": { "TimeZone": "UTC", "IntervalLength": "15 minutes", "IntervalAggregation": "instantaneous", "TimestampAtEndOfInterval": "FALSE" }, - + "Remarks": "Each profile is equipped with 2 redundant sensors (a, and b)\n Metadata also contained in NetCDF header." } - \ No newline at end of file + diff --git a/docs/tutorials/data/tereno_fendt/tereno.json b/docs/tutorials/data/tereno_fendt/tereno.json index cc816e7..c366180 100644 --- a/docs/tutorials/data/tereno_fendt/tereno.json +++ b/docs/tutorials/data/tereno_fendt/tereno.json @@ -17754,4 +17754,4 @@ ] ], "description": "Data derived from Fersch et al. (2020) https://doi.org/10.5194/essd-2020-48. Published under CC BY 4.0.\n It is From the WSN product, the T_a in 20cm depth is extracted" -} \ No newline at end of file +} diff --git a/docs/tutorials/tutorial_01_getting_started.py b/docs/tutorials/tutorial_01_getting_started.py index 27cb3a6..3b4357a 100644 --- a/docs/tutorials/tutorial_01_getting_started.py +++ b/docs/tutorials/tutorial_01_getting_started.py @@ -30,7 +30,7 @@ # 1.1 Load data # ------------- # SciKit-GStat includes a data submodule, that contains some sample datasets. It also offers some basic random sampling on data sources. -# Here we use the well-known Meuse dataset from the R package ``sp`` (https://cran.r-project.org/web/packages/st/index.html). +# Here we use the well-known Meuse dataset from the R package ``sp`` (https://cran.r-project.org/web/packages/st/index.html). # If not specified different, the loading function will only export the lead measurements from the data source. # # **Note:** The data is distributed along with the package sp under a GPL-3 license. @@ -61,12 +61,12 @@ # As a quick reminder, the variogram relates pair-wise separating distances of `coordinates` and relates them to the *semi-variance* of the corresponding `values` pairs. The default estimator used is the Matheron estimator: # # .. math:: -# +# # \gamma (h) = \frac{1}{2N(h)} * \sum_{i=1}^{N(h)}(Z(x_i) - Z(x_{i + h}))^2 -# +# # For more details, please refer to the `User Guide `_. # -# The :class:`Variogram ` class takes at least two arguments. +# The :class:`Variogram ` class takes at least two arguments. # The :func:`coordinates ` and the :func:`values ` observed at these locations. # If you use older versions, `_. # -# Consequently, the :class:`OrdinaryKriging ` class needs a :class:`Variogram ` +# Consequently, the :class:`OrdinaryKriging ` class needs a :class:`Variogram ` # object as a mandatory attribute. Two very important optional attributes are ``min_points`` and ``max_points```. # They will limit the size of the Kriging equation system. As we have 200 observations, # we can require at least 5 neighbors within the range. More than 15 will only unnecessarily slow down the computation. # The ``mode='exact'`` attribute will advise the class to build and solve the system above for each location. # # **Note:** The recommended way for kriging applications is to use the interface to :any:`gstools`. -# There is an easy-to-use interface via :func:`Variogram.to_gstools ` +# There is an easy-to-use interface via :func:`Variogram.to_gstools ` # and :func:`Variogram.to_gs_krige `. # The getting started tutorial will use the builtin kriging class, anyway. ok = skg.OrdinaryKriging(V, min_points=5, max_points=15, mode='exact') diff --git a/docs/tutorials/tutorial_02_estimators.py b/docs/tutorials/tutorial_02_estimators.py index ca7fffd..cc1c96b 100644 --- a/docs/tutorials/tutorial_02_estimators.py +++ b/docs/tutorials/tutorial_02_estimators.py @@ -33,7 +33,7 @@ # %% -# +# def plot_scatter(data, ax): art = ax.scatter(data.x, data.y, 50, c=data.v, cmap='plasma') plt.colorbar(art, ax=ax) @@ -57,16 +57,16 @@ def plot_scatter(data, ax): vario = V2 # %% -# The default estimator configured in :class:`Variogram ` +# The default estimator configured in :class:`Variogram ` # is the :func:`Mathéron estimator ` # (Mathéron, 1963). It is defined like: -# +# # .. math:: -# +# # \gamma (h) = \frac{1}{2N(h)} * \sum_{i=1}^{N(h)}(Z(x_i) - Z(x_{i+h}))^2 -# +# # where: -# +# # * :math:`h` is the distance lag # * :math:`h` is the number of observation pairs in :math:`h`-lag class # * :math:`Z(x_i)` is the observation at the :math:`i`-th location :math:`x` @@ -89,35 +89,35 @@ def plot_scatter(data, ax): # Setting :func:`estimator='cressie' ` # will set the Cressie-Hawkins estimator. # It is implemented as follows (Cressie and Hawkins, 1980): -# +# # .. math:: -# +# # 2\gamma (h) = \frac{\left(\frac{1}{N(h)} \sum_{i=1}^{N(h)} |Z(x_i) - Z(x_{i+h})|^{0.5}\right)^4}{0.457 + \frac{0.494}{N(h)} + \frac{0.045}{N^2(h)}} -# +# # By setting :func:`estimator='dowd' `, # the Dowd estimator (Dowd, 1984) will be used: -# +# # .. matho:: -# -# 2\gamma (h) = 2.198 * {median(Z(x_i) - Z(x_{i+h}))}^2 -# +# +# 2\gamma (h) = 2.198 * {median(Z(x_i) - Z(x_{i+h}))}^2 +# # Finally, :func:`estimator='genton' ` # will set the Genton estimator (Genton, 1998): -# +# # .. math:: -# +# # \gamma (h) = 2.2191\{|V_i(h) - V_j(h)|; i < j\}_{(k)} -# -# with: -# +# +# with: +# # .. math:: # k = \binom{[N_h / 2] + 1}{2} -# +# # and: -# +# # .. math:: # q = \binom{N_h}{2} -# +# fig, _a = plt.subplots(1, 3, figsize=(12, 3), sharey=True) axes = _a.flatten() for ax, estimator_name in zip(axes, ('matheron', 'cressie', 'dowd')): @@ -126,7 +126,7 @@ def plot_scatter(data, ax): ax.set_title(estimator_name.capitalize()) # %% -# The important part is here that the effective range as well as the sill is +# The important part is here that the effective range as well as the sill is # changing for the estimator. This will likely change the Kriging result. # For Kriging, the difference on the first few lag classes is important, # as no points will be used for estimation, that lies outside the range. @@ -187,14 +187,14 @@ def plot_scatter(data, ax): # the upper left corner not as quite well as the other estimators. One can also # see, that a substantial amount of the deviations are caused by the noisy # character of the original image. Note that we loaded the field without -# applying any kind of filter to it. +# applying any kind of filter to it. # # 2.4 References # -------------- # Cressie, N., and D. Hawkins (1980): Robust estimation of the variogram. Math. Geol., 12, 115-125. -# +# # Dowd, P. A., (1984): The variogram and kriging: Robust and resistant estimators, in Geostatistics for Natural Resources Characterization. Edited by G. Verly et al., pp. 91 - 106, D. Reidel, Dordrecht. -# +# # Genton, M. G., (1998): Highly robust variogram estimation, Math. Geol., 30, 213 - 221. -# +# # Matheron, G. (1963). Principles of geostatistics. Economic Geology, 58(8), 1246–1266. https://doi.org/10.2113/gsecongeo.58.8.1246 diff --git a/docs/tutorials/tutorial_03_variogram_models.py b/docs/tutorials/tutorial_03_variogram_models.py index f726049..c32cc29 100644 --- a/docs/tutorials/tutorial_03_variogram_models.py +++ b/docs/tutorials/tutorial_03_variogram_models.py @@ -2,7 +2,7 @@ 3 - Variogram Models ==================== -This tutorial will guide you through the theoretical variogram models available for the :class:`Variogram ` class. +This tutorial will guide you through the theoretical variogram models available for the :class:`Variogram ` class. **In this tutorial you will learn:** @@ -24,7 +24,7 @@ # For this example we will use the pancake dataset. You can use the # :mod:``skgstat.data`` submodule to directly sample the dataset. This is the # red-channel of an image of an actual pancake. The interesting thing about this pancake is, -# that it shows some clear spatial structures in its browning, but of different +# that it shows some clear spatial structures in its browning, but of different # shapes at different scales. This should be reflectable with different samples. s = [30, 80, 300] data1 = skg.data.pancake(N=s[0], seed=42, as_dataframe=True).get('sample') @@ -52,7 +52,7 @@ def plot_scatter(data, ax): V1 = skg.Variogram(data1[['x', 'y']].values, data1.v.values, maxlag='median', normalize=False) V1.plot(show=False); -# %% +# %% # Plot the others as well V2 = skg.Variogram(data2[['x', 'y']].values, data2.v.values, maxlag='median', normalize=False) V3 = skg.Variogram(data3[['x', 'y']].values, data3.v.values, maxlag='median', normalize=False) @@ -100,12 +100,12 @@ def plot_scatter(data, ax): if i == 2: v.bin_func = 'scott' axes[i][j].set_xlabel('Lag (-)') - + # plot axes[i][j].plot(v.bins, v.experimental, '.b') axes[i][j].plot(x, v.fitted_model(x), '-g') axes[i][j].grid(which='major', axis='x') - + # label first col if j == 0: axes[i][j].set_ylabel(col_lab[i]) @@ -115,7 +115,7 @@ def plot_scatter(data, ax): plt.tight_layout() # %% -# That actually demonstrates how the selection of the experimental variogram can +# That actually demonstrates how the selection of the experimental variogram can # have huge influence on the base data for fitting. Now consider the center column. # In each of the plots, the selection of model is not deterministic. # You can argue for at least two different models here, that might actually be supported by the empirical data. @@ -140,13 +140,13 @@ def plot_scatter(data, ax): # %% # This is quite important. We find all 6 models to describe the experimental # variogram more or less equally well in terms of RMSE. Think of the -# implications: We basically can use any model we like. +# implications: We basically can use any model we like. # This is a problem as i.e. the gaussian and the spherical model describe # fundamentally different spatial properties. Thus, our model selection # should be driven by interpretation of the variogram, and not the difference # in RMSE of only 0.4%, which might very likely not be significant at all. -# -# +# +# # But what does this difference look like, when it comes to interpolation? def interpolate(V, ax): @@ -176,12 +176,12 @@ def interpolate(V, ax): # %% # This should illustrate, how important the selection of model is, even if no observation uncertainties are propagated into the analysis. -# +# # 1. Gaussian model is far off, producing estimations far outside the observed value ranges # 2. All other models seem produce quite comparable mean values # 3. BUT: the standard deviation is quite different # 4. The median of the field can vary by more than 3 units, even if we took the Gaussian model out -# +# # You have to remind that we had quite some observations. The selection of model becomes even more arbitrary with smaller samples and more importantly: We have to consider more than one equally probable parameterization of each model when the experimental is more spread. # Finally, we can calculate the difference between the kriging fields to inspect the spread of estimations spatially: @@ -195,7 +195,7 @@ def interpolate(V, ax): # %% # The colorbar is spanning the entire value range. Thus, given the minor differences in the fitting of the models, we would have to reject just any estimation based on an automatic fit, which is considering some uncertainties in the selection of parameters, because the RMSE values were too close. -# +# # To use the result from above, we need to justfy the selection of model first and manually fit the model based on expert knowledge. # %% @@ -205,11 +205,11 @@ def interpolate(V, ax): V1.plot(show=False); # %% -# This is a nugget-effect variogram. Thus we have to reject any geostatistical -# analysis based on this sample. It just does not expose any spatial pattern that +# This is a nugget-effect variogram. Thus we have to reject any geostatistical +# analysis based on this sample. It just does not expose any spatial pattern that # can be exploited. -# -# What about the denser sample. Increasing the sample size should reject some +# +# What about the denser sample. Increasing the sample size should reject some # of the models. Remind, that we are sampling at more short distances and thus, # the variogram will be governed by the short ranged patterns of the field, while # the other samples are more dependent on the medium and large range patterns, as @@ -226,9 +226,9 @@ def interpolate(V, ax): axes[i].set_ylim(0, 2000) # %% -# We can now clearly reject the cubic, gaussian and exponential model. +# We can now clearly reject the cubic, gaussian and exponential model. # I personally would also reject the spherical model we used in the fist place, -# as it is systematically underestimating the semi-variance on short distances. +# as it is systematically underestimating the semi-variance on short distances. d_fields = [] fig, _a = plt.subplots(2,3, figsize=(18, 12), sharex=True, sharey=True) axes = _a.flatten() diff --git a/docs/tutorials/tutorial_04_plotting.py b/docs/tutorials/tutorial_04_plotting.py index 4df5bd7..ed65184 100644 --- a/docs/tutorials/tutorial_04_plotting.py +++ b/docs/tutorials/tutorial_04_plotting.py @@ -4,10 +4,10 @@ At the core of SciKit-GStat is a set of classes, that can be used interactively to perform variogram analysis. One important aspect of this analysis is a rich collection of plotting functions. These are directly available as class methods -of the :class:`Variogram `, -:class:`DirectionalVariogram ` and +of the :class:`Variogram `, +:class:`DirectionalVariogram ` and :class:`SpaceTimeVariogram ` method. -With version ``0.3.3``, SciKit-GStat implements two different plotting backend: +With version ``0.3.3``, SciKit-GStat implements two different plotting backend: `matplotlib `_ and `plotly `_. Generally speaking, matplotlib is great for creating publication ready figures in a variety of formats, including vector-graphic PDF files. Plotly, on the other @@ -22,8 +22,8 @@ meaning you need to take care of the installation yourself, to keep SciKit-GStat's dependency list shorter. -The data used to create the :class:`Variogram ` and -:class:`DirectionalVariogram ` is from +The data used to create the :class:`Variogram ` and +:class:`DirectionalVariogram ` is from Mälicke (2021). Here, pancake dataset is used. The spatio-temporal data is derived from Fersch et al. (2020). From that data publication, the wireless sensor network data is used. The originally published @@ -89,7 +89,7 @@ # %% # Estimate the spatio-temporal variogram with a product-sum model. # Only every 6th hour is taken into account to decrease the memory footprint. -# If you use the full dataset, you need ^120 GiB RAM. +# If you use the full dataset, you need ^120 GiB RAM. # The marginal variograms are kept as they are. STV = skg.SpaceTimeVariogram(coords, vals[:,::6], x_lags=20, t_lags=20, model='product-sum') print(STV) @@ -98,15 +98,15 @@ # 4.2 Backend # ----------- # -# You can switch to `plotly` as a plotting backend by calling the +# You can switch to `plotly` as a plotting backend by calling the # :mod:`plotting.backend` function and passing the name of the backend. # Note that plotly is only a soft dependency and will not automatically be # installed along with SciKit-GStat. You can install it like: -# +# # .. code-block:: bash -# +# # pip install plotly -# +# # Note that in a Jupyter environment you might want to use the plotly.offline # environment to embed the needed Javascript into the notebook. In these cases # you have to catch the Figure object and use the iplot function from the @@ -114,7 +114,7 @@ # # 4.3 Variogram # ------------- -# +# # 4.3.1 :func:`Variogram.plot ` # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # The :func:`Variogram.plot ` is the main plotting @@ -123,7 +123,7 @@ # or further analysis, make sure, that a suitable model was found and fitted # to the experimental data. Further, you have to make sure that the statistical # foundation of this estimation is sound, the lag classes are well designed and -# backed by a suiatable amount of data. +# backed by a suiatable amount of data. # Otherwise, any other geostatistical analysis or method will have to fail, # no matter how nice the results might look like. @@ -137,8 +137,8 @@ fig # %% -# A useful argument for ``plot`` is the ``ax``, this takes a -# ``matplotlib.AxesSubplot`` for the ``'matplotlib'`` backend and a +# A useful argument for ``plot`` is the ``ax``, this takes a +# ``matplotlib.AxesSubplot`` for the ``'matplotlib'`` backend and a # ``plotly.Figure`` for the ``'plotly'`` backend. # You need to supply the correct amount of subplots (two). For convenience, # the histogram in the upper subplot can be disabled. @@ -147,7 +147,7 @@ width=800, height=200, template='seaborn', - showlegend=False, + showlegend=False, margin=dict(l=0, r=0, b=0, t=0) ) @@ -203,7 +203,7 @@ # ``'plotly'`` backend, as you can click on the legend entries to hide a # specific class, or double-click to show only the selected lag class. # This makes it much easier to inspect the classes. -# +# # Plotly # """""" backend('plotly') @@ -213,7 +213,7 @@ # %% # It is, however possible to re-create the plot that was used up to SciKit-GStat # version ``0.3.0`` with only one color. This is still the default for the -# ``'matplotlib'`` backend. +# ``'matplotlib'`` backend. fig = V.scattergram(single_color=True, show=False) fig @@ -232,12 +232,12 @@ # dimension separatedly. With the ``'plotly'`` backend, each dimension will appear # as a coloured group in a single plot. By double-clicking the legend, you can # inspect each group separately. -# +# # The ``'plotly'`` backend will automatically switch the used plot type from a # ordinary scatter-plot to a WebGL backed scatter-plot, if there are more than # 5000 observations. This will add some startup-overhead for the plot to appear, # but the interactivity actions (like pan, zoom) are speed up by magnitudes. -# +# # Plotly # ^^^^^^ backend('plotly') @@ -256,11 +256,11 @@ # Matplotlib # """""""""" -# +# # There is a difference between the ``'matplotlib'`` and ``'plotly'`` backend in # this plotting function. As Plotly utilizes the legend by default to show and # hide traces on the plot, the user can conveniently switch between the -# coordinate dimensions. +# coordinate dimensions. # In Matplotlib, the figures are not interactive by default and therefore # SciKit-GStat will create one subplot for each coordinate dimension. backend('matplotlib') @@ -269,7 +269,7 @@ # %% # 4.3.4 :func:`distance_difference plot ` # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # The final utility plot presented here is a scatter-plot that relates all # pairwise-differences in value to the spatial distance of the respective point # pairs. This can already be considered to be a variogram. For convenience, the @@ -278,10 +278,10 @@ # adjust. To estimate valid, expressive variograms, this is maybe the most important # preparation step. If your lag classes do not represent your data well, you will # never find a useful variogram. -# +# # Plotly # """""" -# +# backend('plotly') fig = V.distance_difference_plot(show=False) fig @@ -305,10 +305,10 @@ # %% # 4.4 Directional Variogram # ------------------------- -# +# # 4.4.1 :func:`pair_field ` # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # The :class:`DirectionalVariogram ` class is # inheriting from :class:`Variogram `. Therefore all plotting # method shown above are available for directional variograms, as well. @@ -328,7 +328,7 @@ # %% # Obviously, one can see the ``azimuth`` (40°) and narrow ``tolerance`` (15°) # settings in the cone-like shapes of the connection lines, but the whole plot -# is not really instructive or helpful like this. +# is not really instructive or helpful like this. # Using the ``points`` keyword, you can show the lines only for a given set of # coordinate locations. You have to pass a list of coordinate indices. With # ``add_points=True``, the seleceted points will be highlighted in red. @@ -337,7 +337,7 @@ # %% # Plotly # """""" -# +# # **Note:** It is not recommended to plot the full # :func:`pair_field ` with all points # using plotly. Due to the implementation, that makes the plot really, @@ -361,10 +361,10 @@ # 4.5.1 `plot(kind='scatter') ` # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # The scatter plot can be used to inspect the experimental variogram data on a # spatial and temporal axis, with the fitted spatio-temporal model fitted to the data. -# +# # Plotly # """""" backend('plotly') @@ -394,7 +394,7 @@ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # 3D plots are great for data exploration, especially if they are interactive. # For publications, 3D plots are not that helpful. Additionally, it can be quite -# tricky sometimes to find a good angle to focus on the main message of a 3D plot. +# tricky sometimes to find a good angle to focus on the main message of a 3D plot. # Hence, there are more plotting modes. They can either be used by # setting ``kind='contour'`` or ``kind='contourf'``. Alternatively, these two # plotting types also have their own method. @@ -403,7 +403,7 @@ # dimension on the y-axis. The semi-variance itself is shown as a contour plot, # that can either only plot the lines (``'contour'``) or filled areas for each # contour (``'contourf'``). -# +# # Plotly # """""" backend('plotly') @@ -418,7 +418,7 @@ # %% # Matplotlib # """""""""" -# +# # The matplotlib versions of the contour plots are not that sophisticated, # but the returned figure can be adjusted to your needs. backend('matplotlib') @@ -426,7 +426,7 @@ # %% -# +# fig = STV.plot(kind='contourf') # %% @@ -437,14 +437,14 @@ # implemented as :class:`Variogram ` instances and can be # changed and plotted like any other :class:`Variogram ` instance, # it can come very handy to plot the marginal models side-by-side. -# +# # This can be done with the :func`marginals ` method. backend('plotly') fig = STV.marginals(show=False) fig # %% -# +# backend('matplotlib') fig = STV.marginals() @@ -457,4 +457,3 @@ backend('plotly') fig = STV.marginals(include_model=True, show=False) fig - diff --git a/docs/tutorials/tutorial_05_binning.py b/docs/tutorials/tutorial_05_binning.py index 5e4bb0c..0c81e93 100644 --- a/docs/tutorials/tutorial_05_binning.py +++ b/docs/tutorials/tutorial_05_binning.py @@ -7,7 +7,7 @@ geostatistical literature. The main reason is, that usually, the same method is used. A user-set amount of equidistant lag classes is formed with ``0`` as lower bound and ``maxlag`` as upper bound. Maxlag is often set to the median or 60% -percentile of all pairwise separating distances. +percentile of all pairwise separating distances. In SciKit-GStat this is also the default behavior, but only one of dozen of different implemented methods. Thus, we want to shed some light onto the other @@ -53,7 +53,7 @@ fig # %% -# .. note:: +# .. note:: # You need to comment the next cell to use the pancake dataset. This cell will # will overwrite the ``coords`` and ``vals`` array create in the last cell. coords, vals = skg.data.meuse().get('sample') @@ -101,7 +101,7 @@ # method will adjust the lag class widths to have the same sample size for each # lag class. This can be used, when there must not be any empty lag classes on # small data samples, or comparable sample sizes are desirable for the -# semi-variance estimator. +# semi-variance estimator. # apply binning bins, _ = skg.binning.uniform_count_lags(V.distance, N, None) @@ -121,9 +121,9 @@ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # The distance matrix is clustered by a K-Means algorithm. # The centroids are used as lag class centers. Each lag class is then formed -# by taking half the distance to each sorted neighboring centroid as a bound. +# by taking half the distance to each sorted neighboring centroid as a bound. # This will most likely result in non-equidistant lag classes. -# +# # One important note about K-Means clustering is, that it is not a # deterministic method, as the starting points for clustering are taken randomly. # Thus, the decision was made to seed the random start values. Therefore, the @@ -148,17 +148,17 @@ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # The other clustering algorithm is a hierarchical clustering algorithm. # This algorithm groups values together based on their similarity, which is -# expressed by Ward's criterion. +# expressed by Ward's criterion. # Agglomerative algorithms work iteratively and deterministic, as at first # iteration each value forms a cluster on its own. Each cluster is then merged # with the most similar other cluster, one at a time, until all clusters are -# merged, or the clustering is interrupted. +# merged, or the clustering is interrupted. # Here, the clustering is interrupted as soon as the specified number of lag # classes is reached. The lag classes are then formed similar to the K-Means # method, either by taking the cluster mean or median as center. -# +# # Ward's criterion defines the one other cluster as the closest, that results -# in the smallest intra-cluster variance for the merged clusters. +# in the smallest intra-cluster variance for the merged clusters. # The main downside is the processing speed. You will see a significant # difference for ``'ward'`` and should not use it on medium and large datasets. @@ -178,16 +178,16 @@ # %% # 5.3 Lag class binning - adjustable ``N`` # ----------------------------------------- -# +# # 5.3.1 :func:`'sturges' ` lag classes # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # Sturge's rule is well known and pretty straightforward. It's the default # method for histograms in R. The number of equidistant lag classes is defined like: -# +# # .. math:: -# +# # n =log_2 (x + 1) -# +# # Sturge's rule works good for small, normal distributed datasets. # apply binning @@ -208,13 +208,13 @@ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # Scott's rule is another quite popular approach to estimate histograms. # The rule is defined like: -# +# # .. math:: -# +# # h = \sigma \frac{24 * \sqrt{\pi}}{x}^{\frac{1}{3}} -# +# # Other than Sturge's rule, it will estimate the lag class width from the -# sample size standard deviation. Thus, it is also quite sensitive to outliers. +# sample size standard deviation. Thus, it is also quite sensitive to outliers. # apply binning bins, n = skg.binning.auto_derived_lags(V.distance, 'scott', None) @@ -232,13 +232,13 @@ # %% # 5.3.3 :func:`'sqrt' ` lag classes # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# The only advantage of this method is its speed. The number of lag classes +# The only advantage of this method is its speed. The number of lag classes # is simply defined like: -# +# # .. math:: -# +# # n = \sqrt{x} $$ -# +# # Thus, it's usually not really a good choice, unless you have a lot of samples. # apply binning @@ -257,14 +257,14 @@ # %% # 5.3.4 :func:`'fd' ` lag classes # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # The Freedman-Diaconis estimator can be used to derive the number of lag -# classes again from an optimal lag class width like: +# classes again from an optimal lag class width like: +# +# .. math:: # -# .. math:: -# # h = 2\frac{IQR}{x^{1/3}} -# +# # As it is based on the interquartile range (IQR), it is very robust to outlier. # That makes it a suitable method to estimate lag classes on non-normal distance # matrices. On the other side it usually over-estimates the $n$ for small @@ -286,13 +286,13 @@ # %% # 5.3.5 :func:`'doane' ` lag classes # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # Doane's rule is an extension to Sturge's rule that takes the skewness of the # distance matrix into account. It was found to be a very reasonable choice on # most datasets where the other estimators didn't yield good results. -# +# # It is defined like: -# +# # .. math:: # \begin{split} # n = 1 + \log_{2}(s) + \log_2\left(1 + \frac{|g|}{k}\right) \\ @@ -321,7 +321,7 @@ # all variograms, so any change is due to the lag class binning. The variogram # will use a maximum lag of ``200`` to get rid of the very thin last bins at # large distances. -# +# # The ``maxlag`` is very close to the effective range of the variogram, thus you # can only see differences in sill. But the variogram fitting is not at the # focus of this tutorial. You can also change the parameter and fit a more @@ -362,7 +362,7 @@ # %% # 5.4.3 :func:`'kmeans' ` lag classes # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # set the new binning method V.bin_func = 'kmeans' @@ -447,7 +447,7 @@ # %% # 5.4.9 :func:`'doane' ` lag classes # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# # In[23]: @@ -459,4 +459,3 @@ print(f'"{V._bin_func_name}" adjusted {V.n_lags} lag classes - range: {np.round(V.cof[0], 1)} sill: {np.round(V.cof[1], 1)}') fig.update_layout(template='plotly_white') fig - diff --git a/docs/tutorials/tutorial_06_gstools.py b/docs/tutorials/tutorial_06_gstools.py index 5288671..0101593 100644 --- a/docs/tutorials/tutorial_06_gstools.py +++ b/docs/tutorials/tutorial_06_gstools.py @@ -2,12 +2,12 @@ 6 - GSTools =========== With version ``0.5`` ``scikit-gstat`` offers an interface to the awesome `gstools `_ -library. This way, you can use a :class:`Variogram ` estimated with ``scikit-gstat`` +library. This way, you can use a :class:`Variogram ` estimated with ``scikit-gstat`` in `gstools `_ to perform random field generation, kriging and much, much more. -For a :class:`Variogram ` instance, there are three possibilities to export into `gstools `_ : +For a :class:`Variogram ` instance, there are three possibilities to export into `gstools `_ : - 1. :func:`Variogram.get_empirical(bin_center=True) ` returns a pair of distance lag bins and experimental semi-variance values, like `gstools.variogram.vario_estimate `_. + 1. :func:`Variogram.get_empirical(bin_center=True) ` returns a pair of distance lag bins and experimental semi-variance values, like `gstools.variogram.vario_estimate `_. 2. :func:`Variogram.to_gstools ` returns a parameterized :any:`CovModel ` derived from the Variogram. 3. :func:`Variogram.to_gs_krige ` returns a :any:`GSTools Krige ` instance based on the variogram @@ -18,8 +18,8 @@ 6.1.1 Reproducing the gstools example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can reproduce the `Getting Started example for variogram estimation from GSTools docs `_ -with ``scikit-gstat``, and replace the calculation of the empirical variogram with :class:`skg.Variogram `. +You can reproduce the `Getting Started example for variogram estimation from GSTools docs `_ +with ``scikit-gstat``, and replace the calculation of the empirical variogram with :class:`skg.Variogram `. Note: This does only make sense if you want to use a distance metric, binning procedure or semi-variance estimator, that is not included in `gstools` or are bound to `scikit-gstat` for any other reason. :class:`Variogram ` will _always_ perform a full model fitting cycle on instantiation, which could lead to some substantial overhead here. This behavior might change in a future version of `scikit-gstat`. @@ -60,7 +60,7 @@ # bin_center, gamma = gs.vario_estimate((x, y), field) # # -# Here, we can use :class:`skg.Variogram `. +# Here, we can use :class:`skg.Variogram `. # From the shown arguments, :func:`estimator ` and # :func:`bin_func ` are using the default values: @@ -172,7 +172,7 @@ # 6.2.1 exporting :class:`Variogram ` # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # -# In this example, the same Variogram from above is estimated, but we use the :func:`exponential ` model. +# In this example, the same Variogram from above is estimated, but we use the :func:`exponential ` model. # An exponential covariance function was used in the first place to create the field that was sampled. skg.plotting.backend('plotly') @@ -197,7 +197,7 @@ # and you want to use the :class:`Variogram.coordinates `, you **must** transpose them. # # .. code-block:: python -# +# # # variogram is a skgstat.Variogram instance # model = variogram.to_gstools() # cond_pos = variogram.coordinates.T @@ -224,16 +224,16 @@ malformed.plot() # %% -# Notice how the spatial properties as well as the value range has changed. -# That's why it is important to estimate :class:`Variogram ` or :any:`CovModel ` +# Notice how the spatial properties as well as the value range has changed. +# That's why it is important to estimate :class:`Variogram ` or :any:`CovModel ` # carefully and not let the GIS do that for you somewhere hidden in the dark. # %% # 6.3 ``to_gs_krige`` # ~~~~~~~~~~~~~~~~~~~ # -# Finally, after carefully estimating and fitting a variogram using SciKit-GStat, -# you can also export it directly into a :any:`GSTools Krige ` instance. +# Finally, after carefully estimating and fitting a variogram using SciKit-GStat, +# you can also export it directly into a :any:`GSTools Krige ` instance. # We use the variogram as in the other sections: # export diff --git a/docs/tutorials/tutorial_07_maximum_likelihood_fit.py b/docs/tutorials/tutorial_07_maximum_likelihood_fit.py index 2fe31f6..715b890 100644 --- a/docs/tutorials/tutorial_07_maximum_likelihood_fit.py +++ b/docs/tutorials/tutorial_07_maximum_likelihood_fit.py @@ -85,7 +85,7 @@ # load the likelihood function for this variogram likelihood = get_likelihood(V) -# minimize the likelihood function +# minimize the likelihood function t3 = time() res = minimize(likelihood, p0, bounds=bounds, method='SLSQP') t4 = time() @@ -97,9 +97,9 @@ # %% # Here, you can see one of the main limitations for ML approaches: runtime. -# A sample size of 300 is rather small and the ML is running +# A sample size of 300 is rather small and the ML is running # considerably slower that MoM. -# +# # Apply the optimized parameters. For comparison, the three method-of-moment methods # from SciKit-GStat are applied as well. Note that the used sample is quite dense. # Thus we do not expect a different between the MoM based procedures. @@ -154,7 +154,7 @@ def f(h, a): return 0. return (3*h) / (2*a) - 0.5 * (h / a)**3 -# create the autocovariance matrix +# create the autocovariance matrix def get_A(r, s, b, dists): a = np.array([f(d, r) for d in dists]) A = squareform((s / (s + b)) * (1 - a)) @@ -182,7 +182,7 @@ def like(r, s, b, z, dists): # %% # You can adjust the autocorrelation function above to any other model and # implement other approaches by adjusting the ``like`` function. -# Finally, minimizing this function is the same like before. You also have to +# Finally, minimizing this function is the same like before. You also have to # take care of the SciPy interface, as you need to wrap the custom likelihood # function to provide the parameters in the right format. from scipy.optimize import minimize diff --git a/docs/userguide/introduction.rst b/docs/userguide/introduction.rst index 511db1f..1a164f7 100644 --- a/docs/userguide/introduction.rst +++ b/docs/userguide/introduction.rst @@ -22,7 +22,7 @@ What is geostatistics? ====================== The basic idea of geostatistics is to describe and estimate spatial -covariance, or correlation, in a set of point data. +covariance, or correlation, in a set of point data. While the main tool, the semi-variogram, is quite easy to implement and use, a lot of important assumptions are underlying it. The typical application is geostatistics is an interpolation. Therefore, @@ -95,9 +95,9 @@ own tools: .. note:: - I am not planning to implement tools from all three fields. + I am not planning to implement tools from all three fields. You can rather use one of the interfaces, like :func:`Variogram.to_gstools ` - to export a variogram to another library, that covers kriging and + to export a variogram to another library, that covers kriging and spatial random field generation in great detail. @@ -121,4 +121,4 @@ Each function will return a dictionary of the actual sample and a brief descript import skgstat as skg skg.data.aniso(N=20) -These samples contain a coordinate and a value array. \ No newline at end of file +These samples contain a coordinate and a value array. diff --git a/docs/userguide/kriging.rst b/docs/userguide/kriging.rst index 500a338..6b00db0 100644 --- a/docs/userguide/kriging.rst +++ b/docs/userguide/kriging.rst @@ -5,80 +5,80 @@ Interpolation Spatial interpolation ===================== -In geostatistics the procedure of spatial interpolation is -known as *Kriging*. That goes back to the inventor of -Kriging, a South-African mining engineer called Dave Krige. +In geostatistics the procedure of spatial interpolation is +known as *Kriging*. That goes back to the inventor of +Kriging, a South-African mining engineer called Dave Krige. He published the method in 1951. -In many text books you will also find the term *prediction*, but -be aware that Kriging is still based on the assumption -that the variable is a random field. THerefore I prefer the +In many text books you will also find the term *prediction*, but +be aware that Kriging is still based on the assumption +that the variable is a random field. THerefore I prefer the term *estimation* and would label the Kriging method a *BLUE*, **B** est **L** inear **U** nbiased **E** stimator. -In general terms, the objective is to estimate a variable at -a location that was not observed using observations from -close locations. Kriging is considered to be the **best** -estimator, because we utilize the spatial structure -described by a variogram to find suitable weights for +In general terms, the objective is to estimate a variable at +a location that was not observed using observations from +close locations. Kriging is considered to be the **best** +estimator, because we utilize the spatial structure +described by a variogram to find suitable weights for averaging the observations at close locations. -Given a set of observation points `s` and observation +Given a set of observation points `s` and observation values at these locations :math:`Z(s)`, it can already be stated -that the estimation at an unobserved location :math:`Z^{*}(s_0)` +that the estimation at an unobserved location :math:`Z^{*}(s_0)` is a weighted mean: .. math:: Z^{*}(s_0) = \sum_{i=0}^N {\lambda}_i Z(s_i) - -where :math:`N` is the size of :math:`s` and :math:`\lambda` -is the array of weights. This is what we want to calculate + +where :math:`N` is the size of :math:`s` and :math:`\lambda` +is the array of weights. This is what we want to calculate from a fitted variogram model. -Assumed that :math:`\lambda` had already been calculated, +Assumed that :math:`\lambda` had already been calculated, estimating the prediction is pretty straightforward: .. ipython:: python :suppress: - + import numpy as np from scipy.spatial.distance import pdist, squareform from pprint import pprint np.set_printoptions(precision=3) - + .. ipython:: python - + Z_s = np.array([4.2, 6.1, 0.2, 0.7, 5.2]) lam = np.array([0.1, 0.3, 0.1, 0.1, 0.4]) - + # calculate the weighted mean np.sum(Z_s * lam) - + or shorter: .. ipython:: python - + Z_s.dot(lam) -In the example above the weights were just made up. -Now we need to understand how this array of weights +In the example above the weights were just made up. +Now we need to understand how this array of weights can be calculated. Using a spatial model ===================== -Instead of just making up weights, we will now learn +Instead of just making up weights, we will now learn how we can utilize a variogram model to calculate the weights. -At its core a variogram describes how point observations become -more dissimilar with distance. Point distances can easily be calculated, +At its core a variogram describes how point observations become +more dissimilar with distance. Point distances can easily be calculated, not only for observed locations, but also for unobserved locations. -As the variogram is only a function of *distance*, we can easily +As the variogram is only a function of *distance*, we can easily calculate a semi-variance value for any possible combination of point -pairs. +pairs. -Assume we have five close observations for an unobserved location, -like in the example above. Instead of making up weights, we can use -the semi-variance value as a weight, as a first shot. -What we still need are locations and a variogram model. For both, +Assume we have five close observations for an unobserved location, +like in the example above. Instead of making up weights, we can use +the semi-variance value as a weight, as a first shot. +What we still need are locations and a variogram model. For both, we can just make something up. .. ipython:: python @@ -86,55 +86,55 @@ we can just make something up. x = np.array([4.0, 2.0, 4.1, 0.3, 2.0]) y = np.array([5.5, 1.2, 3.7, 2.0, 2.5]) z = np.array([4.2, 6.1, 0.2, 0.7, 5.2]) - + s0 = [2., 2.] - + distance_matrix = pdist([s0] + list(zip(x,y))) - + squareform(distance_matrix) - -Next, we build up a variogram model of spherical shape, that uses a -effective range larger than the distances in the matrix. Otherwise, + +Next, we build up a variogram model of spherical shape, that uses a +effective range larger than the distances in the matrix. Otherwise, we would just calculate the arithmetic mean. .. ipython:: python from skgstat.models import spherical - + # range= 7. sill = 2. nugget = 0. model = lambda h: spherical(h, 7.0, 2.0, 0.0) - -The distances to the first point `s0` are the first 5 elements in -the distance matrix. Therefore the semi-variances are calculated + +The distances to the first point `s0` are the first 5 elements in +the distance matrix. Therefore the semi-variances are calculated straightforward. .. ipython:: python variances = model(distance_matrix[:5]) assert len(variances) == 5 - -Of course we could now use the inverse of these semi-variances + +Of course we could now use the inverse of these semi-variances to weigh the observations, **but that would not be correct.** -Remember, that this array `variances` is what we want the -target weights to incorporte. Whatever the weights are, these -variances should be respected. At the same time, the five +Remember, that this array `variances` is what we want the +target weights to incorporte. Whatever the weights are, these +variances should be respected. At the same time, the five points among each other also have distances and therefore variances -that should be respected. Or to put it differently. -Take the first observation point :math:`s_1`. The associated variances -:math:`\gamma` to the other four points need to match the one +that should be respected. Or to put it differently. +Take the first observation point :math:`s_1`. The associated variances +:math:`\gamma` to the other four points need to match the one just calculated. .. math:: a_1 * \gamma(s_1, s_1) + a_2 * \gamma(s_1, s_2) + a_3 * \gamma(s_1, s_3) + a_4 * \gamma(s_1, s_4) + a_5 * \gamma(s_1, s_5) = \gamma(s_1, s_0) -Ok. First: :math:`\gamma(s_1, s_1)` is zero because the distance is obviously zero +Ok. First: :math:`\gamma(s_1, s_1)` is zero because the distance is obviously zero and the model does not have a nugget. All other distances have already been calculated. -:math:`a_1 ... a_5` are factors. These are the weights used to satisfy all given -semi-variances. This is what we need. Obviously, we cannot calculate 5 unknown +:math:`a_1 ... a_5` are factors. These are the weights used to satisfy all given +semi-variances. This is what we need. Obviously, we cannot calculate 5 unknown variables from just one equation. Lukily we have four more observations. Writing the above equation for :math:`s_2, s_3, s_4, s_5`. -Additionally, we will write the linear equation system in matrix form as a +Additionally, we will write the linear equation system in matrix form as a dot product of the :math:`\gamma_i` and the :math:`a_i` part. .. math:: @@ -145,14 +145,14 @@ dot product of the :math:`\gamma_i` and the :math:`a_i` part. \gamma(s_3, s_1) & \gamma(s_3, s_2) & \gamma(s_3, s_3) & \gamma(s_3, s_4) & \gamma(s_3, s_5) \\ \gamma(s_4, s_1) & \gamma(s_4, s_2) & \gamma(s_4, s_3) & \gamma(s_4, s_4) & \gamma(s_4, s_5) \\ \gamma(s_5, s_1) & \gamma(s_5, s_2) & \gamma(s_5, s_3) & \gamma(s_5, s_4) & \gamma(s_5, s_5) \\ - \end{pmatrix} * + \end{pmatrix} * \begin{bmatrix} a_1 \\ a_2 \\ a_3 \\ a_4 \\ a_5\\ - \end{bmatrix} = + \end{bmatrix} = \begin{pmatrix} \gamma(s_0, s_1) \\ \gamma(s_0, s_2) \\ @@ -161,13 +161,13 @@ dot product of the :math:`\gamma_i` and the :math:`a_i` part. \gamma(s_0, s_5) \\ \end{pmatrix} -That might look a bit complicated at first, but we have calculated almost everything. +That might look a bit complicated at first, but we have calculated almost everything. The last matrix are the `variances` that we calculated in the last step. -The first matrix is of same shape as the sqaureform distance matrix calculated in -the very beginning. All we need to do is to map the variogram model on it and +The first matrix is of same shape as the sqaureform distance matrix calculated in +the very beginning. All we need to do is to map the variogram model on it and solve the system for the matrix of factors :math:`a_1 \ldots a_5`. In Python, there are several strategies how you could solve this problem. -Let's at first build the matrix. We need a distance matrix without +Let's at first build the matrix. We need a distance matrix without :math:`s_0` for that. .. ipython:: python @@ -192,12 +192,12 @@ And solve it: # calculate estimation Z_s.dot(a) -That's it. Well, not really. We might have used the -variogram and the spatial structure inferred from the -data for getting better results, but in fact our -result is not **unbiased**. That means, the solver +That's it. Well, not really. We might have used the +variogram and the spatial structure inferred from the +data for getting better results, but in fact our +result is not **unbiased**. That means, the solver can choose any combination that satisfies the equation, -even setting everything to zero except one weight. +even setting everything to zero except one weight. That means :math:`a` could be biased. That would not be helpful. @@ -208,14 +208,14 @@ That would not be helpful. Kriging equation system ======================= -In the last section we came pretty close to the -Kriging algorithm. The only thing missing is to +In the last section we came pretty close to the +Kriging algorithm. The only thing missing is to assure unbiasedness. The weights sum up to almost one, but they are not one. -We want to ensure, that they are always one. This -is done by adding one more equation to the linear +We want to ensure, that they are always one. This +is done by adding one more equation to the linear equation system. Also, we will rename the :math:`a` -array to :math:`\lambda`, which is more frequently +array to :math:`\lambda`, which is more frequently used for Kriging weights. The missing equation is: .. math:: @@ -233,7 +233,7 @@ In matrix form this changes :math:`M` to: \gamma(s_4, s_1) & \gamma(s_4, s_2) & \gamma(s_4, s_3) & \gamma(s_4, s_4) & \gamma(s_4, s_5) & 1\\ \gamma(s_5, s_1) & \gamma(s_5, s_2) & \gamma(s_5, s_3) & \gamma(s_5, s_4) & \gamma(s_5, s_5) & 1\\ 1 & 1 & 1 & 1 & 1 & 0 \\ - \end{pmatrix} * + \end{pmatrix} * \begin{bmatrix} \lambda_1 \\ \lambda_2 \\ @@ -241,7 +241,7 @@ In matrix form this changes :math:`M` to: \lambda_4 \\ \lambda_5 \\ \mu \\ - \end{bmatrix} = + \end{bmatrix} = \begin{pmatrix} \gamma(s_0, s_1) \\ \gamma(s_0, s_2) \\ @@ -251,15 +251,15 @@ In matrix form this changes :math:`M` to: 1 \\ \end{pmatrix} -This is the Kriging equation for Ordinary Kriging that can be found -in text books. We added the ones to the result array and into the -matrix of semivariances. :math:`\mu` is a Lagrangian multiplier -that will be used to estimate the Kriging variance, which will +This is the Kriging equation for Ordinary Kriging that can be found +in text books. We added the ones to the result array and into the +matrix of semivariances. :math:`\mu` is a Lagrangian multiplier +that will be used to estimate the Kriging variance, which will be covered later. -Ordinary Kriging still assumes the observation and their residuals +Ordinary Kriging still assumes the observation and their residuals to be normally distributed and second order stationarity. -.. todo:: +.. todo:: Include the references to Kitanidis and Bardossy. Applied in Python, this can be done like: @@ -293,11 +293,11 @@ perfectly sum up to one now. Kriging error ============= -In the last step, we introduced a factor :math:`\mu`. -It was needed to solve the linear equation system -while assuring that the weights sum up to one. +In the last step, we introduced a factor :math:`\mu`. +It was needed to solve the linear equation system +while assuring that the weights sum up to one. This factor can in turn be added to the weighted -target semi-variances used to build the equation system, +target semi-variances used to build the equation system, to obtain the Kriging error. .. ipython:: python @@ -311,16 +311,16 @@ in which regions the interpolation is more certain. Example ======= -We can use the data shown in the variography section, -to finally interpolate the field and check the -Kriging error. You could either build a loop around the -code shown in the previous section, or just use +We can use the data shown in the variography section, +to finally interpolate the field and check the +Kriging error. You could either build a loop around the +code shown in the previous section, or just use skgstat. .. ipython:: python :suppress: - import pandas as pd + import pandas as pd from skgstat import Variogram import matplotlib.pyplot as plt @@ -328,9 +328,9 @@ skgstat. :okwarning: data = pd.read_csv('data/sample_lr.csv') - V = Variogram(data[['x', 'y']].values, data.z.values, + V = Variogram(data[['x', 'y']].values, data.z.values, maxlag=90, n_lags=25, model='gaussian', normalize=False) - + @savefig kriging_used_variogram.png width=8in V.plot() @@ -339,28 +339,28 @@ skgstat. ok = OrdinaryKriging(V, min_points=5, max_points=20, mode='exact') The :class:`OrdinaryKriging ` class -need at least a fitted :class:`Variogram ` -instance. Using `min_points` we can demand the Kriging equation +need at least a fitted :class:`Variogram ` +instance. Using `min_points` we can demand the Kriging equation system to be build upon at least 5 points to yield robust results. If not enough close observations are found within the effective range -of the variogram, the estimation will not be calculated and a +of the variogram, the estimation will not be calculated and a `np.NaN` value is estimated. -The `max_points` parameter will set the upper bound of the +The `max_points` parameter will set the upper bound of the equation system by using in this case at last the 20 nearest points. Adding more will most likely not change the estimation, as more points will receive small, if not negligible, weights. -But it will increase the processing time, as each added point will +But it will increase the processing time, as each added point will increase the Kriging equation system dimensionality by one. -The `mode` parameter sets the method that will +The `mode` parameter sets the method that will build up the equation system. There are two implemented: -`mode='exact'` and `mode='estimate'`. Estimate is much faster, but -if not used carefully, it can lead to numerical instability quite -quickly. In the technical notes section of this userguide, you +`mode='exact'` and `mode='estimate'`. Estimate is much faster, but +if not used carefully, it can lead to numerical instability quite +quickly. In the technical notes section of this userguide, you will find a whole section on the two modes. -Finally, we need the unobsered locations. The observations in +Finally, we need the unobsered locations. The observations in the file were drawn from a `100x100` random field. .. ipython:: python @@ -383,4 +383,3 @@ the file were drawn from a `100x100` random field. @savefig kriging_result_and_error.png width=8in fig.show() - diff --git a/docs/userguide/userguide.rst b/docs/userguide/userguide.rst index 364de39..469ba20 100644 --- a/docs/userguide/userguide.rst +++ b/docs/userguide/userguide.rst @@ -11,4 +11,4 @@ along with a more general introduction to variogram analysis. introduction variogram - kriging \ No newline at end of file + kriging diff --git a/docs/userguide/variogram.rst b/docs/userguide/variogram.rst index 2a17844..bb1d5d8 100644 --- a/docs/userguide/variogram.rst +++ b/docs/userguide/variogram.rst @@ -138,15 +138,15 @@ suitable compromise. Before diving into binning, we have to understand how the :class:`Variogram Class ` handles distance data. The -distance calculation can be controlled by the +distance calculation can be controlled by the :func:`dist_func ` argument, which takes either a string or a function. The default value is `'euclidean'`. This value is directly passed down to the :func:`pdist ` as the `metric` argument. -Consequently, the distance data is stored as a distance matrix for all -input locations passed to :class:`Variogram ` on -creation. To be more precise, only the upper triangle is stored -in a :class:`array ` with the distance values sorted +Consequently, the distance data is stored as a distance matrix for all +input locations passed to :class:`Variogram ` on +creation. To be more precise, only the upper triangle is stored +in a :class:`array ` with the distance values sorted row-wise. Consider this very straightforward set of locations: .. ipython:: python @@ -167,15 +167,15 @@ Binning ------- As already mentioned, in real world observation data, there won't -be two observation location pairs at **exactly** the same distance. +be two observation location pairs at **exactly** the same distance. Thus, we need to group information about point pairs at **similar** distance -together, to learn how similar their observed values are. +together, to learn how similar their observed values are. With a :class:`Variogram `, we will basically try -to find and describe some systematic statistical behavior from these -similarities. The process of grouping distance data together is +to find and describe some systematic statistical behavior from these +similarities. The process of grouping distance data together is called *binning*. -``scikit-gstat`` has many different methods for binning distance data. +``scikit-gstat`` has many different methods for binning distance data. They can be set using the :func:`bin_func ` attribute. You have to pass the name of the method. The available methods are: @@ -191,14 +191,14 @@ The available methods are: * :func:`ward ` - derive bins by hierarchical clustering and Ward's criterion * :func:`stable_entropy ` - derive bins from stable entropy setting -``['even', 'uniform', 'kmeans', 'ward', 'stable_entropy']`` methods will use two parameters +``['even', 'uniform', 'kmeans', 'ward', 'stable_entropy']`` methods will use two parameters to calculate the bins from the distance matrix: :any:`n_lags `, the amount of bins, and :any:`maxlag `, the maximum distance lag to be considered. ``['sturges', 'scott', 'sqrt', 'fd', 'doane']`` will only use :any:`maxlag ` to derive :any:`n_lags ` from statistical properties of the distance matrix. -The :func:`even ` method will +The :func:`even ` method will then form :any:`n_lags ` bins from ``0`` to :any:`maxlag ` -of same width. +of same width. The :func:`uniform ` method will form the same amount of classes within the same range, using the same point pair count in each bin. The following example illustrates this: @@ -213,11 +213,11 @@ The following example illustrates this: distances = pdist(loc) -Now, look at the different bin edges for the calculated dummy +Now, look at the different bin edges for the calculated dummy distance matrix: .. ipython:: python - :okwarning: + :okwarning: even_width_lags(distances, 10, 250) uniform_count_lags(distances, 10, 250) @@ -252,16 +252,16 @@ and :any:`n_lags `. Observation differences ----------------------- -By the term *observation differences*, the distance between the -observed values are meant. As already laid out, the main idea of -a variogram is to systematially relate similarity of observations -to their spatial proximity. The spatial part was covered in the -sections above, finalized with the calculation of a suitable +By the term *observation differences*, the distance between the +observed values are meant. As already laid out, the main idea of +a variogram is to systematially relate similarity of observations +to their spatial proximity. The spatial part was covered in the +sections above, finalized with the calculation of a suitable binning of all distances. We want to relate exactly these bins -to a measure of similarity of all observation point pairs that +to a measure of similarity of all observation point pairs that fall into this bin. -That's basically it. We need to do three more steps to come up +That's basically it. We need to do three more steps to come up with *one* value per bin, statistically describing the similarity at that distance. @@ -270,16 +270,16 @@ at that distance. 3. Describe all differences by one number -Finding all pairs within a bin is straightforward. We already have -the bin edges and all distances between all possible observation -point combinations (stored in the distance matrix). Using the -:func:`squareform ` function +Finding all pairs within a bin is straightforward. We already have +the bin edges and all distances between all possible observation +point combinations (stored in the distance matrix). Using the +:func:`squareform ` function of scipy, we *could* turn the distance matrix into a 2D version. Then the row and column indices align with the values indices. -However, :class:`Variogram ` implements +However, :class:`Variogram ` implements a method for doing mapping a bit more efficiently. -A :class:`array ` of bin groups for each point pair that +A :class:`array ` of bin groups for each point pair that is indexed exactly like the :func:`distance ` array can be obtained by :func:`lag_groups `. @@ -292,14 +292,14 @@ submodule. coords, vals = skg.data.pancake(N=200).get('sample') V = skg.Variogram( - coords, + coords, vals, n_lags=25 ) V.maxlag = 500 Then, you can compare the first 10 point pairs from the distance matrix -to the first 10 elements returned by the +to the first 10 elements returned by the :func:`lag_groups function `. .. ipython:: python @@ -311,10 +311,10 @@ to the first 10 elements returned by the # first 10 groups V.lag_groups()[:10] -Now, we need the actual :func:`Variogram.bins ` +Now, we need the actual :func:`Variogram.bins ` to verify the grouping. -.. ipython:: python +.. ipython:: python :okwarning: V.bins @@ -323,22 +323,22 @@ The elements ``[2, 3, 6, 8]``are grouped into group ``7``. Their distance values are ``[151.2, 156.1, 142.4, 156.5]``. The grouping starts with ``0``, therefore the corresponding upper bound of the bin is at index ``7`` and the lower at ``6``. -The bin edges are therefore ``140. < x < 160.``. +The bin edges are therefore ``140. < x < 160.``. Consequently, the binning and grouping worked fine. -If you want to access all value pairs at a given group, it would of +If you want to access all value pairs at a given group, it would of course be possible to use the mechanism above to find the correct points. -However, :class:`Variogram ` offers an iterator -that already does that for you: -:func:`lag_classes `. This iterator -will yield all pair-wise observation value differences for the bin -of the actual iteration. The first iteration (index = 0, if you wish) -will yield all differences of group id ``0``. +However, :class:`Variogram ` offers an iterator +that already does that for you: +:func:`lag_classes `. This iterator +will yield all pair-wise observation value differences for the bin +of the actual iteration. The first iteration (index = 0, if you wish) +will yield all differences of group id ``0``. .. note:: - :func:`lag_classes ` will yield - the difference in value of observation point pairs, not the pairs + :func:`lag_classes ` will yield + the difference in value of observation point pairs, not the pairs themselves. .. ipython:: python @@ -346,18 +346,18 @@ will yield all differences of group id ``0``. for i, group in enumerate(V.lag_classes()): print('[Group %d]: %.2f' % (i, np.mean(group))) -The only thing that is missing for a variogram is that we will not +The only thing that is missing for a variogram is that we will not use the arithmetic mean to describe the realtionship. Experimental variograms ----------------------- -The last stage before a variogram function can be modeled is to define +The last stage before a variogram function can be modeled is to define an experimental variogram, also known as *empirical variogram*, which will be used to parameterize a variogram model. -However, the experimental variogram already contains a lot of information -about spatial relationships in the data. Therefore, it's worth looking -at more closely. Last but not least a poor experimental variogram will +However, the experimental variogram already contains a lot of information +about spatial relationships in the data. Therefore, it's worth looking +at more closely. Last but not least a poor experimental variogram will also affect the variogram model, which is ultimatively used to interpolate the input data. @@ -373,16 +373,16 @@ the input data. :func:`experimental `, thus it is a tuple of two 1D arrays. -The previous sections summarized how distance is calculated and handled -by the :class:`Variogram class `. -The :func:`lag_groups ` function makes it -possible to find corresponding observation value pairs for all distance -lags. Finally the last step will be to use a more suitable estimator -for the similarity of observation values at a specific lag. +The previous sections summarized how distance is calculated and handled +by the :class:`Variogram class `. +The :func:`lag_groups ` function makes it +possible to find corresponding observation value pairs for all distance +lags. Finally the last step will be to use a more suitable estimator +for the similarity of observation values at a specific lag. In geostatistics this estimator is called semi-variance and the -the most popular estimator is called *Matheron estimator*. +the most popular estimator is called *Matheron estimator*. By default, the :func:`Matheron ` estimator will be used. -It is defined as +It is defined as .. math:: \gamma (h) = \frac{1}{2N(h)} * \sum_{i=1}^{N(h)}(x)^2 @@ -392,17 +392,17 @@ with: .. math:: x = Z(x_i) - Z(x_{i+h}) -where :math:`Z(x_i)` is the observation value at the i-th location -:math:`x_i`. :math:`h` is the distance lag and :math:`N(h)` is the +where :math:`Z(x_i)` is the observation value at the i-th location +:math:`x_i`. :math:`h` is the distance lag and :math:`N(h)` is the number of point pairs at that lag. -You will find more estimators in :mod:`skgstat.estimators`. -There is the :func:`Cressie-Hawkins `, -which is more robust to extreme values. Other so called robust -estimators are :func:`Dowd ` or +You will find more estimators in :mod:`skgstat.estimators`. +There is the :func:`Cressie-Hawkins `, +which is more robust to extreme values. Other so called robust +estimators are :func:`Dowd ` or :func:`Genton `. -The remaining are experimental estimators and should only be used -with caution. +The remaining are experimental estimators and should only be used +with caution. Let's compare them directly. You could use the code from the last section to group the pair-wise value differencens into lag groups and apply the formula for each estimator. In the example below, we will iteratively change @@ -437,24 +437,24 @@ achieve this: Variogram models ---------------- -The last step to describe the spatial pattern in a data set +The last step to describe the spatial pattern in a data set using variograms is to model the empirically observed and calculated -experimental variogram with a proper mathematical function. -Technically, this setp is straightforward. We need to define a -function that takes a distance value and returns -a semi-variance value. One big advantage of these models is, that we +experimental variogram with a proper mathematical function. +Technically, this setp is straightforward. We need to define a +function that takes a distance value and returns +a semi-variance value. One big advantage of these models is, that we can assure different things, like positive definitenes. Most models are also monotonically increasing and approach an upper bound. Usually these models need three parameters to fit to the experimental variogram. All three parameters have a meaning and are useful to learn something about the data. This upper bound a model approaches -is called *sill*. The distance at which 95% of the sill are approached -is called the *effective range*. -That means, the range is the distance at which -observation values do **not** become more dissimilar with increasing -distance. They are statistically independent. That also means, it doesn't -make any sense to further describe spatial relationships of observations -further apart with means of geostatistics. +is called *sill*. The distance at which 95% of the sill are approached +is called the *effective range*. +That means, the range is the distance at which +observation values do **not** become more dissimilar with increasing +distance. They are statistically independent. That also means, it doesn't +make any sense to further describe spatial relationships of observations +further apart with means of geostatistics. The last parameter is the *nugget*. It is used to add semi-variance to all values. Graphically that means to *move the variogram up on the y-axis*. The nugget is the semi-variance modeled @@ -469,15 +469,15 @@ cannot be described spatially. it was decided to fit models on the *effective range*. You can translate one into the other quite easily. Transformation factors are reported in literature, but not commonly the same ones are used. - Finally, the transformation is always coded into SciKit-GStat's + Finally, the transformation is always coded into SciKit-GStat's :any:`models `, even if it's a 1:1 *transformation*. The spherical model ~~~~~~~~~~~~~~~~~~~ -The sperical model is the most commonly used variogram model. +The sperical model is the most commonly used variogram model. It is characterized by a very steep, exponential increase in semi-variance. -That means it approaches the sill quite quickly. It can be used when +That means it approaches the sill quite quickly. It can be used when observations show strong dependency on short distances. It is defined like: @@ -488,30 +488,30 @@ if h < r, and .. math:: \gamma = b + C_0 - + else. ``b`` is the nugget, :math:`C_0` is the sill, ``h`` is the input -distance lag and ``r`` is the effective range. That is the range parameter -described above, that describes the correlation length. -Many other variogram model implementations might define the range parameter, -which is a variogram parameter. This is a bit confusing, as the range parameter -is specific to the used model. Therefore I decided to directly use the -*effective range* as a parameter, as that makes more sense in my opinion. - -As we already calculated an experimental variogram and find the spherical -model in the :any:`models ` sub-module, we can utilize e.g. -:func:`curve_fit ` from scipy to fit the model +distance lag and ``r`` is the effective range. That is the range parameter +described above, that describes the correlation length. +Many other variogram model implementations might define the range parameter, +which is a variogram parameter. This is a bit confusing, as the range parameter +is specific to the used model. Therefore I decided to directly use the +*effective range* as a parameter, as that makes more sense in my opinion. + +As we already calculated an experimental variogram and find the spherical +model in the :any:`models ` sub-module, we can utilize e.g. +:func:`curve_fit ` from scipy to fit the model using a least squares approach. .. note:: - With the given example, the default usage of :func:`curve_fit ` + With the given example, the default usage of :func:`curve_fit ` will use the Levenberg-Marquardt algorithm, without initial guess for the parameters. - This will fail to find a suitable range parameter. + This will fail to find a suitable range parameter. Thus, for this example, you need to pass an initial guess to the method. - + .. ipython:: python :okwarning: - + from skgstat import models # set estimator back @@ -520,34 +520,34 @@ using a least squares approach. xdata = V.bins ydata = V.experimental - + from scipy.optimize import curve_fit - + # initial guess - otherwise lm will not find a range - p0 = [np.mean(xdata), np.mean(ydata), 0] + p0 = [np.mean(xdata), np.mean(ydata), 0] cof, cov =curve_fit(models.spherical, xdata, ydata, p0=p0) - + Here, *cof* are now the coefficients found to fit the model to the data. .. ipython:: python :okwarning: print("range: %.2f sill: %.f nugget: %.2f" % (cof[0], cof[1], cof[2])) - + .. ipython:: python :okwarning: - + xi =np.linspace(xdata[0], xdata[-1], 100) yi = [models.spherical(h, *cof) for h in xi] - + plt.plot(xdata, ydata, 'og') @savefig manual_fitted_variogram.png width=8in plt.plot(xi, yi, '-b'); -The :class:`Variogram Class ` does in principle the -same thing. The only difference is that it tries to find a good -initial guess for the parameters and limits the search space for -parameters. That should make the fitting more robust. +The :class:`Variogram Class ` does in principle the +same thing. The only difference is that it tries to find a good +initial guess for the parameters and limits the search space for +parameters. That should make the fitting more robust. Technically, we used the Levenberg-Marquardt algorithm above. That's a commonly used, very fast least squares implementation. However, sometimes it fails to find good parameters, as it is @@ -557,8 +557,8 @@ Trust-Region Reflective (TRF), which is also the default for :class:`Variogram `. It uses a valid parameter space as bounds and therefore won't fail in finding parameters. You can, however, switch to Levenberg-Marquardt -by setting the :class:`Variogram.fit_method ` -to 'lm'. +by setting the :class:`Variogram.fit_method ` +to 'lm'. .. ipython:: python @@ -568,7 +568,7 @@ to 'lm'. @savefig trf_automatic_fit.png width=8in V.plot(); pprint(V.parameters) - + V.fit_method ='lm' @savefig lm_automatic_fit.png width=8in V.plot(); @@ -576,30 +576,30 @@ to 'lm'. .. note:: - In this example, the fitting method does not make a difference + In this example, the fitting method does not make a difference at all. Generally, you can say that Levenberg-Marquardt is faster and TRF is more robust. Exponential model ~~~~~~~~~~~~~~~~~ -The exponential model is quite similar to the spherical one. -It models semi-variance values to increase exponentially with -distance, like the spherical. The main difference is that this -increase is not as steep as for the spherical. That means, the -effective range is larger for an exponential model, that was +The exponential model is quite similar to the spherical one. +It models semi-variance values to increase exponentially with +distance, like the spherical. The main difference is that this +increase is not as steep as for the spherical. That means, the +effective range is larger for an exponential model, that was parameterized with the same range parameter. .. note:: - Remember that SciKit-GStat uses the *effective range* + Remember that SciKit-GStat uses the *effective range* to overcome this confusing behaviour. Consequently, the exponential can be used for data that shows a way -too large spatial correlation extent for a spherical model to -capture. +too large spatial correlation extent for a spherical model to +capture. -Applied to the data used so far, you can see the difference between +Applied to the data used so far, you can see the difference between the two models quite nicely: .. ipython:: python @@ -615,7 +615,7 @@ the two models quite nicely: # switch the model V.model = 'exponential' - + @savefig compare_spherical_exponential.png width=8in V.plot(axes=axes[1], hist=False); @@ -635,7 +635,7 @@ Also, the goodness of fit is quite comparable: r_sph = V.describe().get('effective_range') # exponential - V.model = 'exponential' + V.model = 'exponential' rmse_exp = V.rmse r_exp = V.describe().get('effective_range') @@ -645,7 +645,7 @@ Also, the goodness of fit is quite comparable: But the difference in effective range is more pronounced: .. ipython:: python - + print('Spherical effective range: %.1f' % r_sph) print('Exponential effective range: %.1f' % r_exp) @@ -676,12 +676,12 @@ Finally, we can use both models to perform a Kriging interpolation. axes[0].set_title('Spherical') axes[1].set_title('Exponential') axes[0].imshow(field1, origin='lower', cmap='terrain_r', vmin=vmin, vmax=vmax) - + @savefig model_compare_kriging.png width=8in axes[1].imshow(field2, origin='lower', cmap='terrain_r', vmin=vmin, vmax=vmax) While the two final maps look alike, in the difference plot, you can -spot some differences. While performing an analysis, with the model functions in mind, +spot some differences. While performing an analysis, with the model functions in mind, you should take these differences and add them as uncertainty cause by model choice to your final result. @@ -701,19 +701,19 @@ your final result. Gaussian model ~~~~~~~~~~~~~~ -The last fundamental variogram model is the Gaussian. -Unlike the spherical and exponential it models a very different +The last fundamental variogram model is the Gaussian. +Unlike the spherical and exponential it models a very different spatial relationship between semi-variance and distance. -Following the Gaussian model, observations are assumed to -be similar up to intermediate distances, showing just a -gentle increase in semi-variance. Then, the semi-variance -increases dramatically within just a few distance units up +Following the Gaussian model, observations are assumed to +be similar up to intermediate distances, showing just a +gentle increase in semi-variance. Then, the semi-variance +increases dramatically within just a few distance units up to the sill, which is again approached asymtotically. -The model can be used to simulate very sudden and sharp -changes in the variable at a specific distance, +The model can be used to simulate very sudden and sharp +changes in the variable at a specific distance, while being very similar at smaller distances. -To show a typical Gaussian model, we will load another +To show a typical Gaussian model, we will load another sample dataset, that actually shows a Gaussian experimental variogram. .. ipython:: python @@ -731,15 +731,15 @@ sample dataset, that actually shows a Gaussian experimental variogram. Matérn model ~~~~~~~~~~~~ -Another, quite powerful model is the Matérn model. +Another, quite powerful model is the Matérn model. Especially in cases where you cannot chose the appropriate model a priori so easily. -The Matérn model takes an additional smoothness parameter, that can -change the shape of the function in between an exponential -model shape and a Gaussian one. +The Matérn model takes an additional smoothness parameter, that can +change the shape of the function in between an exponential +model shape and a Gaussian one. .. ipython:: python :okwarning: - + xi = np.linspace(0, 100, 100) # plot a exponential and a gaussian @@ -772,23 +772,23 @@ When direction matters What is 'direction'? -------------------- -The classic approach to calculate a variogram is based on the -assumption that covariance between observations can be related to -their separating distance. For this, point pairs of all observation +The classic approach to calculate a variogram is based on the +assumption that covariance between observations can be related to +their separating distance. For this, point pairs of all observation points are formed and it is assumed that they can be formed without any restriction. -The only parameter to be influenced is a limiting distance, beyond which -a point pair does not make sense anymore. +The only parameter to be influenced is a limiting distance, beyond which +a point pair does not make sense anymore. -This assumption might not always hold. Especially in landscapes, processes do -not occur randomly, but in an organized manner. This organization is often +This assumption might not always hold. Especially in landscapes, processes do +not occur randomly, but in an organized manner. This organization is often directed, which can lead to stronger covariance in one direction than another. Therefore, another step has to be introduced before lag classes are formed. -The *direction* of a variogram is then a orientation, which two points need. -If they are not oriented in the specified way, they will be ignored while calculating -a semi-variance value for a given lag class. Usually, you will specify a -orientation, which is called :func:`azimuth `, -and a :func:`tolerance `, which is an +The *direction* of a variogram is then a orientation, which two points need. +If they are not oriented in the specified way, they will be ignored while calculating +a semi-variance value for a given lag class. Usually, you will specify a +orientation, which is called :func:`azimuth `, +and a :func:`tolerance `, which is an offset from the given azimuth, at which a point pair will still be accepted. Defining orientation @@ -796,12 +796,12 @@ Defining orientation One has to decide how orientation of two points is determined. In scikit-gstat, orientation between two observation points is only defined in :math:`\mathbb{R}^2`. -We define the orientation as the **angle between the vector connecting two observation points +We define the orientation as the **angle between the vector connecting two observation points with the x-axis**. -Thus, also the :func:`azimuth ` is defined as an -angle of the azimutal vector to the x-axis, with an -:func:`tolerance ` in degrees added to the +Thus, also the :func:`azimuth ` is defined as an +angle of the azimutal vector to the x-axis, with an +:func:`tolerance ` in degrees added to the exact azimutal orientation clockwise and counter clockwise. The angle :math:`\Phi` between two vectors ``u,v`` is given like: @@ -828,29 +828,29 @@ The angle :math:`\Phi` between two vectors ``u,v`` is given like: @savefig sample_orientation_of_2_1.png width=6in ax.annotate('26.5°', (1.5, 0.25), fontsize=14, color='r') -The described definition of orientation is illustrated in the figure above. +The described definition of orientation is illustrated in the figure above. There are two observation points, :math:`A (0,0)` and :math:`B (2, 1)`. To decide -whether to account for them when calculating the semi-variance at their separating +whether to account for them when calculating the semi-variance at their separating distance lag, their orientation is used. Only if the direction of the varigram includes -this orientation, the points are used. Imagine the azimuth and tolerance would be +this orientation, the points are used. Imagine the azimuth and tolerance would be ``45°``, then anything between ``0°`` (East) and ``90°`` orientation would be included. -The given example shows the orientation angle :math:`\Phi = 26.5°`, which means the +The given example shows the orientation angle :math:`\Phi = 26.5°`, which means the vector :math:`\overrightarrow{AB}` is included. Calculating orientations ------------------------ -SciKit-GStat implements a slightly adapted version of the formula given in the -last section. It makes use of symmetric search areas (tolerance is applied clockwise -and counter clockwise) und therefore any calculated angle might be the result -of calculating the orientation of :math:`\overrightarrow{AB}` or -:math:`\overrightarrow{BA}`. Mathematically, these two vectors have two different -angles, but they are always both taken into account or omitted for a variagram -at the same time. Thus, it does not make a difference for variography. -However, it does make a difference when you try to use the orientation angles +SciKit-GStat implements a slightly adapted version of the formula given in the +last section. It makes use of symmetric search areas (tolerance is applied clockwise +and counter clockwise) und therefore any calculated angle might be the result +of calculating the orientation of :math:`\overrightarrow{AB}` or +:math:`\overrightarrow{BA}`. Mathematically, these two vectors have two different +angles, but they are always both taken into account or omitted for a variagram +at the same time. Thus, it does not make a difference for variography. +However, it does make a difference when you try to use the orientation angles directly as the containing matrix can contain the inverse angles. -This can be demonstrated by an easy example. Let ``c`` be a set of points mirrored +This can be demonstrated by an easy example. Let ``c`` be a set of points mirrored along the x-axis. .. ipython:: python @@ -868,7 +868,7 @@ We can plug these two arrays into the the formula above: angles = np.degrees(np.arccos(u.dot(east) / np.sqrt(np.sum(u**2, axis=1)))) angles.round(1) -You can see, that the both points and their mirrored counterpart have the same +You can see, that the both points and their mirrored counterpart have the same angle to the x-axis, just like expected. This can be visualized by the plot below: .. ipython:: python @@ -884,10 +884,10 @@ angle to the x-axis, just like expected. This can be visualized by the plot belo @savefig sample_orientation_of_multiple_points.png width=6in ax.scatter(c[:,0], c[:,1], 50, c='r') -The main difference to the internal structure storing the orientation angles for a +The main difference to the internal structure storing the orientation angles for a :class:`DirectionalVariogram ` instance will store different angles. -To use the class on only five points, we need to prevent the class from fitting, as +To use the class on only five points, we need to prevent the class from fitting, as fitting on only 5 points will not work. But this does not affect the orientation calculations. Therefore, the :func:`fit ` method is overwritten. @@ -902,7 +902,7 @@ Therefore, the :func:`fit ` method is overwrit DV._calc_direction_mask_data() np.degrees(DV._angles + np.pi)[:len(c) - 1] -The first two points (with positive y-coordinate) show the same result. The other two, +The first two points (with positive y-coordinate) show the same result. The other two, with negative y-coordinates, are also calculated counter clockwise: .. ipython:: python @@ -910,15 +910,15 @@ with negative y-coordinates, are also calculated counter clockwise: 360 - np.degrees(DV._angles + np.pi)[[2,3]] -The :class:`DirectionalVariogram ` class has a plotting -function to show a network graph of all point pairs that are oriented in the -variogram direction. But first we need to increase the tolerance as half tolerance +The :class:`DirectionalVariogram ` class has a plotting +function to show a network graph of all point pairs that are oriented in the +variogram direction. But first we need to increase the tolerance as half tolerance (``45° / 2 = 22.5°`` clockwise and counter clockwise) is smaller than both orientations. .. ipython:: python :okwarning: - DV.tolerance = 90 + DV.tolerance = 90 @savefig sample_pair_field_plot.png width=8in DV.pair_field() @@ -934,8 +934,8 @@ Directional variogram coords = np.random.randint(100, size=(300,2)) vals = [field[_[0], _[1]] for _ in coords] -The next step is to create two different variogram instances, which share the same -parameters, but use a different azimuth angle. One oriented to North and the +The next step is to create two different variogram instances, which share the same +parameters, but use a different azimuth angle. One oriented to North and the second one oriented to East. .. ipython:: python @@ -945,7 +945,7 @@ second one oriented to East. Veast = skg.DirectionalVariogram(coords, vals, azimuth=0, tolerance=90, maxlag=80, n_lags=20) pd.DataFrame({'north':Vnorth.describe(), 'east': Veast.describe()}) -You can see, how the two are differing in effective range and also sill, only +You can see, how the two are differing in effective range and also sill, only caused by the orientation. Let's look at the experimental variogram: .. ipython:: python @@ -958,16 +958,16 @@ caused by the orientation. Let's look at the experimental variogram: @savefig expermiental_direcional_varigram_comparison.png width=8in plt.legend(loc='upper left') -The shape of both experimental variograms is very similar on the first 40 meters -of distance. Within this range, the apparent anisotropy is not pronounced. +The shape of both experimental variograms is very similar on the first 40 meters +of distance. Within this range, the apparent anisotropy is not pronounced. The East-West oriented variograms also have an effective range of only about 40 meters, -which means that in this direction the observations become statistically independent +which means that in this direction the observations become statistically independent at larger distances. -For the North-South variogram the effective range is way bigger and the variogram -plot reveals much larger correlation lengths in that direction. The spatial +For the North-South variogram the effective range is way bigger and the variogram +plot reveals much larger correlation lengths in that direction. The spatial dependency is thus directed in North-South direction. -To perform Kriging, you would now transform the data, especially in North-West -direction, until both variograms look the same within the effective range. +To perform Kriging, you would now transform the data, especially in North-West +direction, until both variograms look the same within the effective range. Finally, the Kriging result is back-transformed into the original coordinate system. diff --git a/requirements.txt b/requirements.txt index d418082..852de3e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,4 @@ matplotlib numba scikit-learn imageio -tqdm \ No newline at end of file +tqdm diff --git a/requirements.unittest.3.6.txt b/requirements.unittest.3.6.txt index 270dd01..29546ab 100644 --- a/requirements.unittest.3.6.txt +++ b/requirements.unittest.3.6.txt @@ -3,4 +3,4 @@ pytest-cov pytest-depends pykrige gstools>=1.3 -plotly \ No newline at end of file +plotly diff --git a/requirements.unittest.3.7.txt b/requirements.unittest.3.7.txt index 270dd01..29546ab 100644 --- a/requirements.unittest.3.7.txt +++ b/requirements.unittest.3.7.txt @@ -3,4 +3,4 @@ pytest-cov pytest-depends pykrige gstools>=1.3 -plotly \ No newline at end of file +plotly diff --git a/requirements.unittest.3.8.txt b/requirements.unittest.3.8.txt index 270dd01..29546ab 100644 --- a/requirements.unittest.3.8.txt +++ b/requirements.unittest.3.8.txt @@ -3,4 +3,4 @@ pytest-cov pytest-depends pykrige gstools>=1.3 -plotly \ No newline at end of file +plotly diff --git a/skgstat/DirectionalVariogram.py b/skgstat/DirectionalVariogram.py index 2519d50..f4aaa59 100644 --- a/skgstat/DirectionalVariogram.py +++ b/skgstat/DirectionalVariogram.py @@ -628,7 +628,7 @@ def pair_field(self, ax=None, cmap="gist_rainbow", points='all', add_points=True cmap : string Any color-map name that is supported by matplotlib points : 'all', int, list - If not ``'all'``, only the given coordinate (int) or + If not ``'all'``, only the given coordinate (int) or list of coordinates (list) will be plotted. Recommended, if the input data is quite large. add_points : bool @@ -636,7 +636,7 @@ def pair_field(self, ax=None, cmap="gist_rainbow", points='all', add_points=True alpha : float Alpha value for the colors to make overlapping vertices visualize better. Defaults to ``0.3``. - + """ # get the backend used_backend = plotting.backend() @@ -644,7 +644,7 @@ def pair_field(self, ax=None, cmap="gist_rainbow", points='all', add_points=True if used_backend == 'matplotlib': return plotting.matplotlib_pair_field(self, ax=ax, cmap=cmap, points=points, add_points=add_points, alpha=alpha, **kwargs) elif used_backend == 'plotly': - return plotting.plotly_pair_field(self, fig=ax, points=points, add_points=add_points, alpha=alpha, **kwargs) + return plotting.plotly_pair_field(self, fig=ax, points=points, add_points=add_points, alpha=alpha, **kwargs) def _triangle(self, angles, dists): r"""Triangular Search Area diff --git a/skgstat/MetricSpace.py b/skgstat/MetricSpace.py index 2b46abb..a2e37f5 100644 --- a/skgstat/MetricSpace.py +++ b/skgstat/MetricSpace.py @@ -307,7 +307,7 @@ def __init__( self._ltree = None self._rtree = None self._dists = None - # Do a very quick check to see throw exceptions + # Do a very quick check to see throw exceptions # if self.dist_metric is invalid... pdist(self.coords[:1, :], metric=self.dist_metric) @@ -385,7 +385,7 @@ def dists(self): return self._dists -# Subfunctions used in RasterEquidistantMetricSpace +# Subfunctions used in RasterEquidistantMetricSpace # (outside class so that they can be pickled by multiprocessing) def _get_disk_sample( coords: np.ndarray, @@ -407,7 +407,7 @@ def _get_disk_sample( count = np.count_nonzero(idx1) indices1 = np.argwhere(idx1) - # Second index: randomly select half of the valid pixels, + # Second index: randomly select half of the valid pixels, # so that the other half can be used by the equidist # sample for low distances indices2 = rnd_func.choice(count, size=min(count, sample_count), replace=False) diff --git a/skgstat/SpaceTimeVariogram.py b/skgstat/SpaceTimeVariogram.py index c0390e4..87deffd 100644 --- a/skgstat/SpaceTimeVariogram.py +++ b/skgstat/SpaceTimeVariogram.py @@ -337,7 +337,7 @@ def t_lags(self): raise ValueError("Only 'max' supported as string argument.") elif self._t_lags is None: self._t_lags = len(self.tbins) - + return self._t_lags @t_lags.setter diff --git a/skgstat/Variogram.py b/skgstat/Variogram.py index 5fafe46..e63b3cd 100644 --- a/skgstat/Variogram.py +++ b/skgstat/Variogram.py @@ -1737,7 +1737,7 @@ def _format_values_stack(self, values: np.ndarray) -> np.ndarray: """ Create a numpy column stack to calculate differences between two value arrays. The format function will handle sparse matrices, as these do not include - pairwise differences that are separated beyond maxlag. + pairwise differences that are separated beyond maxlag. The dense numpy.array matrices contain all point pairs. """ diff --git a/skgstat/__version__.py b/skgstat/__version__.py index d706e92..bf66ffc 100644 --- a/skgstat/__version__.py +++ b/skgstat/__version__.py @@ -1 +1 @@ -__version__ = '1.0.13' \ No newline at end of file +__version__ = '1.0.13' diff --git a/skgstat/binning.py b/skgstat/binning.py index 26c1305..cc68ca9 100644 --- a/skgstat/binning.py +++ b/skgstat/binning.py @@ -170,7 +170,7 @@ def kmeans(distances, n, maxlag, binning_random_state=42, **kwargs): # filter for distances < maxlag d = distances[np.where(distances <= maxlag)] - # filter the sklearn convervence warning, because working with + # filter the sklearn convervence warning, because working with # undefined state in binning does not make any sense with warnings.catch_warnings(): warnings.filterwarnings('error') @@ -308,7 +308,7 @@ def loss(edges): return np.sum(np.abs(np.diff(h))) # minimize the loss function - opt = dict(maxiter=kwargs.get('binning_maxiter', 5000)) + opt = dict(maxiter=kwargs.get('binning_maxiter', 5000)) res = minimize(loss, initial_guess, method='Nelder-Mead', options=opt) if res.success: diff --git a/skgstat/data/__init__.py b/skgstat/data/__init__.py index d608ad7..1d5bb06 100644 --- a/skgstat/data/__init__.py +++ b/skgstat/data/__init__.py @@ -10,20 +10,20 @@ origins = dict( pancake="""Image of a pancake with apparent spatial structure. - Copyright Mirko Mälicke, 2020. If you use this data cite SciKit-GStat: + Copyright Mirko Mälicke, 2020. If you use this data cite SciKit-GStat: - Mälicke, M.: SciKit-GStat 1.0: a SciPy-flavored geostatistical variogram estimation - toolbox written in Python, Geosci. Model Dev., 15, 2505–2532, + Mälicke, M.: SciKit-GStat 1.0: a SciPy-flavored geostatistical variogram estimation + toolbox written in Python, Geosci. Model Dev., 15, 2505–2532, https://doi.org/10.5194/gmd-15-2505-2022, 2022. """, aniso="""Random field greyscale image with geometric anisotropy. The anisotropy in North-East direction has a factor of 3. The random field was generated using gstools. - Copyright Mirko Mälicke, 2020. If you use this data, cite SciKit-GStat: + Copyright Mirko Mälicke, 2020. If you use this data, cite SciKit-GStat: - Mälicke, M.: SciKit-GStat 1.0: a SciPy-flavored geostatistical variogram estimation - toolbox written in Python, Geosci. Model Dev., 15, 2505–2532, + Mälicke, M.: SciKit-GStat 1.0: a SciPy-flavored geostatistical variogram estimation + toolbox written in Python, Geosci. Model Dev., 15, 2505–2532, https://doi.org/10.5194/gmd-15-2505-2022, 2022. """, @@ -41,14 +41,14 @@ """, corr_var="""Random sample at random locations created using numpy. - The sample can be created for multiple variables, which will be + The sample can be created for multiple variables, which will be cross-correlated. The statistical moment of each variable can be specified as well as the co-variance matrix can be given. IMPORTANT: This data generator is part of SciKit-GStat and is built on Numpy. If you use it, please cite: - Mälicke, M.: SciKit-GStat 1.0: a SciPy-flavored geostatistical variogram estimation - toolbox written in Python, Geosci. Model Dev., 15, 2505–2532, + Mälicke, M.: SciKit-GStat 1.0: a SciPy-flavored geostatistical variogram estimation + toolbox written in Python, Geosci. Model Dev., 15, 2505–2532, https://doi.org/10.5194/gmd-15-2505-2022, 2022. """ @@ -340,7 +340,7 @@ def corr_variable( Returns random cross-correlated variables assigned to random coordinate locations. These can be used for testing cross-variograms, or as a random benchmark for cross-variograms in method development, aka. does - actual correlated data exhibit different cross-variograms of random + actual correlated data exhibit different cross-variograms of random variables of the same correlation coefficient matrix. Parameters @@ -350,20 +350,20 @@ def corr_variable( length has to match size. means : List[float] Mean values of the variables, defaults to two variables with - mean of 1. The number of means determines the number of + mean of 1. The number of means determines the number of variables, which will be returned. vars : List[float] - Univariate variances for each of the random variables. + Univariate variances for each of the random variables. If None, and cov is given, the diagonal of the correlation - coefficient matrix will be used. If cov is None, the + coefficient matrix will be used. If cov is None, the correlation will be random, but the variance will match. If vars is None, random variances will be used. cov : list, float - Co-variance matrix. The co-variances and variances for all + Co-variance matrix. The co-variances and variances for all created random variables can be given directly, as matrix of shape ``(len(means), len(means))``. If cov is a float, the same matrix will be created using the same - co-variance for all combinations. + co-variance for all combinations. coordinates : np.ndarray Coordinates to be used for the sample. If None, random locations are created. @@ -375,13 +375,13 @@ def corr_variable( ------- result : dict Dictionary of the sample and a citation information. - + """ # Handle coordinates if coordinates is None: np.random.seed(seed) coordinates = np.random.normal(10, 5, size=(size, 2)) - + # get the number of variables N = len(means) @@ -390,7 +390,7 @@ def corr_variable( np.random.seed(seed) # use 0...1 ratio of m for variance vars = [np.random.random() * m for m in means] - + # check the cov matrix if cov is None: np.random.seed(seed) @@ -402,16 +402,16 @@ def corr_variable( elif isinstance(cov, (int, float)): cov = np.ones((N, N)) * cov np.fill_diagonal(cov, vars) - + # matrix already elif isinstance(cov, (np.ndarray, list, tuple)) and np.asarray(cov).ndim == 2: # overwrite variances cov = np.asarray(cov) vars = np.diag(cov) - + else: raise ValueError("if cov is given it has to be either one uniform co-variance, or a co-variance matrix.") - + # create the values np.random.seed(seed) values = np.random.multivariate_normal(means, cov, size=size) diff --git a/skgstat/data/samples/README.md b/skgstat/data/samples/README.md index abc72f5..ee8e6c4 100644 --- a/skgstat/data/samples/README.md +++ b/skgstat/data/samples/README.md @@ -8,4 +8,4 @@ Pebesma EJ, Bivand RS (2005). “Classes and methods for spatial data in R.” R News, 5(2), 9–13. https://CRAN.R-project.org/doc/Rnews/. Bivand RS, Pebesma E, Gomez-Rubio V (2013). Applied spatial data - analysis with R, Second edition. Springer, NY. https://asdar-book.org/. \ No newline at end of file + analysis with R, Second edition. Springer, NY. https://asdar-book.org/. diff --git a/skgstat/data/samples/meuse.txt b/skgstat/data/samples/meuse.txt index 59621a1..ee16c08 100644 --- a/skgstat/data/samples/meuse.txt +++ b/skgstat/data/samples/meuse.txt @@ -153,4 +153,4 @@ 179085,330292,3.1,39,173,496,8.577,0.423837,9.1,"3","1","0","Ah",520 178875,330311,2.1,31,119,342,8.429,0.27709,6.5,"3","1","0","Ah",350 179466,330381,0.8,21,51,162,9.406,0.358606,5.7,"3","1","0","W",460 -180627,330190,2.7,27,124,375,8.261,0.0122243,5.5,"3","3","0","W",40 \ No newline at end of file +180627,330190,2.7,27,124,375,8.261,0.0122243,5.5,"3","3","0","W",40 diff --git a/skgstat/interfaces/gstools.py b/skgstat/interfaces/gstools.py index 21eafef..4d9f97b 100644 --- a/skgstat/interfaces/gstools.py +++ b/skgstat/interfaces/gstools.py @@ -80,7 +80,7 @@ def skgstat_to_gstools(variogram, **kwargs): # if Variogram is a cross-variogram warn the user if variogram.is_cross_variogram: - warnings.warn("This instance is a cross-variogram!!" + + warnings.warn("This instance is a cross-variogram!!" + " GSTools.CovModel will most likely not handle this Variogram correctly.") diff --git a/skgstat/interfaces/pykrige.py b/skgstat/interfaces/pykrige.py index 85963b0..bf704b3 100644 --- a/skgstat/interfaces/pykrige.py +++ b/skgstat/interfaces/pykrige.py @@ -61,7 +61,7 @@ def pykrige_params(variogram): if not __check_pykrige_available(): return - # get the parameters into the correct order. + # get the parameters into the correct order. pars = variogram.parameters return [pars[1], pars[0], pars[2]] @@ -74,7 +74,7 @@ def pykrige_as_kwargs(variogram, adjust_maxlag=False, adjust_nlags=False): if not __check_pykrige_available(): return - # as far as I get it, there is no maximum lag in pykrige. + # as far as I get it, there is no maximum lag in pykrige. if adjust_maxlag: variogram.maxlag = None else: diff --git a/skgstat/models.py b/skgstat/models.py index 93447ad..760302d 100644 --- a/skgstat/models.py +++ b/skgstat/models.py @@ -84,7 +84,7 @@ def spherical(h, r, c0, b=0.0): @variogram @jit(nopython=True) -def exponential(h, r, c0, b=0): +def exponential(h, r, c0, b=0.0): r"""Exponential Variogram function Implementation of the exponential variogram function. Calculates the @@ -134,7 +134,7 @@ def exponential(h, r, c0, b=0): .. [8] Chiles, J.P., Delfiner, P. (1999). Geostatistics. Modeling Spatial Uncertainty. Wiley Interscience. - .. [9] Journel, A G, and Huijbregts, C J. Mining geostatistics. + .. [9] Journel, A G, and Huijbregts, C J. Mining geostatistics. United Kingdom: N. p., 1976. """ @@ -146,7 +146,7 @@ def exponential(h, r, c0, b=0): @variogram @jit(nopython=True) -def gaussian(h, r, c0, b=0): +def gaussian(h, r, c0, b=0.0): r""" Gaussian Variogram function Implementation of the Gaussian variogram function. Calculates the @@ -199,7 +199,7 @@ def gaussian(h, r, c0, b=0): .. [10] Chiles, J.P., Delfiner, P. (1999). Geostatistics. Modeling Spatial Uncertainty. Wiley Interscience. - .. [11] Journel, A G, and Huijbregts, C J. Mining geostatistics. + .. [11] Journel, A G, and Huijbregts, C J. Mining geostatistics. United Kingdom: N. p., 1976. """ @@ -211,7 +211,7 @@ def gaussian(h, r, c0, b=0): @variogram @jit(nopython=True) -def cubic(h, r, c0, b=0): +def cubic(h, r, c0, b=0.0): r"""Cubic Variogram function Implementation of the Cubic variogram function. Calculates the @@ -257,7 +257,7 @@ def cubic(h, r, c0, b=0): References ---------- - .. [12] Montero, J.-M., Mateu, J., & others. (2015). Spatial and spatio-temporal + .. [12] Montero, J.-M., Mateu, J., & others. (2015). Spatial and spatio-temporal geostatistical modeling and kriging (Vol. 998). John Wiley & Sons. """ @@ -275,7 +275,7 @@ def cubic(h, r, c0, b=0): @variogram @jit(nopython=True) -def stable(h, r, c0, s, b=0): +def stable(h, r, c0, s, b=0.0): r"""Stable Variogram function Implementation of the stable variogram function. Calculates the @@ -347,7 +347,7 @@ def stable(h, r, c0, s, b=0): @variogram @jit(forceobj=True) -def matern(h, r, c0, s, b=0): +def matern(h, r, c0, s, b=0.0): r"""Matérn Variogram function Implementation of the Matérn variogram function. Calculates the diff --git a/skgstat/plotting/__init__.py b/skgstat/plotting/__init__.py index ebf1e91..7139a4e 100644 --- a/skgstat/plotting/__init__.py +++ b/skgstat/plotting/__init__.py @@ -24,7 +24,7 @@ def backend(name=None): elif name not in ALLOWED_BACKENDS: raise ValueError( - "'%s' is not an allowed plotting backend.\nOptions are: [%s]" % + "'%s' is not an allowed plotting backend.\nOptions are: [%s]" % (name, ','.join(["'%s'" % _ for _ in ALLOWED_BACKENDS])) ) diff --git a/skgstat/plotting/stvariogram_plot3d.py b/skgstat/plotting/stvariogram_plot3d.py index 6cc6a9e..6959947 100644 --- a/skgstat/plotting/stvariogram_plot3d.py +++ b/skgstat/plotting/stvariogram_plot3d.py @@ -131,7 +131,7 @@ def plotly_plot_3d(stvariogram, kind='scatter', fig=None, **kwargs): xaxis_title='space', yaxis_title='time', zaxis_title='semivariance [%s]' % stvariogram.estimator.__name__ - )) + )) # return return fig diff --git a/skgstat/stmodels.py b/skgstat/stmodels.py index a35c796..1e87c60 100644 --- a/skgstat/stmodels.py +++ b/skgstat/stmodels.py @@ -52,8 +52,8 @@ def sum(lags, Vx, Vt): .. math:: \gamma (h,t) = \gamma_x (h) + \gamma_t (t) - - Where :math:`\gamma_x(h)` is the spatial marginal variogram and + + Where :math:`\gamma_x(h)` is the spatial marginal variogram and :math:`\gamma_t(t)` is the temporal marginal variogram. It is not a good idea to use this model in almost any case, as it assumes @@ -113,9 +113,9 @@ def product(lags, Vx, Vt, Cx, Ct): The product sum model is implemented following [14]_: .. math:: - \gamma (h,t) = C_x * \gamma_t(t) + C_t * \gamma_x(h) - \gamma_x(h) * \gamma_t(t) - - Where :math:`\gamma_x(h)` is the spatial marginal variogram and + \gamma (h,t) = C_x * \gamma_t(t) + C_t * \gamma_x(h) - \gamma_x(h) * \gamma_t(t) + + Where :math:`\gamma_x(h)` is the spatial marginal variogram and :math:`\gamma_t(t)` is the temporal marginal variogram. References diff --git a/skgstat/tests/__init__.py b/skgstat/tests/__init__.py index c0ea76b..f3c0cbd 100644 --- a/skgstat/tests/__init__.py +++ b/skgstat/tests/__init__.py @@ -36,4 +36,4 @@ import os os.environ['SKG_SUPRESS'] = 'TRUE' -""" \ No newline at end of file +""" diff --git a/skgstat/tests/test_binning.py b/skgstat/tests/test_binning.py index 66adaec..60507e8 100644 --- a/skgstat/tests/test_binning.py +++ b/skgstat/tests/test_binning.py @@ -134,7 +134,7 @@ def test_kmeans(self): def test_kmeans_convergence(self): with self.assertRaises(ValueError) as err: kmeans(np.array([1, 1, 1, 1, 1]), 3, None) - + self.assertTrue('KMeans failed to converge' in str(err.exception)) def test_ward(self): diff --git a/skgstat/tests/test_cross_utility.py b/skgstat/tests/test_cross_utility.py index 63e30fb..2f35efd 100644 --- a/skgstat/tests/test_cross_utility.py +++ b/skgstat/tests/test_cross_utility.py @@ -19,11 +19,11 @@ def setUp(self) -> None: # set up default values, whenever c and v are not important np.random.seed(42) self.c = np.random.gamma(10, 4, (100, 2)) - + # build the multivariate sample means = [1, 10, 100, 1000] cov = [[1, 0.8, 0.7, 0.6], [0.8, 1, 0.2, 0.2], [0.7, 0.2, 1.0, 0.2], [0.6, 0.2, 0.2, 1.0]] - + np.random.seed(42) self.v = np.random.multivariate_normal(means, cov, size=100) @@ -34,7 +34,7 @@ def test_cross_matrix_shape(self): # check shape mat = np.asarray(mat, dtype='object') self.assertTrue(mat.shape, (4, 4)) - + def test_cross_matrix_diagonal(self): """Test that the primary variograms are correct""" # get the cross variogram matrix diff --git a/skgstat/tests/test_data_loader.py b/skgstat/tests/test_data_loader.py index d0537f4..edc9bdd 100644 --- a/skgstat/tests/test_data_loader.py +++ b/skgstat/tests/test_data_loader.py @@ -89,7 +89,7 @@ def test_corr_var_derirved(): # test uniform covariance cov = np.ones((2, 2)) * 0.8 np.fill_diagonal(cov, vars) - + # generate test sample np.random.seed(42) d = np.random.multivariate_normal([1.0, 10.0], cov, size=50) @@ -102,5 +102,5 @@ def test_corr_var_derirved(): def test_corr_var_matrix_error(): with pytest.raises(ValueError) as e: data.corr_variable(50, [1.0, 2.0], cov='NotAllowed') - + assert 'uniform co-variance, or a co-variance matrix' in str(e.value) diff --git a/skgstat/tests/test_directionalvariogram.py b/skgstat/tests/test_directionalvariogram.py index e1aece2..985ed8b 100644 --- a/skgstat/tests/test_directionalvariogram.py +++ b/skgstat/tests/test_directionalvariogram.py @@ -16,7 +16,7 @@ def setUp(self): def test_standard_settings(self): DV = DirectionalVariogram(self.c, self.v, normalize=True) - + assert_array_almost_equal(DV.describe()["normalized_effective_range"], 436., decimal=0) assert_array_almost_equal(DV.describe()["normalized_sill"], 2706., decimal=0) assert_array_almost_equal(DV.describe()["normalized_nugget"], 0., decimal=0) @@ -77,7 +77,7 @@ def test_invalid_model_type(self): 'model name, or it has to be the search area ' 'itself' ) - + def test_binning_change_nlags(self): DV = DirectionalVariogram(self.c, self.v, n_lags=5) diff --git a/skgstat/tests/test_interfaces.py b/skgstat/tests/test_interfaces.py index 2fe8f70..3fc74cb 100644 --- a/skgstat/tests/test_interfaces.py +++ b/skgstat/tests/test_interfaces.py @@ -93,7 +93,7 @@ def test_find_best_model(self): gs = gs.fit(self.c, self.v) - # Python 3.6 yields 'exponential', + # Python 3.6 yields 'exponential', # while 3.7, 3.8 yield 'gaussian' - this is so stupid self.assertTrue(gs.best_params_['model'] in ['gaussian', 'exponential']) @@ -287,7 +287,7 @@ def test_infer_dims(self): assert_array_almost_equal( model.variogram(self.xi), self.yi, decimal=2 ) - + class TestGstoolsAllModels(unittest.TestCase): def setUp(self): diff --git a/skgstat/tests/test_kriging.py b/skgstat/tests/test_kriging.py index 3b039e5..7419e9f 100644 --- a/skgstat/tests/test_kriging.py +++ b/skgstat/tests/test_kriging.py @@ -33,7 +33,7 @@ def test_coordinates_with_duplicates(self): def test_min_points_type_check(self): with self.assertRaises(ValueError) as e: OrdinaryKriging(self.V, min_points=4.0) - + self.assertEqual( str(e.exception), 'min_points has to be an integer.' ) @@ -41,7 +41,7 @@ def test_min_points_type_check(self): def test_min_points_negative(self): with self.assertRaises(ValueError) as e: OrdinaryKriging(self.V, min_points=-2) - + self.assertEqual( str(e.exception), 'min_points can\'t be negative.' ) @@ -49,7 +49,7 @@ def test_min_points_negative(self): def test_min_points_larger_max_points(self): with self.assertRaises(ValueError) as e: OrdinaryKriging(self.V, min_points=10, max_points=5) - + self.assertEqual( str(e.exception), 'min_points can\'t be larger than max_points.' ) @@ -57,7 +57,7 @@ def test_min_points_larger_max_points(self): def test_max_points_type_check(self): with self.assertRaises(ValueError) as e: OrdinaryKriging(self.V, max_points=16.0) - + self.assertEqual( str(e.exception), 'max_points has to be an integer.' ) @@ -66,7 +66,7 @@ def test_max_points_negative(self): with self.assertRaises(ValueError) as e: ok = OrdinaryKriging(self.V, max_points=10) ok.max_points = - 2 - + self.assertEqual( str(e.exception), 'max_points can\'t be negative.' ) @@ -75,7 +75,7 @@ def test_max_points_smaller_min_points(self): with self.assertRaises(ValueError) as e: ok = OrdinaryKriging(self.V, min_points=3, max_points=5) ok.max_points = 2 - + self.assertEqual( str(e.exception), 'max_points can\'t be smaller than min_points.' ) @@ -94,7 +94,7 @@ def test_mode_settings(self): def test_mode_unknown(self): with self.assertRaises(ValueError) as e: OrdinaryKriging(self.V, mode='foo') - + self.assertEqual( str(e.exception), "mode has to be one of 'exact', 'estimate'." ) @@ -102,7 +102,7 @@ def test_mode_unknown(self): def test_precision_TypeError(self): with self.assertRaises(TypeError) as e: OrdinaryKriging(self.V, precision='5.5') - + self.assertEqual( str(e.exception), 'precision has to be of type int' ) @@ -110,7 +110,7 @@ def test_precision_TypeError(self): def test_precision_ValueError(self): with self.assertRaises(ValueError) as e: OrdinaryKriging(self.V, precision=0) - + self.assertEqual( str(e.exception), 'The precision has be be > 1' ) @@ -118,7 +118,7 @@ def test_precision_ValueError(self): def test_solver_AttributeError(self): with self.assertRaises(AttributeError) as e: OrdinaryKriging(self.V, solver='peter') - + self.assertEqual( str(e.exception), "solver has to be ['inv', 'numpy', 'scipy']" ) diff --git a/skgstat/tests/test_models.py b/skgstat/tests/test_models.py index 6cac237..1d3aa17 100644 --- a/skgstat/tests/test_models.py +++ b/skgstat/tests/test_models.py @@ -153,7 +153,7 @@ def test_matern_nugget(self): for r, m in zip(result, model): self.assertAlmostEqual(r, m, places=2) - + def test_matern_r_switch(self): # run the default with an extreme s value diff --git a/skgstat/tests/test_plotting_backend.py b/skgstat/tests/test_plotting_backend.py index 0bc3b45..3966cc1 100644 --- a/skgstat/tests/test_plotting_backend.py +++ b/skgstat/tests/test_plotting_backend.py @@ -2,7 +2,7 @@ from skgstat.plotting import backend import matplotlib.pyplot as plt -import plotly.graph_objects as go +import plotly.graph_objects as go def test_backend_no_args(): diff --git a/skgstat/tests/test_stmodels.py b/skgstat/tests/test_stmodels.py index 578ca48..202c84c 100644 --- a/skgstat/tests/test_stmodels.py +++ b/skgstat/tests/test_stmodels.py @@ -86,7 +86,7 @@ def setUp(self): def test_default(self): assert_array_almost_equal( - [stmodels.product_sum(h, self.Vx, self.Vt, + [stmodels.product_sum(h, self.Vx, self.Vt, k1=2.2, k2=2.3, k3=4.3, Cx=5, Ct=7) for h in self.lags], [35.55, 101.99, 118.6, 118.6, 113.92, 116.91], decimal=2 @@ -94,7 +94,7 @@ def test_default(self): def test_default_as_array(self): assert_array_almost_equal( - stmodels.product_sum(self.lags, self.Vx, self.Vt, + stmodels.product_sum(self.lags, self.Vx, self.Vt, k1=2.2, k2=2.3, k3=4.3, Cx=5, Ct=7), [35.55, 101.99, 118.6, 118.6, 113.92, 116.91], decimal=2 @@ -102,7 +102,7 @@ def test_default_as_array(self): def test_with_zero_ks(self): assert_array_almost_equal( - stmodels.product_sum(self.lags, self.Vx, self.Vt, + stmodels.product_sum(self.lags, self.Vx, self.Vt, k1=0, k2=0, k3=0, Cx=5, Ct=7), [0., 0., 0., 0., 0., 0.], decimal=2 @@ -110,7 +110,7 @@ def test_with_zero_ks(self): def test_with_all_one(self): assert_array_almost_equal( - stmodels.product_sum(self.lags, self.Vx, self.Vt, + stmodels.product_sum(self.lags, self.Vx, self.Vt, k1=1, k2=1, k3=1, Cx=5, Ct=7), [14.71, 41.13, 47. ,47. ,44.96, 46.61], decimal=2 @@ -118,7 +118,7 @@ def test_with_all_one(self): def test_as_product_model(self): assert_array_almost_equal( - stmodels.product_sum(self.lags, self.Vx, self.Vt, + stmodels.product_sum(self.lags, self.Vx, self.Vt, k1=1, k2=0, k3=0, Cx=5, Ct=7), stmodels.product(self.lags, self.Vx, self.Vt, 5, 7), decimal=2 diff --git a/skgstat/tests/test_util.py b/skgstat/tests/test_util.py index 27cea6a..c6bb454 100644 --- a/skgstat/tests/test_util.py +++ b/skgstat/tests/test_util.py @@ -117,4 +117,4 @@ def test_propagate_many_targets(): # unstack the list conf_exp, conf_par = conf_list assert conf_exp.shape == (12, 3) - assert conf_par.shape == (3, 3) \ No newline at end of file + assert conf_par.shape == (3, 3) diff --git a/skgstat/tests/test_variogram.py b/skgstat/tests/test_variogram.py index 52ce572..3c8e9e8 100644 --- a/skgstat/tests/test_variogram.py +++ b/skgstat/tests/test_variogram.py @@ -25,12 +25,12 @@ class TestSpatiallyCorrelatedData(unittest.TestCase): def setUp(self): # Generate some random but spatially correlated data # with a range of ~20 - + np.random.seed(42) c = np.random.sample((50, 2)) * 60 np.random.seed(42) v = np.random.normal(10, 4, 50) - + V = Variogram(c, v).describe() V["effective_range"] = 20 OK = OrdinaryKriging(V, coordinates=c, values=v) @@ -47,13 +47,13 @@ def test_dense_maxlag_inf(self): for x, y in zip(Vdense.parameters, Vsparse.parameters): self.assertAlmostEqual(x, y, places=3) - + def test_sparse_maxlag_50(self): V = Variogram(self.c, self.v, maxlag=50) for x, y in zip(V.parameters, [20.264, 6.478, 0]): self.assertAlmostEqual(x, y, places=3) - + def test_sparse_maxlag_30(self): V = Variogram(self.c, self.v, maxlag=30) @@ -168,7 +168,7 @@ def test_value_error_on_set_trf(self): v.fit_method = 'trf' self.assertTrue("'trf' is bounded and therefore" in str(e.exception)) - + def test_value_error_trf(self): """Test the Attribute error on TRF instantiation on single value input""" # catch the same input value warning @@ -192,7 +192,7 @@ def test_pairwise_diffs(self): diff = pdist(np.column_stack((self.v, np.zeros(len(self.v)))), metric='euclidean') assert_array_almost_equal(V.pairwise_diffs, diff, decimal=2) - + def test_pairwise_diffs_preprocessing(self): """ Remove the diffs and then request the diffs again to check preprocessing @@ -424,7 +424,7 @@ def test_unknown_dist_func(self): with self.assertRaises(ValueError) as e: V.set_dist_function('notadistance') - + self.assertEqual( str(e.exception), 'Unknown Distance Metric: notadistance' @@ -435,7 +435,7 @@ def test_wrong_dist_func_input(self): with self.assertRaises(ValueError) as e: V.set_dist_function(55) - + self.assertEqual( str(e.exception), 'Input not supported. Pass a string or callable.' @@ -463,7 +463,7 @@ def disabled_test_direct_dist_setting(): # Distance can no longer be explicitly set # it would require setting the whole MetricSpace, with a # non-sparse diagonal matrix - + V = Variogram([(0, 0), (4, 1), (1, 1)], [1, 2, 3], n_lags=2) V.distance = np.array([0, 0, 100]) @@ -689,7 +689,7 @@ def test_fit_sigma_raises_AttributeError(self): with self.assertRaises(AttributeError) as e: self.V.fit_sigma - + self.assertTrue( 'len(fit_sigma)' in str(e.exception) ) @@ -901,7 +901,7 @@ def test_manual_fit(self): ) self.assertEqual(V.parameters, [10., 5., 0.0]) - + def test_manual_fit_change(self): V = Variogram( self.c, @@ -937,7 +937,7 @@ def test_manual_preserve_params(self): params, decimal=1 ) - + def test_implicit_nugget(self): V = Variogram(self.c, self.v, use_nugget=False) @@ -1007,7 +1007,7 @@ def test_r(self): V = Variogram(self.c, self.v, n_lags=12, normalize=False) for model, r in zip( - ('gaussian', 'exponential', 'stable'), + ('gaussian', 'exponential', 'stable'), [0.39, 0.55, 0.60] ): V.set_model(model) @@ -1021,7 +1021,7 @@ def test_NS(self): [0.0206, 0.0206, 0.0206] ): self.assertAlmostEqual(V.NS, NS, places=4) - + def test_mae(self): V = Variogram(self.c, self.v, n_lags=15) @@ -1087,7 +1087,7 @@ def test_get_empirical(self): # test assert_array_almost_equal(bins, emp_x) assert_array_almost_equal(exp, emp_y) - + def test_get_empirical_center(self): V = Variogram(self.c, self.v) @@ -1110,7 +1110,7 @@ def test_data_no_force(self): assert_array_almost_equal( lags, - [0., 4.7, 9.4, 14.1, 18.8, 23.5, 28.2, 32.9, 37.6, 42.3], + [0., 4.7, 9.4, 14.1, 18.8, 23.5, 28.2, 32.9, 37.6, 42.3], decimal=2 ) @@ -1124,7 +1124,7 @@ def disabled_test_data_with_force(self): # Distance can no longer be explicitly set # it would require setting the whole MetricSpace, with a # non-sparse diagonal matrix - + # should work if _dist is corccupted self.V._dist = self.V._dist * 5. self.V.cof = None @@ -1160,15 +1160,15 @@ def test_data_normalized(self): [0., 13.97, 13.97, 13.97, 13.97], decimal=2 ) - + def test_parameter_property_matern(self): V = self.V.clone() - + # test matern param = [42.3, 16.2, 0.1, 0.] V.set_model('matern') assert_array_almost_equal(V.parameters, param, decimal=2) - + def test_parameter_property_stable(self): V = self.V.clone() @@ -1230,7 +1230,7 @@ def test_plotly_dd_plot(self): ) plotting.backend('matplotlib') - + def test_undefined_backend(self): # force the backend into an undefined state import skgstat @@ -1244,7 +1244,7 @@ def test_undefined_backend(self): str(e.exception), 'The plotting backend has an undefined state.' ) - + # make the backend valid again skgstat.__backend__ = 'matplotlib' @@ -1279,7 +1279,7 @@ def test_samples(self): self.data[['x', 'y']].values, self.data.z.values, samples=sample_size, binning_random_state=44).describe() - + self.assertAlmostEqual(Vf["normalized_effective_range"], Vs["normalized_effective_range"], delta = Vf["normalized_effective_range"] / 5) self.assertAlmostEqual(Vf["effective_range"], Vs["effective_range"], delta = Vf["effective_range"] / 5) self.assertAlmostEqual(Vf["sill"], Vs["sill"], delta = Vf["sill"] / 5) @@ -1376,7 +1376,7 @@ def test_cross_variogram_warns(self): with self.assertWarns(Warning) as w: vario.to_gstools() - + self.assertTrue("This instance is a cross-variogram!!" in str(w.warning)) diff --git a/skgstat/util/__init__.py b/skgstat/util/__init__.py index 962c3e7..0e1cbde 100644 --- a/skgstat/util/__init__.py +++ b/skgstat/util/__init__.py @@ -1 +1 @@ -from .shannon import shannon_entropy \ No newline at end of file +from .shannon import shannon_entropy diff --git a/skgstat/util/cross_variogram.py b/skgstat/util/cross_variogram.py index 85d6d5d..d235287 100644 --- a/skgstat/util/cross_variogram.py +++ b/skgstat/util/cross_variogram.py @@ -20,7 +20,7 @@ def cross_variograms(coordinates: np.ndarray, values: np.ndarray, **kwargs) -> L The diagonal of the *'matrix'* holds primary variograms (without cross option) for the respective column. The function accepts all keyword arguments that are also accepted by - :class:`Variogram ` and + :class:`Variogram ` and :class:`DirectionalVariogram ` and passes them down to the respective function. The directional variogram will be used as base class if any of the specific arguments are present: azimuth, bandwidth diff --git a/skgstat/util/likelihood.py b/skgstat/util/likelihood.py index 42b9095..ed71c24 100644 --- a/skgstat/util/likelihood.py +++ b/skgstat/util/likelihood.py @@ -4,8 +4,8 @@ References ---------- -[601] Lark, R. M. "Estimating variograms of soil properties by the - method‐of‐moments and maximum likelihood." European Journal +[601] Lark, R. M. "Estimating variograms of soil properties by the + method‐of‐moments and maximum likelihood." European Journal of Soil Science 51.4 (2000): 717-728. """ from typing import Callable, List @@ -35,8 +35,8 @@ References ---------- -[601] Lark, R. M. "Estimating variograms of soil properties by the - method‐of‐moments and maximum likelihood." European Journal +[601] Lark, R. M. "Estimating variograms of soil properties by the + method‐of‐moments and maximum likelihood." European Journal of Soil Science 51.4 (2000): 717-728. """ diff --git a/skgstat/util/shannon.py b/skgstat/util/shannon.py index bdc1d2c..432b11a 100644 --- a/skgstat/util/shannon.py +++ b/skgstat/util/shannon.py @@ -18,7 +18,7 @@ def shannon_entropy(x, bins): bins : list, int upper edges of the bins used to calculate the histogram of x. - + Returns ------- h : float diff --git a/tutorials/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json b/tutorials/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json index 5d6346a..56d8ebc 100644 --- a/tutorials/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json +++ b/tutorials/tereno_fendt/meta_data_CosmicSense_JFC1_DE-Fen_SNdata.json @@ -5,14 +5,14 @@ "Info": "These files are part of the dataset published with the data-paper mentioned below.", "cite-as": "Fersch, B., Francke, T., Heistermann, M., Schrön, M., Döpper, V., Jakobi, J. et. al (2020): A dense network of cosmic-ray neutron sensors for soilmoisture observation in a highly instrumented pre-alpine headwater catchment in Germany. Earth System Science Data. https://doi.org/10.5194/essd-2020-48" }, - + "Provider": { "Name": "Benjamin Fersch", "Institution": "KIT Campus Alpin", "Email": "fersch@kit.edu", - "Comment": "" + "Comment": "" }, - + "SpaceTimeCoverage": { "StartDate": "2019-05-01", "EndDate": "2019-07-31", @@ -23,14 +23,14 @@ "Elevation": "595 m ASL", "Weblink": "https://geoportal.bayern.de/bayernatlas/?zoom=15&lang=de&topic=ba&bgLayer=atkis&E=654197&N=5299736&catalogNodes=122,11&layers=luftbild&crosshair=marker" }, - + "Source": { "Name": "Benjamin Fersch", "Institution": "KIT Campus Alpin", "LinkToOriginalSource": "https://www.imk-ifu.kit.edu/tereno.php" }, - - + + "Variables": { "time": "time of measurement", "lat": "profile latitude coordinate", @@ -45,7 +45,7 @@ "T_a": "soil temperature (sensor group a)", "T_b": "soil temperature (sensor group b)" }, - + "Units": { "time": "minutes since 2019-05-01 00:00:00", "lat": "degree north", @@ -60,20 +60,20 @@ "T_a": "degree Celsius", "T_b": "degree Celsius" }, - + "SpatialReferenceSystem": { "Name": "WGS 84", - "EPSG": "4326" + "EPSG": "4326" }, - - + + "TemporalReferenceSystem": { "TimeZone": "UTC", "IntervalLength": "15 minutes", "IntervalAggregation": "instantaneous", "TimestampAtEndOfInterval": "FALSE" }, - + "Remarks": "Each profile is equipped with 2 redundant sensors (a, and b)\n Metadata also contained in NetCDF header." } - \ No newline at end of file + diff --git a/tutorials/tereno_fendt/tereno.json b/tutorials/tereno_fendt/tereno.json index cc816e7..c366180 100644 --- a/tutorials/tereno_fendt/tereno.json +++ b/tutorials/tereno_fendt/tereno.json @@ -17754,4 +17754,4 @@ ] ], "description": "Data derived from Fersch et al. (2020) https://doi.org/10.5194/essd-2020-48. Published under CC BY 4.0.\n It is From the WSN product, the T_a in 20cm depth is extracted" -} \ No newline at end of file +}