diff --git a/README.rst b/README.rst index 506d3d594..84ce12254 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -.. image:: https://www.giotto.ai/static/vector/logo-tda.svg +.. image:: doc/images/tda_logo.svg :width: 850 |Version|_ |Azure-build|_ |Azure-cov|_ |Azure-test|_ |Twitter-follow|_ |Slack-join|_ @@ -25,38 +25,32 @@ giotto-tda ========== -giotto-tda is a high performance topological machine learning toolbox in Python built on top of -scikit-learn and is distributed under the GNU AGPLv3 license. It is part of the `Giotto `_ family of open-source projects. +``giotto-tda`` is a high-performance topological machine learning toolbox in Python built on top of +``scikit-learn`` and is distributed under the GNU AGPLv3 license. It is part of the `Giotto `_ +family of open-source projects. Project genesis =============== -giotto-tda is the result of a collaborative effort between `L2F SA -`_, the `Laboratory for Topology and Neuroscience -`_ at EPFL, and the `Institute of Reconfigurable & Embedded Digital Systems (REDS) -`_ of HEIG-VD. +``giotto-tda`` is the result of a collaborative effort between `L2F SA `_, +the `Laboratory for Topology and Neuroscience `_ at EPFL, +and the `Institute of Reconfigurable & Embedded Digital Systems (REDS) `_ of HEIG-VD. License ======= - -giotto-tda is distributed under the AGPLv3 `license `_. -If you need a different distribution license, please contact the L2F team at -business@l2f.ch. +.. _L2F team: business@l2f.ch +``giotto-tda`` is distributed under the AGPLv3 `license `_. +If you need a different distribution license, please contact the `L2F team`_. Documentation ============= -Please visit https://giotto-ai.github.io/gtda-docs and navigate to the version you are interested in. - -Getting started -=============== +Please visit `https://giotto-ai.github.io/gtda-docs `_ and navigate to the version you are interested in. -To get started with giotto-tda, first follow the installations steps below. `This blog post `_, and references therein, offer a friendly introduction to the topic of topological machine learning and to the philosophy behind giotto-tda. - -Tutorials and use cases ------------------------ +Use cases +========= -Simple tutorials can be found in the `examples `_ folder. For a wide selection of use cases and application domains, you can visit `this page `_. +For a wide selection of use cases and application domains, you can visit `this page `_. Installation ============ @@ -64,7 +58,7 @@ Installation Dependencies ------------ -The latest stable version of giotto-tda requires: +The latest stable version of ``giotto-tda`` requires: - Python (>= 3.6) - NumPy (>= 1.17.0) @@ -81,7 +75,7 @@ To run the examples, jupyter is required. User installation ----------------- -The simplest way to install giotto-tda is using ``pip`` :: +The simplest way to install ``giotto-tda`` is using ``pip`` :: pip install -U giotto-tda @@ -93,12 +87,18 @@ bug fixes can be installed by running :: pip install -U giotto-tda-nightly -The main difference between giotto-tda-nightly and the developer installation (see the section +The main difference between ``giotto-tda-nightly`` and the developer installation (see the section on contributing, below) is that the former is shipped with pre-compiled wheels (similarly to the stable release) and hence does not require any C++ dependencies. As the main library module is called ``gtda`` in -both the stable and nightly versions, giotto-tda and giotto-tda-nightly should not be installed in +both the stable and nightly versions, ``giotto-tda`` and ``giotto-tda-nightly`` should not be installed in the same environment. +Developer installation +---------------------- + +Please consult the `relevant page `_ +for detailed instructions on how to build ``giotto-tda`` from sources across different platforms. + .. _contributing-section: Contributing @@ -106,73 +106,8 @@ Contributing We welcome new contributors of all experience levels. The Giotto community goals are to be helpful, welcoming, and effective. To learn more about -making a contribution to giotto-tda, please see the `CONTRIBUTING.rst -`_ file. - -Developer installation ----------------------- - -Installing both the PyPI release and source of giotto-tda in the same environment is not recommended since it is -known to cause conflicts with the C++ bindings. - -The developer installation requires three important C++ dependencies: - -- A C++14 compatible compiler -- CMake >= 3.9 -- Boost >= 1.56 - -Please refer to your system's instructions and to the `CMake `_ and -`Boost `_ websites for definitive guidance on how to install these dependencies. The instructions below are unofficial, please follow them at your own risk. - -Linux -~~~~~ - -Most Linux systems should come with a suitable compiler pre-installed. For the other two dependencies, you may consider using your distribution's package manager, e.g. by running - -.. code-block:: bash - - sudo apt-get install cmake libboost-dev - -if ``apt-get`` is available in your system. - -macOS -~~~~~ - -On macOS, you may consider using ``brew`` (https://brew.sh/) to install the dependencies as follows: - -.. code-block:: bash - - brew install gcc cmake boost - -Windows -~~~~~~~ - -On Windows, you will likely need to have `Visual Studio `_ installed. At present, -it appears to be important to have a recent version of the VS C++ compiler. One way to check whether this is the case -is as follows: 1) open the VS Installer GUI; 2) under the "Installed" tab, click on "Modify" in the relevant VS -version; 3) in the newly opened window, select "Individual components" and ensure that v14.24 or above of the MSVC -"C++ x64/x86 build tools" is selected. The CMake and Boost dependencies are best installed using the latest binary -executables from the websites of the respective projects. - - -Source code -~~~~~~~~~~~ - -You can obtain the latest state of the source code with the command:: - - git clone https://github.com/giotto-ai/giotto-tda.git - - -To install: -~~~~~~~~~~~ - -.. code-block:: bash - - cd giotto-tda - python -m pip install -e ".[dev]" - -This way, you can pull the library's latest changes and make them immediately available on your machine. -Note: we recommend upgrading ``pip`` and ``setuptools`` to recent versions before installing in this way. +making a contribution to ``giotto-tda``, please consult the `relevant page +`_. Testing ------- @@ -182,13 +117,6 @@ source directory:: pytest gtda - -Changelog -========= - -See the `RELEASE.rst `__ file -for a history of notable changes to giotto-tda. - Important links --------------- diff --git a/doc/Makefile b/doc/Makefile index 86ed375ed..ce472f77e 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -6,7 +6,7 @@ ########## Config ifndef GITDIR -GITDIR = ../../../projects/gtda-docs +GITDIR = ../../gtda-docs endif ifndef VERSION diff --git a/doc/conf.py b/doc/conf.py index e5707081e..c8eccd985 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -23,7 +23,7 @@ project = 'giotto-tda' copyright = '2020, L2F' author = 'Guillaume Tauzin, Umberto Lupo, Matteo Caorsi, Anibal Medina, ' \ - 'Lewis Tunstall' + 'Lewis Tunstall, Wojciech Reise' # The full version, including alpha/beta/rc tags release = __version__ @@ -107,7 +107,6 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -# html_theme = "sphinx_rtd_theme" html_theme_options = { @@ -122,17 +121,15 @@ with open('versions', 'r') as f: _versions = [c[2:] for c in f.read().splitlines()] _versions = list(filter(lambda c: not(c.startswith('.')), _versions)) -html_theme_options.update({'versions': [(c, f'../{c}/index.html') - for c in set(_versions).union([current_version])]}) +html_theme_options.update({ + 'versions': [ + (c, f'../{c}/index.html') + for c in set(_versions).union([current_version]) + ] +}) # Get logo -path_to_image = "images/tda_logo.svg" -if not(os.path.exists(path_to_image)): - import requests - r = requests.get('https://www.giotto.ai/static/vector/logo-tda.svg') - with open(path_to_image, 'wb') as f: - f.write(r.content) -html_logo = path_to_image +html_logo = "images/tda_logo.svg" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -145,4 +142,4 @@ .. |ProjectVersion| replace:: Foo Project, version {versionnum} """.format( versionnum=release, -) \ No newline at end of file +) diff --git a/doc/contributing/index.rst b/doc/contributing/index.rst index cc259a48a..58ff4f748 100644 --- a/doc/contributing/index.rst +++ b/doc/contributing/index.rst @@ -18,47 +18,49 @@ This page contains a summary of what one needs to do to contribute. Guidelines ********** -Pull Request Checklist -====================== +Essentials for contributing +=========================== -Before sending your pull requests, make sure you followed this list. - - Read the `contributing guidelines `_. - - Read the `code of conduct `_. - - Ensure you have signed the `contributor license agreement (CLA) `_. - - Check if the changes are consistent with the guidelines. - - Changes are consistent with the Coding Style. - - Run Unit Tests. +Contributor License Agreement +----------------------------- -How to become a contributor and submit your own code -==================================================== - -Contributor License Agreements ------------------------------- - -In order to become a contributor of giotto-tda, the first step is to sign the +In order to become a contributor of ``giotto-tda``, the first step is to sign the `contributor license agreement (CLA) `_. **NOTE**: Only original source code from you and other people that have signed the CLA can be accepted into the main repository. -Contributing code ------------------ - -If you have improvements to giotto-tda, do not hesitate to send us pull requests! -Please follow the Github how to (https://help.github.com/articles/using-pull-requests/). -The giotto-tda team will review your pull requests. Once the pull requests are approved and pass continuous integration checks, the -giotto-tda team will work on getting your pull request submitted to our GitHub -repository. Eventually, your pull request will be merged automatically on GitHub. -If you want to contribute, start working through the giotto-tda codebase, -navigate to the `GitHub issue tab `_ -and start looking through interesting issues. These are issues that we believe -are particularly well suited for outside contributions, often because we -probably won't get to them right now. If you decide to start on an issue, leave -a comment so that other people know that you're working on it. If you want to -help out, but not alone, use the issue comment thread to coordinate. +Pull requests +------------- + +If you have improvements to ``giotto-tda``, do not hesitate to send us pull requests! +Please follow the `Github how to `_ and +make sure you followed this checklist *before* submitting yor pull request: + +- Make sure you have signed the `contributor license agreement (CLA) `_. +- Read the :ref:`Contribution guidelines and standards `. +- Read the `code of conduct `_. +- Check that the changes are consistent with the guidelines and coding styles. +- Run unit tests. + +The ``giotto-tda`` team will review your pull requests. Once the pull requests are approved +and pass continuous integration checks, the ``giotto-tda`` team will work on getting your pull +request submitted to our GitHub repository. Eventually, your pull request will be merged +automatically on GitHub. + +Issues +------ + +If you would like to know how you can contribute to the ``giotto-tda`` codebase, we recommend +that you navigate to the `GitHub issue tab `_ +and start looking through interesting issues. If you decide to start working on an issue, leave +a comment so that other people know that you're working on it. If you want to help out, but not +alone, use the issue comment thread to coordinate. Contribution guidelines and standards ===================================== +.. _contribution_guidelines_standards: + Before sending your pull request for review, make sure your changes are consistent with the guidelines and follow the coding style below. @@ -70,26 +72,24 @@ General guidelines and philosophy for contribution b) guard against future breaking changes to lower the maintenance cost. * Bug fixes also generally require unit tests, because the presence of bugs usually indicates insufficient test coverage. -* Keep API compatibility in mind when you change code in core giotto-tda. +* Keep API compatibility in mind when you change code in core ``giotto-tda``. * Clearly define your exceptions using the utils functions and test the exceptions. -* When you contribute a new feature to giotto-tda, the maintenance burden is    - (by default) transferred to the giotto-tda team. This means that the benefit    - of the contribution must be compared against the cost of maintaining the    - feature. +* When you contribute a new feature to ``giotto-tda``, the maintenance burden is    + (by default) transferred to the ``giotto-tda`` team. This means that the benefit    + of the contribution must be compared against the cost of maintaining the feature. C++ coding style ---------------- -Changes to giotto-tda's C/C++ code should conform to `Google C++ Style Guide `_. -Use `clang-tidy` to check your C/C++ changes. To install `clang-tidy` on -ubuntu:16.04, do: +Changes to ``giotto-tda``'s C/C++ code should conform to `Google C++ Style Guide `_. +Use ``clang-tidy`` to check your C/C++ changes. As an example, to install ``clang-tidy`` on Ubuntu 16.04, do: .. code-block:: bash apt-get install -y clang-tidy -You can check a C/C++ file by doing: +You can check a C/C++ file by running: .. code-block:: bash @@ -98,14 +98,15 @@ You can check a C/C++ file by doing: Python coding style ------------------- -Changes to giotto-tda's Python code should conform to PEP8 directives. -Use `flake8` to check your Python changes. To install `flake8` just do +Whenever possible, changes to ``giotto-tda``'s Python code should conform to +`PEP8 `_ directives. Use ``flake8`` to check your Python +changes. To install ``flake8`` just do .. code-block:: python pip install flake8 -You can use `flake8` on your python code via the following instructions: +You can use ``flake8`` on your python code via the following instructions: .. code-block:: python @@ -123,140 +124,19 @@ We provide a pre-commit git hook to prevent accidental commits to the master bra Running unit tests ------------------ -There are two ways to run unit tests for giotto-tda. +There are two ways to run unit tests for ``giotto-tda``. -1. Using tools and libraries installed directly on your system. The election tool is `pytest`. To install `pytest` just do +1. Using tools and libraries installed directly on your system. ``giotto-tda`` relies on ``pytest``. + To install ``pytest`` just run .. code-block:: python pip install pytest -You can use `pytest` on your python code via the following instructions: +You can use ``pytest`` on your python code via the following instructions: .. code-block:: python pytest name_of_your_script.py -2. Using Azure (azure-pipelines.yml) and giotto-tda's CI scripts. - - -************* -Documentation -************* - -Description of the infrastructure -================================= - -The documentation is hosted on github-pages (on `https://giotto-ai.github.io/gtda-docs/ `_). -It has 3 main components: - -- API: auto-generated python documentation (sphinx), -- contribution guidelines, README, theory page etc, -- collection of notebook examples (from ../examples, converted to `.py` scripts and executed). - -All of the 3 components are `html` pages, generated as described in :ref:`How to build `. -The generated pages have to be committed to a local clone of the -`github repository containing the documentation `_, -which also contains documentation for previous versions of the project. - -Generating documentation has been automated and is now part of the Azure CI. Each merge to master generates a new documentation. - -How to build -============ - -.. _build_docs: - -Basic instructions ------------------- - -Create an environment using the ???? file and activate it. We assume that the `giotto-tda` and `gtda-docs` repositories -are cloned in `/path/to/giotto-tda/` and `path/to/gtda-docs/`. - -.. code-block:: bash - - cd path/to/giotto-tda/ - cd doc/ - -Set the environment variable `GITDIR` to `path/to/gtda-docs/`, either directly in the console or editing the `Makefile`: - -.. code-block:: bash - - GITDIR = path/to/gtda-docs/ - -Then, generating the documentation, copying it to the `gtda-docs` repository and committing is done with: - -.. code-block:: bash - - make all_gh - make gh-commit - -Note that the success of the `gh-commit` target depends on whether you have writing rights to the `gtda-docs` repository. - -Step-by-step instructions -------------------------- - -We describe in more details the targets in the Makefile, following the flow described above. - -Clean -~~~~~ - -The `all-gh` target starts with `clean-gh`` which uses the underlying sphinx `clean` target to remove files from the `build` directory. -Similarly, we remove `theory/glossary.rst`, which might have been geenerated by a previous call to `make all-gh`. - -Theory -~~~~~~ - -**This step requires `pandoc` and `pandoc-citeproc` as additional dependencies.** - -The glossary `theory/glossary.tex` contains the mathematical definitions of the functionalities -and the terms used throughout the documentation. - -The document, along with the bibliography, is converted to an `.rst`, using `pandoc`. -It is included in the main `toctree` of the documentation. -The only purpose and use of `theory/before_glossary.rst` is to have the reference/hyperlink. - -Notebooks -~~~~~~~~~ - -The documentation contains notebooks from `../examples`. They are included as `.rst` files in the `notebooks` directory, -where they are grouped under two categories: `basic` (for quickstarts) and `advanced` (for synthetic examples with some basic analysis). -which record the output. - -The workflow with copying the notebooks to `notebooks/`, along with helper functions. Executing them and converting to `.rst with `jupyter nbconvert` -follows in `convert-notebooks`. - -It is important to stress that since this step takes a long time, and, for small changes tested locally (without deploying), -we offer the possibility of building the documentation without this step. -To include notebooks in the documentation, set `RUNNOTEBOOKS=TRUE`. This is the default option in the Azure CI. Also, note that building the documentation will probably fail -if the `.rst` files for notebooks are not present. - -Html -~~~~ - -**This step requires `wreise/sphinx_rtd_theme `_ as an additional dependency.** -**Please make sure to uninstall the `sphinx_rtd_theme`, part of the default developer installation of `giotto-tda`.** - -This is the step where `Sphinx` is actually used. -We use the standard `make html` command, which also takes the configuration from `conf.py`. -In particular, we use `a fork of the sphinx-rtd-theme `_. -For details, please see the documentation of `Sphinx` and the extensions listed in `conf.py`. - -Versions -~~~~~~~~ - -Multiple versions of the documentation are available, in a *ReadTheDocs-style* menu. Technically, to achieve this, -we detect the folders present in the `gtda-docs` repository and add -the currently-built version - either a new folder, or replace entirely the content of the existing folder with the same version name. -It is easy to build the documentation with the new list of versions, and redirect from that version to the previously-existing ones. -Redirecting to other versions from **previous** versions is achieved by updating the sections of all `*.html` files, using the `update_versions.py` script. - -Move to git and commit -~~~~~~~~~~~~~~~~~~~~~~ - -Sphinx generates the documentation in the `build` directory. We copy the contents of `build/html/` to `path/to/gtda_docs/$(VERSION)`, -where $(VERSION) is an environment variable (set in the `Makefile`) which dictates the name/tag of the version that we are building. -When opening the page, the user is redirected to the documentation of the latest stable version, -but the documentation for previous versions can still be accessed and is kept for backwards compatibility. - -All the changes in the `gtda-docs` repo are staged and committed. A push is tried and requires a password. -It can only succeed if the user has write access to that repository. \ No newline at end of file +2. Using Azure and ``giotto-tda``'s `CI scripts `_. \ No newline at end of file diff --git a/doc/faq.rst b/doc/faq.rst index 923448734..a27285501 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -3,47 +3,27 @@ FAQ === -How to cite? ------------- - -Cite the paper! - -.. code-block:: latex - - @inproceedings{whatever_2014, - address = {Moon}, - series = {{ABC}'14}, - title = {A fancy paper}, - isbn = {978-1-4503-2594-3}, - url = {https://doi.org/10.123/abs}, - doi = {123.12345}, - booktitle = {A fancy book}, - publisher = {Association for Computing Machinery}, - author = {Author, Well-Known}, - month = jun, - year = {2014}, - keywords = {giotto}, - pages = {-1-4} - } - - -I am a researcher. Can I use the giotto-tda in my project? +I am a researcher. Can I use ``giotto-tda`` in my project? ---------------------------------------------------------- +.. _L2F team: business@l2f.ch -Of course, the license is very permissive. For more information, please contact the L2F team at -business@l2f.ch. +Of course! The `license `_ is very permissive. +For more information, please contact the `L2F team`_. -I cannot install `giotto-tda` on Windows. ------------------------------------------ +I cannot install ``giotto-tda`` +------------------------------- -We are trying our best to support a variety of most-used operating systems. -If you experience any trouble, it is likely that others already have and reported it. +We are trying our best to support a variety of widely-used operating systems. Please navigate to +:ref:`Installation ` and review the steps outlined there. Take care of the differences +between a simple user installation and a more involved developer installation from sources. +If you still experience issues, it is possible others also have encountered and reported them. Please consult the list of `issues `_, including the closed ones, and open a new one in case you did not find help. -There are many TDA-libraries available. How is `giotto-tda` different? ----------------------------------------------------------------------- +There are many TDA libraries available. How is ``giotto-tda`` different? +------------------------------------------------------------------------ -Giotto-tda is oriented towards machine learning (for details, see the :ref:`guiding principles `). -This philosophy is in contrast with other reference librairies, like `GUDHI `_, -which provide more functionality, at the expense of being less adapted to, f.ex. batch processing, or having no unified API. \ No newline at end of file +``giotto-tda`` is oriented towards machine learning (for details, see the :ref:`guiding principles `). +This philosophy is in contrast with other reference libraries, like `GUDHI `_, +which provide more low-level functionality at the expense of being less adapted to e.g. batch processing, or of +being tightly integrated with ``scikit-learn``. \ No newline at end of file diff --git a/doc/library.rst b/doc/library.rst index 1a326ef65..924c4db61 100644 --- a/doc/library.rst +++ b/doc/library.rst @@ -3,12 +3,10 @@ Overview ######## -**A high performance topological machine learning toolbox in Python.** +**A high-performance topological machine learning toolbox in Python** -Giotto-tda is a high performance topological machine learning toolbox in Python built on top of -scikit-learn and is distributed under the GNU AGPLv3 license. It is part of the `Giotto `_ family of open-source projects. - -**Read our paper on arXiv!** +``giotto-tda`` is a high performance topological machine learning toolbox in Python built on top of +``scikit-learn`` and is distributed under the GNU AGPLv3 license. It is part of the `Giotto `_ family of open-source projects. .. _guiding_principles: @@ -16,83 +14,99 @@ scikit-learn and is distributed under the GNU AGPLv3 license. It is part of the Guiding principles ****************** - * | **Seamless integration with widely used ML frameworks: Python + scikit-learn.** - | Inherit their strengths and allow for creation of heterogeneous ML pipelines. - * | **Code modularity: Algorithms as transformers.** - | “Lego blocks” approach. - * | **User-friendliness and familiarity to the broad data science community.** - | Strict adherence to scikit-learn API and developer guidelines, “fit-transform” paradigm - * | **Standardisation.** - | Allow for integration of most available techniques into a generic framework. Consistency of API across different modules - * | **Performance within the language constraints.** - | Vectorized code, parallelism (likely in future: just-in-time compilation and more) - * | **Data structures.** - | Support for time series, graphs, images. - -*********************** -30s guide to Giotto-TDA -*********************** + * | **Seamless integration with** ``scikit-learn`` + | Strictly adhere to the ``scikit-learn`` API and development guidelines, inherit the strengths of that framework. + * | **Code modularity** + | Topological feature creation steps as transformers. Allow for the creation of a large number of topologically-powered machine learning pipelines. + * | **Standardisation** + | Implement the most successful techniques from the literature into a generic framework with a consistent API. + * | **Innovation** + | Improve on existing algorithms, and make new ones available in open source. + * | **Performance** + | For the most demanding computations, fall back to state-of-the-art C++ implementations, bound efficiently to Python. Vectorized code and implements multi-core parallelism (with ``joblib``). + * | **Data structures** + | Support for **tabular data**, **time series**, **graphs**, and **images**. + +*************************** +30s guide to ``giotto-tda`` +*************************** For installation instructions, see :ref:`the installation instructions `. -The functionalities of Giotto-TDA are provided in `scikit-learn`-style transformers. -This allows you to jump in the familiar way of generating features from your data. Here is an example of `VietorisRipsPersistence`, +The functionalities of ``giotto-tda`` are provided in ``scikit-learn``–style transformers. +This allows you to generate topological features from your data in a familiar way. Here is an example with the :class:`VietorisRipsPersistence` transformer: .. code-block:: python from gtda.homology import VietorisRipsPersistence - vietorisrips_tr = VietorisRipsPersistence() + VR = VietorisRipsPersistence() + +which computes topological summaries, called :ref:`persistence diagrams `, from collections of :ref:`point clouds ` or weighted graphs, as follows: + +.. code-block:: python + + diagrams = VR.fit_transform(point_clouds) -which calculates :ref:`persistent diagrams ` from a :ref:`point cloud `. +A plotting API allows for quick visual inspection of the outputs of many of ``giotto-tda``'s transformers. To visualize the i-th output sample, run .. code-block:: python - diagrams = vietorisrips_tr.fit_transform(point_clouds) + diagrams = VR.plot(diagrams, sample=i) -You can create features from the persistence diagrams in a similar way, using, for example, the :ref:`BettiCurve ` transformer. +You can create scalar or vector features from persistence diagrams using ``giotto-tda``'s dedicated transformers. Here is an example with the :class:`PersistenceEntropy` transformer: .. code-block:: python from gtda.diagrams import PersistenceEntropy - image_tr = PersistenceEntropy() - features = image_tr.fit_transform(diagrams) + PE = PersistenceEntropy() + features = PE.fit_transform(diagrams) -Extraction of topological features phrased in terms of transformers allows you to use the standard tools from scikit-learn, -combining topological features with standard models and -like grid-search or cross-validate your model. +:obj:`features` is a two-dimensional ``numpy`` array. This is important to making this type of topological feature generation fit into a typical machine learning workflow from ``scikit-learn``. +In particular, topological feature creation steps can be fed to or used alongside models from ``scikit-learn``, creating end-to-end pipelines which can be evaluated in cross-validation, +optimised via grid-searches, etc.: .. code-block:: python from sklearn.ensemble import RandomForestClassifier + from gtda.pipeline import make_pipeline from sklearn.model_selection import train_test_split - X_train, X_valid, y_train, y_valid = train_test_split(features, labels) - model = RandomForestClassifier() + X_train, X_valid, y_train, y_valid = train_test_split(point_clouds, labels) + RFC = RandomForestClassifier() + model = make_pipeline(VR, PE, RFC) model.fit(X_train, y_train) model.score(X_valid, y_valid) -EXPAND WITH A SNIPPET OR TWO FOR MAPPER +``giotto-tda`` also implements the `Mapper algorithm `_ as a highly customisable ``scikit-learn`` :class:`Pipeline`, and provides simple plotting functions +for visualizing output Mapper graphs and have real-time interaction with the pipeline parameters: + +.. code-block:: python + + from gtda.mapper import make_mapper_pipeline + from sklearn.decomposition import PCA + from sklearn.cluster import DBSCAN + + pipe = make_mapper_pipeline(filter_func=PCA(), clusterer=DBSCAN()) + plot_interactive_mapper_graph(pipe, data) ********* Resources ********* -Examples -======== - -We provide a number of :ref:`examples `, which offer: +Tutorials and examples +====================== - - a more comprehensive view of how the API can be used in simple, synthetic examples, - - an intuitive explanation of topological techniques. +We provide a number of :ref:`tutorials and examples `, which offer: -Additionally, the `post `_ -by Lewis Tunstall provides a general overview of the library. + - quick start guides to the API; + - in-depth examples showcasing more of the library's features; + - intuitive explanations of topological techniques. Use cases ========= -A selection of use cases that we worked on are available as github repositories and some of them are published as posts on Medium. -Please refer to `github `_ or the `L2F website `_ for a summary. +A selection of use cases for ``giotto-tda`` is collected at `this page `_. +The related GitHub repositories can be found at `github `_. ********** What's new diff --git a/doc/modules/base.rst b/doc/modules/base.rst index 149d2f848..c0cd3c010 100644 --- a/doc/modules/base.rst +++ b/doc/modules/base.rst @@ -11,3 +11,4 @@ :template: class.rst base.TransformerResamplerMixin + base.PlotterMixin diff --git a/doc/modules/index.rst b/doc/modules/index.rst index 45f0fcf7c..9f960ec34 100644 --- a/doc/modules/index.rst +++ b/doc/modules/index.rst @@ -14,10 +14,11 @@ This pages contains a list of available features in the library. point_clouds.rst time_series.rst graphs.rst + images.rst + plotting.rst base.rst pipeline.rst validation.rst - images.rst .. :mod:`gtda.manifold`: Manifold learning diff --git a/doc/modules/mapper.rst b/doc/modules/mapper.rst index 4db0778b2..406b68607 100644 --- a/doc/modules/mapper.rst +++ b/doc/modules/mapper.rst @@ -22,6 +22,7 @@ Filters Covers ------- + .. currentmodule:: gtda .. autosummary:: @@ -33,6 +34,7 @@ Covers Clustering ---------- + .. currentmodule:: gtda .. autosummary:: @@ -44,6 +46,7 @@ Clustering Pipeline -------- + .. currentmodule:: gtda .. autosummary:: @@ -61,6 +64,7 @@ Pipeline Visualization ------------- + .. currentmodule:: gtda .. autosummary:: @@ -75,7 +79,7 @@ Utilities .. currentmodule:: gtda .. autosummary:: - :toctree: generated/ + :toctree: generated/mapper/utils :template: function.rst mapper.utils.decorators.method_to_transform diff --git a/doc/modules/plotting.rst b/doc/modules/plotting.rst new file mode 100644 index 000000000..2f8154057 --- /dev/null +++ b/doc/modules/plotting.rst @@ -0,0 +1,18 @@ +:mod:`gtda.plotting`: Plotting functions +======================================== + +.. automodule:: gtda.plotting + :no-members: + :no-inherited-members: + +.. currentmodule:: gtda + +.. autosummary:: + :toctree: generated/plotting + :template: function.rst + + plotting.plot_point_cloud + plotting.plot_heatmap + plotting.plot_diagram + plotting.plot_betti_curves + plotting.plot_betti_surfaces diff --git a/doc/notebooks/advanced.rst b/doc/notebooks/advanced.rst deleted file mode 100644 index a0de36236..000000000 --- a/doc/notebooks/advanced.rst +++ /dev/null @@ -1,32 +0,0 @@ -######## -Advanced -######## - -This page contains advanced examples - -.. - toctree:: - :maxdepth: 2 - :hidden: - - classifying_shapes - lorenz_attractor - voids_on_the_plane - -.. include:: lorenz_attractor.rst - :end-before: Import libraries - -Try it on `github `__ for full interactivity, -or check `the static version `__. - -.. include:: classifying_shapes.rst - :end-before: Import libraries - -Try it on `github `__ for full interactivity, -or check `the static version `__. - -.. include:: voids_on_the_plane.rst - :end-before: Import libraries - -Try it on `github `__ for full interactivity, -or check `the static version `__. \ No newline at end of file diff --git a/doc/notebooks/basic.rst b/doc/notebooks/basic.rst deleted file mode 100644 index 131c45ae8..000000000 --- a/doc/notebooks/basic.rst +++ /dev/null @@ -1,25 +0,0 @@ -##### -Basic -##### - -This page contains basic examples. - -.. - toctree:: - :maxdepth: 2 - :hidden: - - vietoris_rips_quickstart - mapper_quickstart - -.. include:: vietoris_rips_quickstart.rst - :end-before: Import libraries - -Try it on `github `__ for full interactivity, -or check `the static version `__. - -.. include:: mapper_quickstart.rst - :end-before: Import libraries - -Try it on `github `__ for full interactivity, -or check `the static version `__. diff --git a/doc/notebooks/examples.rst b/doc/notebooks/examples.rst new file mode 100644 index 000000000..924921297 --- /dev/null +++ b/doc/notebooks/examples.rst @@ -0,0 +1,31 @@ +######## +Examples +######## + +This page contains examples of use of ``giotto-tda``. + +.. toctree:: + :maxdepth: 1 + + classifying_shapes + lorenz_attractor + voids_on_the_plane + +.. + include:: lorenz_attractor.rst + :end-before: Import libraries + + Try it on `github `__ for full interactivity, + or check `the static version `__. + + .. include:: classifying_shapes.rst + :end-before: Import libraries + + Try it on `github `__ for full interactivity, + or check `the static version `__. + + .. include:: voids_on_the_plane.rst + :end-before: Import libraries + + Try it on `github `__ for full interactivity, + or check `the static version `__. \ No newline at end of file diff --git a/doc/notebooks/index.rst b/doc/notebooks/index.rst index 7e7f73d12..e0dbffcf5 100644 --- a/doc/notebooks/index.rst +++ b/doc/notebooks/index.rst @@ -1,20 +1,20 @@ -########################################## -Examples, tutorials and plotting utilities -########################################## +###################### +Tutorials and examples +###################### -.. image:: https://www.giotto.ai/static/vector/logo.svg +.. image:: ../images/tda_logo.svg :width: 850 .. _notebooks_index: -This page contains examples and is composed of two parts. First, a more comprehensive view of how the API can be used in simple, synthetic examples, -with an intuitive explanation of topological techniques. Second, more advanced examples showcasing basic academic applications. +Browse through our tutorials to get acquainted with ``giotto-tda``'s API and basic functionality. Check out the +examples for more in-depth applications. .. toctree:: :maxdepth: 2 - basic - advanced + tutorials + examples diff --git a/doc/notebooks/tutorials.rst b/doc/notebooks/tutorials.rst new file mode 100644 index 000000000..52f886203 --- /dev/null +++ b/doc/notebooks/tutorials.rst @@ -0,0 +1,26 @@ +######### +Tutorials +######### + +This page contains tutorials to help you get started with ``giotto-tda``. Additionally, the `post `_ +by Lewis Tunstall provides a friendly introduction to the philosophy of ``giotto-tda`` and to some of its main features. + +.. toctree:: + :maxdepth: 1 + + vietoris_rips_quickstart + plotting_api + mapper_quickstart + +.. + include:: vietoris_rips_quickstart.rst + :end-before: Import libraries + + Try it on `github `__ for full interactivity, + or check `the static version `__. + + .. include:: mapper_quickstart.rst + :end-before: Import libraries + + Try it on `github `__ for full interactivity, + or check `the static version `__. diff --git a/doc/theory/glossary.tex b/doc/theory/glossary.tex index c6decbc1a..7494377d0 100644 --- a/doc/theory/glossary.tex +++ b/doc/theory/glossary.tex @@ -3,8 +3,8 @@ \usepackage{enumerate} \usepackage{tikz-cd} \usepackage{bm} -\usepackage[breaklinks=true, bookmarks=true, -bookmarksnumbered=true, breaklinks=true, +\usepackage[bookmarks=true, +bookmarksnumbered=true, pdfstartview=FitH, hyperfigures=false, plainpages=false, naturalnames=true, colorlinks=true, pagebackref=true, @@ -18,23 +18,27 @@ \begin{document} - \title{Glossary} + \title{Theory Glossary} \maketitle + + \bibliography{bibliography} \section{Symbols} - \begin{tabular}{ l l l} - $\Bbbk$ & : & An arbitrary field. \\ - $\mathbb R$ & : & The field of real numbers. \\ - $\overline{\mathbb R}$ & : & The two point compactification $[-\infty, +\infty]$ of the real numbers. \\ - $\mathbb N$ & : & The counting numbers $0,1,2, \ldots$ as a subset of $\mathbb R$. \\ - $\mathbb R^d$ & : & The vector space of $d$-tuples of real numbers. \\ - $\Delta$ & : & The \hyperref[multiset]{multiset} $\{(s,s)\,;\ s \in \mathbb R\}$ with multiplicity $(s,s) \mapsto +\infty$. + \begin{tabular}{ l l} + $\Bbbk$ & An arbitrary field. \\ + $\mathbb R$ & The field of real numbers. \\ + $\overline{\mathbb R}$ & The two point compactification $[-\infty, +\infty]$ of the real numbers. \\ + $\mathbb N$ & The counting numbers $0,1,2, \ldots$ as a subset of $\mathbb R$. \\ + $\mathbb R^d$ & The vector space of $d$-tuples of real numbers. \\ + $\Delta$ & The + %\hyperref[multiset]{multiset} + multiset $ \lbrace (s, s) \mid s \in \mathbb{R} \rbrace $ with multiplicity $ ( s,s ) \mapsto +\infty$. \end{tabular} \section{Homology} - \subsection*{Cubical complex} \label{cubical complex} + \subsection*{Cubical complex} \label{cubical_complex} An \textit{elementary interval} $I_a$ is a subset of $\mathbb{R}$ of the form $[a, a+1]$ or $[a,a] = \{a\}$ for some $a \in \mathbb{R}$. These two types are called respectively \textit{non-degenerate} and \textit{degenerate}. To a non-degenerate elementary interval we assign two degenerate elementary intervals \begin{equation*} @@ -57,21 +61,23 @@ \paragraph{\\ Reference:} \cite{mischaikow04computational} - \subsection*{Simplicial complex} \label{simplicial complex} + \subsection*{Simplicial complex} \label{simplicial_complex} A set $\{v_0, \dots, v_n\} \subset \mathbb{R}^N$ is said to be \textit{geometrically independent} if the vectors $\{v_0-v_1, \dots, v_0-v_n\}$ are linearly independent. In this case, we refer to their convex closure as a \textit{simplex}, explicitly \begin{equation*} - [v_0,\dots ,v_n] = \left\{ \sum c_i (v_0 - v_i)\ \big|\ c_1+\dots+c_n = 1,\ c_i \geq 0 \right\} + \lbrack v_0, \ldots , v_n \rbrack = \left\{ \sum c_i (v_0 - v_i)\ \big|\ c_1+\dots+c_n = 1,\ c_i \geq 0 \right\} \end{equation*} - and to $n$ as its \textit{dimension}. The \textit{$i$-th face} of $[v_0, \dots, v_n]$ is defined by + and to $n$ as its \textit{dimension}. The $i$\textit{-th face} of $[v_0, \dots, v_n]$ is defined by \begin{equation*} - d_i[v_0, \dots, v_n] = [v_0, \dots, \widehat{v}_i, \dots, v_n] + d_i[v_0, \ldots, v_n] = [v_0, \dots, \widehat{v}_i, \dots, v_n] \end{equation*} where $\widehat{v}_i$ denotes the absence of $v_i$ from the set. - A \textit{simplicial complex} $X$ is a finite union of simplices in $\mathbb{R}^N$ satisfying that every face of a simplex in $X$ is in $X$ and that the non-empty intersection of two simplices in $X$ is a face of each. Every simplicial complex defines an \hyperref[abstract simplicial complex]{abstract simplicial complex}. + A \textit{simplicial complex} $X$ is a finite union of simplices in $\mathbb{R}^N$ satisfying that every face of a simplex in $X$ is in $X$ and that the non-empty intersection of two simplices in $X$ is a face of each. Every simplicial complex defines an + % \hyperref[abstract_simplicial_complex]{abstract simplicial complex} + abstract simplicial complex. - \subsection*{Abstract simplicial complex} \label{abstract simplicial complex} + \subsection*{Abstract simplicial complex} \label{abstract_simplicial_complex} An \textit{abstract simplicial complex} is a pair of sets $(V, X)$ with the elements of $X$ being subsets of $V$ such that: \begin{enumerate} @@ -82,31 +88,39 @@ The elements of $X$ are called \textit{simplices} and the \textit{dimension} of a simplex $x$ is defined by $|x| = \# x - 1$ where $\# x$ denotes the cardinality of $x$. Simplices of dimension $d$ are called $d$-simplices. We abuse terminology and refer to the elements of $V$ and to their associated $0$-simplices both as \textit{vertices}. - The \textit{$k$-skeleton }$X_k$ of a simplicial complex $X$ is the subcomplex containing all simplices of dimension at most $k$. A simplicial complex is said to be \textit{$d$-dimensional} if $d$ is the smallest integer satisfying $X = X_d$. + The $k$\textit{-skeleton} $X_k$ of a simplicial complex $X$ is the subcomplex containing all simplices of dimension at most $k$. A simplicial complex is said to be $d$\textit{-dimensional} if $d$ is the smallest integer satisfying $X = X_d$. A \textit{simplicial map} between simplicial complexes is a function between their vertices such that the image of any simplex via the induced map is a simplex. A simplicial complex $X$ is a \textit{subcomplex} of a simplicial complex $Y$ if every simplex of $X$ is a simplex of $Y$. - Given a finite abstract simplicial complex $X = (V, X)$ we can choose a bijection from $V$ to a geometrically independent subset of $\mathbb R^N$ and associate a \hyperref[simplicial complex]{simplicial complex} to $X$ called its \textit{geometric realization}. + Given a finite abstract simplicial complex $X = (V, X)$ we can choose a bijection from $V$ to a geometrically independent subset of $\mathbb R^N$ and associate a + %\hyperref[simplicial_complex]{simplicial complex} + simplicial complex + to $X$ called its \textit{geometric realization}. - \subsection*{Ordered simplicial complex} \label{ordered simplical complex} + \subsection*{Ordered simplicial complex} + \label{ordered_simplical_complex} - An \textit{ordered simplicial complex} is an \hyperref[abstract simplicial complex]{abstract simplicial complex} where the set of vertices is equipped with a partial order such that the restriction of this partial order to any simplex is a total order. We denote an $n$-simplex using its ordered vertices by $[v_0, \dots, v_n]$. + An \textit{ordered simplicial complex} is an + % \hyperref[abstract_simplicial_complex]{abstract simplicial complex} + abstract simplicial complex where the set of vertices is equipped with a partial order such that the restriction of this partial order to any simplex is a total order. We denote an $n$-simplex using its ordered vertices by $[v_0, \dots, v_n]$. A \textit{simplicial map} between ordered simplicial complexes is a simplicial map $f$ between their underlying simplicial complexes preserving the order, i.e., $v \leq w$ implies $f(v) \leq f(w)$. - \subsection*{Directed simplicial complex} \label{directed simplicial complex} + \subsection*{Directed simplicial complex} \label{directed_simplicial_complex} A \textit{directed simplicial complex} is a pair of sets $(V, X)$ with the elements of $X$ being tuples of elements of $V$, i.e., elements in $\bigcup_{n\geq1} V^{\times n}$ such that: \begin{enumerate} - \item for every $v$ in $V$, the tuple $v$ is in $X$ and + \item for every $v$ in $V$, the tuple $v$ is in $X$ \item if $x$ is in $X$ and $y$ is a subtuple of $x$, then $y$ is in $X$. \end{enumerate} - With appropriate modifications the same terminology and notation introduced for \hyperref[ordered simplicial complex]{ordered simplicial complex} applies to directed simplicial complex. + With appropriate modifications the same terminology and notation introduced for + %\hyperref[ordered_simplical_complex]{ordered simplicial complex} + ordered simplicial complex applies to directed simplicial complex. - \subsection*{Chain complex} \label{chain complex} + \subsection*{Chain complex} \label{chain_complex} A \textit{chain complex} of is a pair $(C_*, \partial)$ where \begin{equation*} @@ -114,52 +128,66 @@ \end{equation*} with $C_n$ a $\Bbbk$-vector space and $\partial_n : C_{n+1} \to C_n$ is a $\Bbbk$-linear map such that $\partial_{n+1} \partial_n = 0$. We refer to $\partial$ as the \textit{boundary map} of the chain complex. - The elements of $C$ are called \textit{chains} and if $c \in C_n$ we say its \textit{degree} is $n$ or simply that it is an $n$-chain. Elements in the kernel of $\partial$ are called \textit{cycles}, and elements in the image of $\partial$ are called \textit{boundaries}. Notice that every boundary is a cycle. This fact is central to the definition of \hyperref[homology]{homology}. + The elements of $C$ are called \textit{chains} and if $c \in C_n$ we say its \textit{degree} is $n$ or simply that it is an $n$-chain. Elements in the kernel of $\partial$ are called \textit{cycles}, and elements in the image of $\partial$ are called \textit{boundaries}. Notice that every boundary is a cycle. This fact is central to the definition of + % \hyperref[homology_and_cohomology]{homology} + homology. A \textit{chain map} is a $\Bbbk$-linear map $f : C \to C'$ between chain complexes such that $f(C_n) \subseteq C'_n$ and $\partial f = f \partial$. Given a chain complex $(C_*, \partial)$, its linear dual $C^*$ is also a chain complex with $C^{-n} = \mathrm{Hom_\Bbbk}(C_n, \Bbbk)$ and boundary map $\delta$ defined by $\delta(\alpha)(c) = \alpha(\partial c)$ for any $\alpha \in C^*$ and $c \in C_*$. - \subsection*{Homology and cohomology} \label{homology and cohomology} + \subsection*{Homology and cohomology} \label{homology_and_cohomology} - Let $(C_*, \partial)$ be a \hyperref[chain complex]{chain complex}. Its \textit{$n$-th homology group} is the quotient of the subspace of $n$-cycles by the subspace of $n$-boundaries, that is, $H_n(C_*) = \mathrm{ker}(\partial_n)/ \mathrm{im}(\partial_{n+1})$. The \textit{homology} of $(C, \partial)$ is defined by $H_*(C) = \bigoplus_{n \in \mathbb Z} H_n(C)$. + Let $(C_*, \partial)$ be a + % \hyperref[chain_complex]{chain complex} + chain complex. Its $n$\textit{-th homology group} is the quotient of the subspace of $n$-cycles by the subspace of $n$-boundaries, that is, $H_n(C_*) = \mathrm{ker}(\partial_n)/ \mathrm{im}(\partial_{n+1})$. The \textit{homology} of $(C, \partial)$ is defined by $H_*(C) = \bigoplus_{n \in \mathbb Z} H_n(C)$. When the chain complex under consideration is the linear dual of a chain complex we sometimes refer to its homology as the \textit{cohomology} of the predual complex and write $H^n$ for $H_{-n}$. A chain map $f : C \to C'$ induces a map between the associated homologies. - \subsection*{Simplicial chains and simplicial homology} \label{simplicial chains and simplicial homology} + \subsection*{Simplicial chains and simplicial homology} \label{simplicial_chains_and_simplicial_homology} - Let $X$ be an ordered or directed simplicial complex. Define its \textit{simplicial chain complex with $\Bbbk$-coefficients} $C_*(X; \Bbbk)$ by + Let $X$ be an ordered or directed simplicial complex. Define its \textit{simplicial chain complex with} $\Bbbk$\textit{-coefficients} $C_*(X; \Bbbk)$ by \begin{equation*} - C_n(X; \Bbbk) = \Bbbk\{X_n\} \qquad \partial_n(x) = \sum_{i=0}^{n} (-1)^i d_ix + C_n(X; \Bbbk) = \Bbbk\{X_n\}, \qquad \partial_n(x) = \sum_{i=0}^{n} (-1)^i d_ix \end{equation*} - and its \textit{homology and cohomology with $\Bbbk$-coefficients} as the \hyperref[homology and cohomology]{homology and cohomology} of this chain complex. We use the notation $H_*(X; \Bbbk)$ and $H^*(X; \Bbbk)$ for these. + and its \textit{homology and cohomology with} $\Bbbk$\textit{-coefficients} as the + % \hyperref[homology_and_cohomology]{homology and cohomology} + homology and cohomology of this chain complex. We use the notation $H_*(X; \Bbbk)$ and $H^*(X; \Bbbk)$ for these. - A \hyperref[abstract simplicial complex]{simplicial map} induces a \hyperref[chain complex]{chain map} between the associated simplicial chain complexes and, therefore, between the associated simplicial (co)homologies. + A + % \hyperref[abstract_simplicial_complex]{simplicial map} + simplicial map induces a + % \hyperref[chain_complex]{chain map} + chain map between the associated simplicial chain complexes and, therefore, between the associated simplicial (co)homologies. - \subsection*{Cubical chains and cubical homology} \label{cubical chains and cubical homology} + \subsection*{Cubical chains and cubical homology} \label{cubical_chains_and_cubical_homology} - Let $X$ be a cubical complex. Define its \textit{cubical chain complex with $\Bbbk$-coefficients} $C_*(X; \Bbbk)$ by + Let $X$ be a cubical complex. Define its \textit{cubical chain complex with} $\Bbbk$\textit{-coefficients} $C_*(X; \Bbbk)$ by \begin{equation*} - C_n(X; \Bbbk) = \Bbbk\{X_n\} \qquad \partial_n x = \sum_{i = 1}^{n} (-1)^{i-1}(d^+_i x - d^-_i x) + C_n(X; \Bbbk) = \Bbbk\{X_n\}, \qquad \partial_n x = \sum_{i = 1}^{n} (-1)^{i-1}(d^+_i x - d^-_i x) \end{equation*} where $x = I_1 \times \cdots \times I_N$ and $s(i)$ is the dimension of $I_1 \times \cdots \times I_i$. - Its \textit{homology and cohomology with $\Bbbk$-coefficients} is the \hyperref[homology and cohomology]{homology and cohomology} of this chain complex. We use the notation $H_*(X; \Bbbk)$ and $H^*(X; \Bbbk)$ for these. + Its \textit{homology and cohomology with} $\Bbbk$\textit{-coefficients} is the + % \hyperref[homology_and_cohomology]{homology and cohomology} + homology and cohomology of this chain complex. We use the notation $H_*(X; \Bbbk)$ and $H^*(X; \Bbbk)$ for these. - \subsection*{Filtered complex} \label{filtered complex} + \subsection*{Filtered complex} \label{filtered_complex} A \textit{filtered complex} is a collection of simplicial or cubical complexes $\{X_s\}_{s \in \mathbb R}$ such that $X_s$ is a subcomplex of $X_t$ for each $s \leq t$. - \subsection*{Cellwise filtration} \label{cellwise filtration} + \subsection*{Cellwise filtration} \label{cellwise_filtration} - A \textit{cellwise filtration} is a simplicial or cubical complex $X$ together with a total order $\leq$ on its simplices or elementary cubes such that for each $y \in X$ the set $\{x \in X\ :\ x \leq y\}$ is a subcomplex of $X$. A cellwise filtration can be naturally thought of as a \hyperref[filtered complex]{filtered complex}. + A \textit{cellwise filtration} is a simplicial or cubical complex $X$ together with a total order $\leq$ on its simplices or elementary cubes such that for each $y \in X$ the set $\{x \in X\ :\ x \leq y\}$ is a subcomplex of $X$. A cellwise filtration can be naturally thought of as a + % \hyperref[filtered_complex]{filtered complex} + filtered complex. - \subsection*{Clique and flag complexes} \label{clique and flag complexes} + \subsection*{Clique and flag complexes} \label{clique_and_flag_complexes} Let $G$ be a $1$-dimensional abstract (resp. directed) simplicial complex. The abstract (resp. directed) simplicial complex $\langle G \rangle$ has the same set of vertices as $G$ and $\{v_0, \dots, v_n\}$ \big(resp. $(v_0, \dots, v_n)$\big) is a simplex in $\langle G \rangle$ if an only if $\{v_i, v_j\}$ \big(resp. $(v_i, v_j)$\big) is in $G$ for each pair of vertices $v_i, v_j$. - An abstract (resp. directed) simplicial complex $X$ is a \textit{clique (resp. flag) complex} if $X = \langle G \rangle$ for some $G$. + An abstract (resp. directed) simplicial complex $X$ is a \textit{clique (resp.\ flag) complex} if $X = \langle G \rangle$ for some $G$. Given a function \begin{equation*} @@ -174,53 +202,72 @@ w\{v_0, \dots, v_n\} & = \max\{ w\{v_i, v_j\}\ |\ i \neq j\} \\ w(v_0, \dots, v_n) & = \max\{ w(v_i, v_j)\ |\ i < j\} \end{align*} - and define the \hyperref[filtered complex]{filtered complex} $\{\langle G \rangle_{s}\}_{s \in \mathbb R}$ by + and define the % \hyperref[filtered_complex]{filtered complex} + filtered complex $\{\langle G \rangle_{s}\}_{s \in \mathbb R}$ by \begin{equation*} \langle G \rangle_s = \{\sigma \in \langle G \rangle\ |\ w(\sigma) \leq s\}. \end{equation*} - A filtered complex $\{X_s\}_{s \in \mathbb R}$ is a \textit{filtered clique (resp. flag) complex} if $X_s = \langle G \rangle_s$ for some $(G,w)$. + A filtered complex $\{X_s\}_{s \in \mathbb R}$ is a \textit{filtered clique (resp.\ flag) complex} if $X_s = \langle G \rangle_s$ for some $(G,w)$. - \subsection*{Persistence module} \label{persistence module} + \subsection*{Persistence module} \label{persistence_module} A \textit{persistence module} is a collection containing a $\Bbbk$-vector spaces $V(s)$ for each real number $s$ together with $\Bbbk$-linear maps $f_{st} : V(s) \to V(t)$, referred to as \textit{structure maps}, for each pair $s \leq t$, satisfying naturality, i.e., if $r \leq s \leq t$, then $f_{rt} = f_{st} \circ f_{rs}$ and tameness, i.e., all but finitely many structure maps are isomorphisms. A \textit{morphism of persistence modules} $F : V \to W$ is a collection of linear maps $F(s) : V(s) \to W(s)$ such that $F(t) \circ f_{st} = f_{st} \circ F(s)$ for each par of reals $s \leq t$. We say that $F$ is an \textit{isomorphisms} if each $F(s)$ is. - \subsection*{Persistent simplicial (co)homology} \label{persistent simplicial (co)homology} + \subsection*{Persistent simplicial (co)homology} \label{persistent_simplicial_(co)homology} Let $\{X(s)\}_{s \in \mathbb R} $ be a set of ordered or directed simplicial complexes together with simplicial maps $f_{st} : X(s) \to X(t)$ for each pair $s \leq t$, such that \begin{equation*} r \leq s \leq t\ \quad\text{implies} \quad f_{rt} = f_{st} \circ f_{rs} \end{equation*} - for example, a \hyperref[filtered complex]{filtered complex}. Its \textit{persistent simplicial homology with $\Bbbk$-coefficients} is the persistence module + for example, a + % \hyperref[filtered_complex]{filtered complex} + filtered complex. Its \textit{persistent simplicial homology with} $\Bbbk$\textit{-coefficients} is the persistence module \begin{equation*} H_*(X(s); \Bbbk) \end{equation*} - with structure maps $H_*(f_{st}) : H_*(X(s); \Bbbk) \to H_*(X(t); \Bbbk)$ induced form the maps $f_{st.}$ In general, the collection constructed this way needs not satisfy the tameness condition of a \hyperref[persistence module]{persistence module}, but we restrict attention to the cases where it does. Its \textit{persistence simplicial cohomology with $\Bbbk$-coefficients} is defined analogously. + with structure maps $H_*(f_{st}) : H_*(X(s); \Bbbk) \to H_*(X(t); \Bbbk)$ induced form the maps $f_{st.}$ In general, the collection constructed this way needs not satisfy the tameness condition of a + % \hyperref[persistence_module]{persistence module} + persistence module, but we restrict attention to the cases where it does. Its \textit{persistence simplicial cohomology with} $\Bbbk$\textit{-coefficients} is defined analogously. - \subsection*{Vietoris-Rips complex and Vietoris-Rips persistence} \label{vietoris-rips complex and vietoris-rips persistence} + \subsection*{Vietoris-Rips complex and Vietoris-Rips persistence} \label{vietoris-rips_complex_and_vietoris-rips_persistence} - Let $(X, d)$ be a \hyperref[finite metric spaces and point clouds]{finite metric space}. Define the Vietoris-Rips complex of $X$ as the \hyperref[filtered complex]{filtered complex} $VR_s(X)$ that contains a subset of $X$ as a simplex if all pairwise distances in the subset are less than or equal to $s$, explicitly + Let $(X, d)$ be a + % \hyperref[finite_metric_spaces_and_point_clouds]{finite metric space} + finite metric space. Define the Vietoris-Rips complex of $X$ as the + % \hyperref[filtered_complex]{filtered complex} + filtered complex $VR_s(X)$ that contains a subset of $X$ as a simplex if all pairwise distances in the subset are less than or equal to $s$, explicitly \begin{equation*} VR_s(X) = \Big\{ [v_0,\dots,v_n]\ \Big|\ \forall i,j\ \,d(v_i, v_j) \leq s \Big\}. \end{equation*} - The \textit{Vietoris-Rips persistence} of $(X, d)$ is the \hyperref[persistent simplicial (co)homology]{persistent simplicial (co)homology} of $VR_s(X)$. + The \textit{Vietoris-Rips persistence} of $(X, d)$ is the + % \hyperref[persistent_simplicial_(co)homology]{persistent simplicial (co)homology} + persistent simplicial (co)homology of $VR_s(X)$. A more general version is obtained by replacing the distance function with an arbitrary function \begin{equation*} w : X \times X \to \mathbb R \cup \{\infty\} \end{equation*} - and defining $VR_s(X)$ as the \hyperref[clique and flag complexes]{filtered clique complex} associated to $(X \times X ,w)$. + and defining $VR_s(X)$ as the + % \hyperref[clique_and_flag_complexes]{filtered clique complex} + filtered clique complex associated to $(X \times X ,w)$. - \subsection*{\v{C}ech complex and \v{C}ech persistence} \label{cech complex and cech persistence} + \subsection*{\v{C}ech complex and \v{C}ech persistence} \label{cech_complex_and_cech_persistence} - Let $(X, d)$ be a \hyperref[finite metric spaces and point clouds]{point cloud}. Define the \v{C}ech complex of $X$ as the \hyperref[filtered complex]{filtered complex} $\check{C}_s(X)$ that is empty if $s<0$ and, if $s \geq 0$, contains a subset of $X$ as a simplex if the balls of radius $s$ with centers in the subset have a non-empty intersection, explicitly + Let $(X, d)$ be a + % \hyperref[finite_metric_spaces_and_point_clouds]{point cloud} + point cloud. Define the \v{C}ech complex of $X$ as the + % \hyperref[filtered_complex]{filtered complex} + filtered complex $\check{C}_s(X)$ that is empty if $s<0$ and, if $s \geq 0$, contains a subset of $X$ as a simplex if the balls of radius $s$ with centers in the subset have a non-empty intersection, explicitly \begin{equation*} \check{C}_s(X) = \Big\{ [v_0,\dots,v_n]\ \Big|\ \bigcap_{i=0}^n B_s(x_i) \neq \emptyset \Big\}. \end{equation*} - The \textit{\v Cech persistence (co)homology} of $(X,d)$ is the \hyperref[persistent simplicial (co)homology]{persistent simplicial (co)homo-logy} of $\check{C}_s(X)$. + The \textit{\v Cech persistence (co)homology} of $(X,d)$ is the + % \hyperref[persistent_simplicial_(co)homology]{persistent simplicial (co)homo-logy} + persistent simplicial (co)homo-logy of $\check{C}_s(X)$. \subsection*{Multiset} \label{multiset} @@ -234,19 +281,23 @@ \end{cases} \end{equation*} - \subsection*{Persistence diagram} \label{persistence diagram} + \subsection*{Persistence diagram} \label{persistence_diagram} - A \textit{persistence diagram} is a \hyperref[multiset]{multiset} of points in + A \textit{persistence diagram} is a + %\hyperref[multiset]{multiset} + multiset of points in \begin{equation*} \mathbb R \times \big( \mathbb{R} \cup \{+\infty\} \big). \end{equation*} - Given a \hyperref[persistence module]{persistence module} its associated persistence diagram is determined by the following condition: for each pair $s,t$ the number counted with multiplicity of points $(b,d)$ in the multiset, satisfying $b \leq s \leq t < d$ is equal to the rank of $f_{st.}$ + Given a + % \hyperref[persistence_module]{persistence module} + persistence module, its associated persistence diagram is determined by the following condition: for each pair $s,t$ the number counted with multiplicity of points $(b,d)$ in the multiset, satisfying $b \leq s \leq t < d$ is equal to the rank of $f_{st.}$ A well known result establishes that there exists an isomorphism between two persistence module if and only if their persistence diagrams are equal. - \subsection*{Wasserstein and bottleneck distance} \label{wasserstein and bottleneck distance} + \subsection*{Wasserstein and bottleneck distance} \label{wasserstein_and_bottleneck_distance} - The \textit{$p$-Wasserstein distance} between two persistence diagrams $D_1$ and $D_2$ is the infimum over all bijections $\gamma: D_1 \cup \Delta \to D_2 \cup \Delta$ of + The $p$\textit{-Wasserstein distance} between two persistence diagrams $D_1$ and $D_2$ is the infimum over all bijections $\gamma: D_1 \cup \Delta \to D_2 \cup \Delta$ of \begin{equation*} \Big(\sum_{x \in D_1 \cup \Delta} ||x - \gamma(x)||_\infty^p \Big)^{1/p} \end{equation*} @@ -259,15 +310,17 @@ \paragraph{\\ Reference:} \cite{kerber2017geometry} - \subsection*{Persistence landscape} \label{persistence landscape} + \subsection*{Persistence landscape} \label{persistence_landscape} A \textit{persistence landscape} is a set $\{\lambda_k\}_{k \in \mathbb N}$ of functions \begin{equation*} \lambda : \mathbb R \to \overline{\mathbb R} \end{equation*} - where $\lambda_k$ is referred to as the \textit{$k$-layer of the persistence landscape}. + where $\lambda_k$ is referred to as the $k$\textit{-layer of the persistence landscape}. - Let $\{(b_i, d_i)\}_{i \in I}$ be a \hyperref[persistence diagram] {persistence diagram}. Its \textit{associated persistence landscape} $\lambda$ is defined by letting $\lambda_k$ be the $k$-th largest value of the set $\{\Lambda_i(t)\}_ {i \in I}$ where + Let $\{(b_i, d_i)\}_{i \in I}$ be a + % \hyperref[persistence_diagram]{persistence diagram} + persistence diagram. Its \textit{associated persistence landscape} $\lambda$ is defined by letting $\lambda_k$ be the $k$-th largest value of the set $\{\Lambda_i(t)\}_ {i \in I}$ where \begin{equation*} \Lambda_i(t) = \left[ \min \{t-b_i, d_i-t\}\right]_+ \end{equation*} @@ -277,7 +330,7 @@ \paragraph{\\ Reference:} \cite{bubenik2015statistical} - \subsection*{Persistence landscape norm} \label{persistence landscape norm} + \subsection*{Persistence landscape norm} \label{persistence_landscape_norm} Given a function $f : \mathbb R \to \overline{\mathbb R}$ define \begin{equation*} @@ -285,7 +338,9 @@ \end{equation*} whenever the right hand side exists and is finite. - The \textit{$p$-norm} of a \hyperref[persistence landscape]{persistence landscape} $\lambda = \{\lambda_k\}_{k \in \mathbb N}$ is defined to be + The $p$\textit{-norm} of a + % \hyperref[persistence_landscape]{persistence landscape} + persistence landscape $\lambda = \{\lambda_k\}_{k \in \mathbb N}$ is defined to be \begin{equation*} ||\lambda||_p = \left( \sum_{i \in \mathbb N} ||\lambda_i||^p_p \right)^{1/p} @@ -294,27 +349,35 @@ \paragraph{\\ References:} \cite{stein2011functional, bubenik2015statistical} - \subsection*{Weighted silhouette} \label{weighted silhouettes} + \subsection*{Weighted silhouette} \label{weighted_silhouette} - Let $D = {(b_i, d_i)}_{i \in I}$ be a \hyperref[persistence diagram] {persistence diagram}. A \textit{weighted silhouette} associated to $D$ is a continuous function $\phi : \mathbb R \to \mathbb R$ of the form + Let $D = {(b_i, d_i)}_{i \in I}$ be a + % \hyperref[persistence_diagram] {persistence diagram} + persistence diagram. A \textit{weighted silhouette} associated to $D$ is a continuous function $\phi : \mathbb R \to \mathbb R$ of the form \begin{equation*} \phi(t) = \frac{\sum_{i \in I}w_i \Lambda_i(t)}{\sum_{i \in I}w_i}, \end{equation*} where $\{w_i\}_{i \in I}$ is a set of positive real numbers and - \begin{equation*} \label{equation: lambda for persistence landscapes} + \begin{equation*} \label{equation:lambda_for_persistence_landscapes} \Lambda_i(t) = \left[ \min \{t-b_i, d_i-t\}\right]_+ \end{equation*} with $c_+ := \max(c,0)$. The particular choice $w_i = \vert d_i - b_i \vert^p$ for $0 < p \leq \infty$ is referred to as \textit{power-weighted silhouettes}. \paragraph{\\ References:} \cite{chazal2014stochastic} - \subsection*{Amplitude} \label{amplitude} + \subsection*{Amplitude} + \label{amplitude} - Given a function assigning a real number to a pair of persistence diagrams, we define the \textit{amplitude} of a persistence diagram $D$ to be the value assigned to the pair $(D \cup \Delta, \Delta)$. Important examples of such functions are: \hyperref[wasserstein and bottleneck distance]{Wasserstein and bottleneck distances} and \hyperref[persistence landscape norm]{landscape distance}. + Given a function assigning a real number to a pair of persistence diagrams, we define the \textit{amplitude} of a persistence diagram $D$ to be the value assigned to the pair $(D \cup \Delta, \Delta)$. Important examples of such functions are: %\hyperref[wasserstein_and_bottleneck_distance]{Wasserstein and bottleneck distances} + Wasserstein and bottleneck distances and + % \hyperref[persistence_landscape_norm]{landscape distance} + landscape distance. - \subsection*{Persistence entropy} \label{persistence entropy} + \subsection*{Persistence entropy} \label{persistence_entropy} - Intuitively, this is a measure of the entropy of the points in a \hyperref[persistence diagram]{persistence diagram}. Precisely, let $D = \{(b_i, d_i)\}_{i \in I}$ be a persistence diagram with each $d_i < +\infty$. The \textit{persistence entropy} of $D$ is defined by + Intuitively, this is a measure of the entropy of the points in a + % \hyperref[persistence_diagram]{persistence diagram} + persistence diagram. Precisely, let $D = \{(b_i, d_i)\}_{i \in I}$ be a persistence diagram with each $d_i < +\infty$. The \textit{persistence entropy} of $D$ is defined by \begin{equation*} E(D) = - \sum_{i \in I} p_i \log(p_i) \end{equation*} @@ -325,13 +388,15 @@ \paragraph{\\ References:} \cite{rucco2016characterisation} - \subsection*{Betti curve} \label{betti curve} + \subsection*{Betti curve} \label{betti_curve} - Let $D$ be a \hyperref[persistence diagram]{persistence diagram}. Its \textit{Betti curve} is the function $\beta_D : \mathbb R \to \mathbb N$ whose value on $s \in \mathbb R$ is the number, counted with multiplicity, of points $(b_i,d_i)$ in $D$ such that $b_i \leq s 0$ the intersection between $K$ and $\{y \,;\ d(x,y) < \epsilon \}$ is not empty. It is said to be \textit{compact} if it is both bounded and complete. \section{Bibliography} \bibliography{bibliography}{} \bibliographystyle{alpha} + \end{document} diff --git a/examples/README.rst b/examples/README.rst index 58ac2a186..1f4ac6df0 100644 --- a/examples/README.rst +++ b/examples/README.rst @@ -1,22 +1,22 @@ -.. image:: https://www.giotto.ai/static/vector/logo.svg +.. image:: ../doc/images/tda_logo.svg :width: 850 Examples, tutorials and plotting utilities ========================================== -In this folder you can find basic tutorials and examples to get started quickly with giotto-tda. Additionally, ``plotting.py`` contains utilities for plotting the outputs of several computations you can perform with giotto-tda. +In this folder you can find basic tutorials and examples to get started quickly with ``giotto-tda``. Classifying Shapes ------------------ -This tutorial is about generating classical surfaces, such as tori and 2-spheres, and study their cohomological properites. +This tutorial is about generating classical surfaces, such as tori and 2-spheres, and study their cohomological properties. Non-orientable surfaces, such as the Klein bottle, are approximated by a grid and the reciprocal distances between the grid vertices forms the input of the Vietoris–Rips algorithm. Lorenz attractor ---------------- -This tutorial is about detecting chaotic regimes in a simulation of the `Lorenz attractor `_. The main tools of giotto-tda useful for time-series analysis (such as the *Takens embedding*) are used and explained in the tutorial. Other feature creation methods, such as the *persistence landscape* or the *persistence entropy*, are described in the final part of the +This tutorial is about detecting chaotic regimes in a simulation of the `Lorenz attractor `_. The main tools of ``giotto-tda`` useful for time-series analysis (such as the *Takens embedding*) are used and explained in the tutorial. Other feature creation methods, such as the *persistence landscape* or the *persistence entropy*, are described in the final part of the tutorial. Mapper quickstart diff --git a/examples/classifying_shapes.ipynb b/examples/classifying_shapes.ipynb index 0356518fe..973394d32 100644 --- a/examples/classifying_shapes.ipynb +++ b/examples/classifying_shapes.ipynb @@ -6,7 +6,9 @@ "source": [ "# Case study: Classification of shapes\n", "\n", - "The following notebook explains how to use giotto-tda to be able to classify topologically different high-dimensional spaces.\n", + "This notebook explains how to use `giotto-tda` to be able to classify topologically different high-dimensional spaces.\n", + "\n", + "If you are looking at a static version of this notebook and would like to run its contents, head over to [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/classifying_shapes.ipynb).\n", "\n", "**License: AGPLv3**" ] @@ -16,7 +18,7 @@ "metadata": {}, "source": [ "## Import libraries\n", - "The first step consists in importing relevant *gtda* components and other useful libraries or modules." + "The first step consists in importing relevant `giotto-tda` components and other useful libraries or modules." ] }, { @@ -27,24 +29,13 @@ "source": [ "# Importing libraries\n", "from gtda.homology import VietorisRipsPersistence\n", - "from gtda.diagrams import PersistenceEntropy, BettiCurve, PersistenceLandscape, HeatKernel\n", + "from gtda.diagrams import PersistenceEntropy\n", "\n", "import numpy as np\n", "\n", - "from sklearn.pipeline import Pipeline\n", + "from gtda.pipeline import Pipeline\n", "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.metrics import pairwise_distances\n", "\n", - "import matplotlib.pyplot as plt\n", - "from mpl_toolkits.mplot3d import Axes3D " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ "# Plotting functions\n", "from gtda.plotting import plot_diagram, plot_point_cloud, plot_heatmap" ] @@ -53,7 +44,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Sampling orientable surfaces\n", + "## Sampling orientable surfaces\n", "\n", "We are going to consider three classical topological spaces: the circle, the 2-torus and the 2-sphere.\n", "The purpose of this tutorial is to go through the most famous topological spaces and compute their homology groups.\n", @@ -108,7 +99,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Computing persistent homology\n", + "## Computing persistent homology\n", "\n", "In the next section we will use giotto-tda to compute the persistent homology groups of the topological spaces we just constructed.\n", "\n", @@ -127,26 +118,17 @@ "homology_dimensions = (0, 1, 2)\n", "VR = VietorisRipsPersistence(\n", " metric='euclidean', max_edge_length=10, homology_dimensions=homology_dimensions)\n", - "VR.fit(topological_spaces)\n", "\n", - "# List of all the time-ordered persistence diagrams obtained from the list of correlation matrices\n", - "diagrams = VR.transform(topological_spaces)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(diagrams.shape)" + "# Array of persistence diagrams, one per point cloud in the input\n", + "diagrams = VR.fit_transform(topological_spaces)\n", + "print(f'diagrams.shape = {diagrams.shape}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Persistence diagrams\n", + "## Persistence diagrams\n", "\n", "The topological information of the point cloud is synthesised in the persistence diagram. The horizontal axis corresponds to the moment in which an homological generator is born, while the vertical axis corresponds to the moments in which a homological generator dies.\n", "\n", @@ -187,7 +169,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Conclusion of the first part\n", + "## Conclusion of the first part\n", + "\n", "As you can see from the persistence diagrams, all the betti numbers were found. Some other persistent generators are also appearing, depending on how dense the sampling is and how much noise there is. For example, we see a rather neat persistence diagram over the Torus bottle (we see two persistent generators for $H_1$ and one persistent generator for $H_2$). Notice though that there are other persistent $H_1$ generators, possibly due to the non-uniform sampling method we used for the torus.\n", "\n", "On the other hand, the persistence diagram for the circle is as perfect as it could be: one unique generator of $H_1$ and no other persistent generator, as expected." @@ -197,7 +180,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Classification of noisy orientable surfaces\n", + "## Classification of noisy orientable surfaces\n", "In the next section we generate hundreds of noisy spheres and noisy tori. The effect of noise is to displace the points sampling the aforementioned surfaces by a random amount in a random direction.\n", "\n", "The Vietoris–Rips algorithm is used to compute persistence diagrams. Afterwards, from each diagram, the *persistence entropy* is computed.\n", @@ -299,7 +282,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Generating non-orientable surfaces\n", + "## Generating non-orientable surfaces\n", "\n", "We are going to consider different classical shapes: the real projective space and the Klein bottle.\n", "The purpose of the second part of the tutorial is to define shapes via a distance matrix. We also add noise to the distance matrix: the main reason is not to have overlapping points in the persistence diagram.\n", @@ -397,7 +380,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Computing persistent homology\n", + "## Computing persistent homology\n", "\n", "In the next section we will use `giotto-tda` to compute the persistent homology groups of the topological spaces we just constructed." ] @@ -421,7 +404,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Persistence diagrams\n", + "## Persistence diagrams\n", "\n", "The topological information of the point cloud is synthesised in the persistence diagram. The horizontal axis corresponds to the moment in which an homological generator is born, while the vertical axis corresponds to the moments in which an homological generator dies.\n", "\n", @@ -452,19 +435,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Conclusion\n", + "## Conclusion\n", "\n", "As you can see from the persistence diagrams, all the Betti numbers were found. Some other persistent generators are also appearing, depending on how dense the sampling is and how much noise there is.\n", "\n", "For example, we see a rather neat persistence diagram over the Klein bottle (we see two persistent generators for $H_1$ and one persistent generator for $H_2$). Notice that all these homology groups are computed over the field $\\mathbb{F}_2$." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/lorenz_attractor.ipynb b/examples/lorenz_attractor.ipynb index 12826eaf9..15fb5ec7a 100644 --- a/examples/lorenz_attractor.ipynb +++ b/examples/lorenz_attractor.ipynb @@ -8,6 +8,8 @@ "\n", "This notebook contains a full TDA pipeline to analyse the transitions of the Lorenz system to a chaotic regime from the stable one and viceversa.\n", "\n", + "If you are looking at a static version of this notebook and would like to run its contents, head over to [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/lorenz_attractor.ipynb).\n", + "\n", "**License: AGPLv3**" ] }, @@ -62,7 +64,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Setting up the Lorenz attractor simulation\n", + "## Setting up the Lorenz attractor simulation\n", "\n", "In the next block we set up all the parameters of the Lorenz system and we define also the instants at which the regime (stable VS chaotic) changes." ] @@ -107,7 +109,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Resampling the time series\n", + "## Resampling the time series\n", "\n", "It is important to find the correct time scale at which key signals take place. Here we propose one possible resampling period: *10h*. Recall that the unit time is *1h*. The resampler method is used to perform the resampling." ] @@ -140,7 +142,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Takens Embedding\n", + "## Takens Embedding\n", "\n", "In order to obtain meaningful topological features from a time series, we use a delayed-time embedding technique, invented by F. Takens in the late 1960s.\n", "The idea is simple: given a time series $X(t)$, one can extract a sequence of vectors of the form $X_i := [(X(t_i)), X(t_i + 2 \\tau), ..., X(t_i + M \\tau)]$.\n", @@ -245,8 +247,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Persistence diagram\n", - "The topological information of the correlation metric is synthesised in the persistent diagram. The horizontal axis corresponds to the moment in which an homological generator is born, while the vertical axis corresponds to the moments in which an homological generator dies.\n", + "## Persistence diagram\n", + "The topological information in the embedding is synthesised via the persistence diagram. The horizontal axis corresponds to the moment in which a homological generator is born, while the vertical axis corresponds to the moments in which a homological generator dies.\n", "The generators of the homology groups (at given rank) are colored differently." ] }, @@ -293,7 +295,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Scikit-learn–style pipeline\n", + "## Scikit-learn–style pipeline\n", "\n", "One of the advantages of `giotto-tda` is the compatibility with `scikit-learn`. It is possible to set up and run a full pipeline such as the one above in a few lines:" ] @@ -339,9 +341,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Rescaling the diagram\n", + "## Rescaling the diagram\n", "\n", - "Rescaling a diagram means normalizing points such that the maximum \"bottleneck distance\" from the *empty diagram* (by default, across all homology dimensions) is equal to one. Notice that this means the birth and death scales are modified. We can use `Scakler` as follows:" + "Rescaling a diagram means normalizing points such that the maximum \"bottleneck distance\" from the *empty diagram* (by default, across all homology dimensions) is equal to one. Notice that this means the birth and death scales are modified. We can use `Scaler` as follows:" ] }, { @@ -361,7 +363,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Filtering diagrams\n", + "## Filtering diagrams\n", "\n", "Filtering a diagram means eliminating the homology generators whose lifespan is considererd too short to be significant. We can use `Filtering` as follows:" ] @@ -415,7 +417,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Persistence entropy\n", + "## Persistence entropy\n", "\n", "In this section we show how to compute the *entropy* of persistence diagrams." ] @@ -447,7 +449,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Betti Curves\n", + "## Betti Curves\n", "\n", "In this section we show how to compute the Betti curves of a persistence diagram. We also show the plot of the Betti surface, i.e. the time-stack of the Betti curves." ] @@ -476,7 +478,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Distances among diagrams\n", + "## Distances among diagrams\n", "\n", "In this section we show how to compute several notions of distances among persistence diagrams.\n", "\n", @@ -563,7 +565,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# New distances in the embedding space: kNN graphs and geodesic distances\n", + "## New distances in the embedding space: kNN graphs and geodesic distances\n", "\n", "We propose here a new way to compute distances between points in the embedding space. Instead of considering the Euclidean distance in the Takens space, we propose to build a $k$-nearest neighbors graph and then use the geodesic distance on such graph." ] @@ -678,7 +680,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.1" + "version": "3.7.6" } }, "nbformat": 4, diff --git a/examples/mapper_quickstart.ipynb b/examples/mapper_quickstart.ipynb index 3d76b8991..480a134d1 100644 --- a/examples/mapper_quickstart.ipynb +++ b/examples/mapper_quickstart.ipynb @@ -6,7 +6,9 @@ "source": [ "# Getting Started with Mapper\n", "\n", - "In this notebook we explore a few of the core features included in giotto-tda's implementation of the [Mapper algorithm](https://research.math.osu.edu/tgda/mapperPBG.pdf). \n", + "In this notebook we explore a few of the core features included in `giotto-tda`'s implementation of the [Mapper algorithm](https://research.math.osu.edu/tgda/mapperPBG.pdf). \n", + "\n", + "If you are looking at a static version of this notebook and would like to run its contents, head over to [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/mapper_quickstart.ipynb).\n", "\n", "## Useful references\n", "\n", @@ -34,7 +36,7 @@ "import pandas as pd # Not a requirement of giotto-tda, but is compatible with the gtda.mapper module\n", "\n", "# Data viz\n", - "import plotly.graph_objects as go\n", + "from gtda.plotting import plot_point_cloud\n", "\n", "# TDA magic\n", "from gtda.mapper import (\n", @@ -49,11 +51,7 @@ "# ML tools\n", "from sklearn import datasets\n", "from sklearn.cluster import DBSCAN\n", - "from sklearn.decomposition import PCA\n", - "\n", - "import warnings\n", - "\n", - "warnings.simplefilter(action=\"ignore\", category=FutureWarning)" + "from sklearn.decomposition import PCA" ] }, { @@ -70,17 +68,9 @@ "metadata": {}, "outputs": [], "source": [ - "data, _ = datasets.make_circles(n_samples=5000, noise=0.05, factor=0.3, random_state=42)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig = go.Figure(data=go.Scatter(x=data[:, 0], y=data[:, 1], mode='markers'))\n", - "fig.show()" + "data, _ = datasets.make_circles(n_samples=5000, noise=0.05, factor=0.3, random_state=42)\n", + "\n", + "plot_point_cloud(data)" ] }, { @@ -90,7 +80,7 @@ "## Configure the Mapper pipeline\n", "Given a dataset ${\\cal D}$ of points $x \\in \\mathbb{R}^n$, the basic steps behind Mapper are as follows:\n", "\n", - "1. Map ${\\cal D}$ to a lower-dimensional space using a _**filter function**_ $ f: \\mathbb{R}^n \\to \\mathbb{R}^m $. Common choices for the filter function include projection onto one or more axes via PCA or density-based methods. In giotto-tda, you can import a variety of filter functions as follows:\n", + "1. Map ${\\cal D}$ to a lower-dimensional space using a _**filter function**_ $ f: \\mathbb{R}^n \\to \\mathbb{R}^m $. Common choices for the filter function include projection onto one or more axes via PCA or density-based methods. In `giotto-tda`, you can import a variety of filter functions as follows:\n", "\n", "```python\n", "from gtda.mapper.filter import FilterFunctionName\n", @@ -102,7 +92,7 @@ "from gtda.mapper.cover import CoverName\n", "```\n", "\n", - "3. For each interval $U_i \\in {\\cal U}$ cluster the points in the preimage $f^{-1}(U_i)$ into sets $C_{i,1}, \\ldots , C_{i,k_i}$. The choice of clustering algorithm can be any of scikit-learn's [clustering methods](https://scikit-learn.org/stable/modules/clustering.html) or an implementation of agglomerative clustering in giotto-tda:\n", + "3. For each interval $U_i \\in {\\cal U}$ cluster the points in the preimage $f^{-1}(U_i)$ into sets $C_{i,1}, \\ldots , C_{i,k_i}$. The choice of clustering algorithm can be any of `scikit-learn`'s [clustering methods](https://scikit-learn.org/stable/modules/clustering.html) or an implementation of agglomerative clustering in `giotto-tda`:\n", "\n", "```python\n", "# scikit-learn method\n", @@ -111,9 +101,9 @@ "from gtda.mapper.cluster import FirstSimpleGap\n", "```\n", "\n", - "4. Construct the topological graph whose vertices are the cluster sets $(C_{i,j})_{i\\in I, j \\in \\{1,\\ldots,k_i\\}}$ and an edge exists between two nodes if they share points in common: $C_{i,j} \\cap C_{k,l} \\neq \\emptyset$. This step is handled automatically by giotto-tda.\n", + "4. Construct the topological graph whose vertices are the cluster sets $(C_{i,j})_{i\\in I, j \\in \\{1,\\ldots,k_i\\}}$ and an edge exists between two nodes if they share points in common: $C_{i,j} \\cap C_{k,l} \\neq \\emptyset$. This step is handled automatically by `giotto-tda`.\n", "\n", - "These four steps are implemented in the `MapperPipeline` object that mimics the `Pipeline` class from scikit-learn. We provide a convenience function `make_mapper_pipeline()` that allows you to pass the choice of filter function, cover, and clustering algorithm as arguments. For example, to project our data onto the $x$- and $y$-axes, we could setup the pipeline as follows:" + "These four steps are implemented in the `MapperPipeline` object that mimics the `Pipeline` class from `scikit-learn`. We provide a convenience function `make_mapper_pipeline()` that allows you to pass the choice of filter function, cover, and clustering algorithm as arguments. For example, to project our data onto the $x$- and $y$-axes, we could setup the pipeline as follows:" ] }, { @@ -153,7 +143,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "With the Mapper pipeline at hand, it is now a simple matter to visualise it. To warm up, let's examine the graph in two-dimensions using the default arguments of giotto-tda's plotting function:" + "With the Mapper pipeline at hand, it is now a simple matter to visualise it. To warm up, let's examine the graph in two-dimensions using the default arguments of `giotto-tda`'s plotting function:" ] }, { @@ -163,8 +153,7 @@ "outputs": [], "source": [ "fig = plot_static_mapper_graph(pipe, data)\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { @@ -192,15 +181,14 @@ "fig = plot_static_mapper_graph(\n", " pipe, data, color_by_columns_dropdown=True, plotly_kwargs=plotly_kwargs\n", ")\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In the dropdown menu, the entry `color_variable` refers to a user-defined quantity to color by - by default it is the average value of the points in each node. In general, one can configure this quantity to be an array, a scikit-learn transformer, or a list of indices to select from the data. For example, coloring by a PCA component can be implemented as follows:" + "In the dropdown menu, the entry `color_variable` refers to a user-defined quantity to color by - by default it is the average value of the points in each node. In general, one can configure this quantity to be an array, a `scikit-learn` transformer, or a list of indices to select from the data. For example, coloring by a PCA component can be implemented as follows:" ] }, { @@ -215,21 +203,15 @@ "fig = plot_static_mapper_graph(\n", " pipe, data, color_by_columns_dropdown=True, color_variable=pca\n", ")\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Pass a pandas DataFrame as input" + "fig.show(config={'scrollZoom': True})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ + "### Pass a pandas DataFrame as input\n", + "\n", "It is also possible to feed `plot_static_mapper_graph()` a pandas DataFrame:" ] }, @@ -266,8 +248,7 @@ "outputs": [], "source": [ "fig = plot_static_mapper_graph(pipe, data_df, color_by_columns_dropdown=True)\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { @@ -275,6 +256,7 @@ "metadata": {}, "source": [ "### Change the layout algorithm\n", + "\n", "By default, `plot_static_mapper_graph()` uses the Kamada–Kawai algorithm for the layout; however any of the layout algorithms defined in python-igraph are supported (see [here](https://igraph.org/python/doc/igraph.Graph-class.html) for a list of possible layouts). For example, we can switch to the Fruchterman–Reingold layout as follows:" ] }, @@ -285,7 +267,7 @@ "outputs": [], "source": [ "# Reset back to numpy projection\n", - "pipe.set_params(filter_func=Projection(columns=[0, 1]))" + "pipe.set_params(filter_func=Projection(columns=[0, 1]));" ] }, { @@ -297,8 +279,7 @@ "fig = plot_static_mapper_graph(\n", " pipe, data, layout=\"fruchterman_reingold\", color_by_columns_dropdown=True\n", ")\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { @@ -316,8 +297,7 @@ "outputs": [], "source": [ "fig = plot_static_mapper_graph(pipe, data, layout_dim=3, color_by_columns_dropdown=True)\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { @@ -325,7 +305,8 @@ "metadata": {}, "source": [ "## Run the Mapper pipeline\n", - "Behind the scenes of `plot_static_mapper_graph()` is a `MapperPipeline` object `pipe` that can be used like a typical scikit-learn estimator. For example, to extract the underlying graph data structure we can do the following:" + "\n", + "Behind the scenes of `plot_static_mapper_graph()` is a `MapperPipeline` object `pipe` that can be used like a typical `scikit-learn` estimator. For example, to extract the underlying graph data structure we can do the following:" ] }, { @@ -409,8 +390,7 @@ " color_by_columns_dropdown=True,\n", " plotly_kwargs=plotly_kwargs,\n", ")\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { @@ -425,7 +405,8 @@ "metadata": {}, "source": [ "## Creating custom filter functions\n", - "In some cases, the list of filter functions provided in `filter.py` or scikit-learn may not be sufficient for the task at hand. In such cases, one can pass any callable to the pipeline that acts _row-wise_ on the input data. For example, we can project by taking the sum of the $(x,y)$ coordinates as follows:" + "\n", + "In some cases, the list of filter functions provided in `gtda.mapper.filter.py` or `scikit-learn` may not be sufficient for the task at hand. In such cases, one can pass any callable to the pipeline that acts **row-wise** on the input data. For example, we can project by taking the sum of the $(x,y)$ coordinates as follows:" ] }, { @@ -452,23 +433,20 @@ "outputs": [], "source": [ "fig = plot_static_mapper_graph(pipe, data, plotly_kwargs=None)\n", - "# Display figure\n", - "fig.show(config={\"scrollZoom\": True})" + "fig.show(config={'scrollZoom': True})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In general, any callable (i.e. function) that operates **_row-wise_** can be passed." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Visualise the 2D Mapper graph interactively\n", - "In general, buidling useful Mapper graphs requires some iteration through the various parameters in the cover and clustering algorithm. To simplify that process, giotto-tda provides an interactive figure that can be configured in real-time. If invalid parameters are selected, the _Show logs_ checkbox can be used to see what went wrong." + "## Visualise the 2D Mapper graph interactively (Live Jupyter session needed)\n", + "\n", + "In general, building useful Mapper graphs requires some iteration through the various parameters in the cover and clustering algorithm. To simplify that process, `giotto-tda` provides an interactive figure that can be configured in real time.\n", + "\n", + "If invalid parameters are selected, the _Show logs_ checkbox can be used to see what went wrong.\n", + "\n", + "**To see the interactive output, please download the notebook from [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/mapper_quickstart.ipynb) and execute it locally.**" ] }, { @@ -479,7 +457,7 @@ "source": [ "pipe = make_mapper_pipeline()\n", "\n", - "# Generate interactive plot\n", + "# Generate interactive widget\n", "plot_interactive_mapper_graph(pipe, data, color_by_columns_dropdown=True)" ] }, diff --git a/examples/plotting_api.ipynb b/examples/plotting_api.ipynb new file mode 100644 index 000000000..107e73ef2 --- /dev/null +++ b/examples/plotting_api.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Plotting in `giotto-tda`\n", + "\n", + "`giotto-tda` includes a set of plotting functions and class methods, powered by `plotly`. The library's plotting API is designed to facilitate the exploration of intermediate results in pipelines by harnessing the highly visual nature of topological signatures.\n", + "\n", + "This notebook is a quick tutorial on how to use `giotto-tda`'s plotting functionalities and unified plotting API. The plotting functions in `gtda.mapper` are not covered here as they are somewhat tailored to the Mapper algorithm, see the [dedicated tutorial](https://giotto-ai.github.io/gtda-docs/dev/notebooks/mapper_quickstart.html).\n", + "\n", + "If you are looking at a static version of this notebook and would like to run its contents, head over to [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/plotting_api.ipynb).\n", + "\n", + "**License: AGPLv3**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Basic philosophy and `plot` methods" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The computational building blocks of `giotto-tda` are `scikit-learn`–style estimators. Typically, they are also transformers, i.e. they possess a `transform` and/or a `fit-transform` method which:\n", + "\n", + "- act on an array-like object `X` which collects a certain number of \"samples\" of a given kind;\n", + "- return a transformed array-like object `Xt` which collects a (potentially different) number of \"samples\" of a potentially different kind.\n", + "\n", + "The basic philosophy of `giotto-tda`'s class-level plotting API is to equip relevant transformers with `plot` methods taking two main arguments:\n", + "\n", + "- an object such as `Xt` above (i.e. consistent with the *outputs* of `transform` or `fit-transform`);\n", + "- an integer index passed via the `sample` keyword and indicating which sample in `Xt` should be plotted.\n", + "\n", + "In other words, `.plot(Xt, sample=i)` will produce a plot of `Xt[i]` which is tailored to the nature of the samples in `Xt`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plotting functions\n", + "\n", + "Several `plot` methods in `giotto-tda` actually fall back to specialised functions which can be found in the [plotting subpackage](https://giotto-ai.github.io/gtda-docs/dev/modules/pipeline.html) and which can be used directly instead. However, unless the additional degree of control is necessary, `plot` methods should be preferred as they often exploit class parameters and/or attributes (e.g. those computed during `fit`) to automatically fill some parameters in the corresponding functions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2 Example: Plotting persistence diagrams with `VietorisRipsPersistence`\n", + "\n", + "Let's take the example of `VietorisRipsPersistence` – a transformer also covered in [another notebook](https://giotto-ai.github.io/gtda-docs/dev/notebooks/vietoris_rips_quickstart.html). Let's create the input collection `X` for this transformer as a collection of randomly generated point clouds, each containing 100 points positioned along two circles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "np.random.seed(seed=42)\n", + "from gtda.homology import VietorisRipsPersistence\n", + "from sklearn.datasets import make_circles\n", + "\n", + "X = np.asarray([\n", + " make_circles(100, factor=np.random.random())[0]\n", + " for i in range(10)\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Incidentally, samples in `X` can be plotted using `gtda.plotting.plot_point_cloud`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from gtda.plotting import plot_point_cloud\n", + "i = 0\n", + "plot_point_cloud(X[i])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us instantiate a `VietorisRipsTransformer` object, and call the `fit-transform` method on `X` to obtain the transformed object `Xt`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "VR = VietorisRipsPersistence()\n", + "Xt = VR.fit_transform(X)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For any sample index i, `Xt[i]` is a two-dimensional array encoding the multi-scale topological information which can be extracted from the i-th point cloud `X[i]`.\n", + "\n", + "It is typically too difficult to get a quick idea of the interesting information contained in `Xt[i]` by looking at the array directly. This information is best displayed as a so-called \"persistence diagram\" in 2D. The `plot` method of our `VietorisRipsPersistence` instance achieves precisely this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "VR.plot(Xt, sample=i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the case of `VietorisRipsPersistence`, `plot` is a thin wrapper around the function `gtda.plotting.plot_diagram`, so the same result could have been achieved by importing that function and calling `plot_diagram(Xt[i])`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the diagram, each point indicates a topological feature in the data which appears at a certain \"birth\" scale and remains present all the way up to a later \"death\" scale. A point's distance from the diagonal is directly proportional to the difference between the point's \"death\" and its \"birth\". Hence, this distance visually communicates how \"persistent\" the associated topological feature is. Topological features are partitioned by dimension using colors: above, features in dimension 0 are red while those in dimension 1 are green. In dimension 0, the diagram describes connectivity structure in the data in a very similar way to linkage clustering: we see three points along the vertical axis, which are in one-to-one correspondence with \"merge\" events in the sense of hierarchical clustering. In dimension 1, the diagram describes the presence of \"independent\" one-dimensional holes in the data: as expected, there are only two significant points, corresponding to the two \"persistent\" circles." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Derived convenience methods: `transform_plot` and `fit_transform_plot`\n", + "\n", + "Where appropriate, `giotto-tda` transformers which have a `plot` method can also implement the two derived methods `transform_plot` and `fit_transform_plot`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.1 `transform_plot`\n", + "\n", + "This method takes two main arguments:\n", + "\n", + "- an object such as `X` above (i.e. consistent with the *inputs* of `transform` or `fit-transform`);\n", + "- an integer index i passed via the `sample` keyword.\n", + "\n", + "The logic of `transform_plot` can be roughly described as follows: first, the sample `X[i]` is transformed; then, the result is plotted using `plot` and returned. [More technically: we first create a trivial collection `X_sing = [X[i]]`, which contains a single sample from `X`. Then, we compute `Xt_sing = .transform(X_sing)`. Assuming `Xt_sing` contains a single transformed sample, we call `.plot(Xt_sing, sample=0)`, and also return `Xt_sing`.]\n", + "\n", + "In the example of Section 1.2, we would do:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "VR = VietorisRipsPersistence()\n", + "VR.fit(X)\n", + "VR.transform_plot(X, sample=i);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.2 `fit_transform_plot`\n", + "\n", + "This method is equivalent to first fitting the transformer using `X` (and, optionally, a target variable `y`), and then calling `transform_plot` on `X` and a given sample index.\n", + "\n", + "The workflow in the example of Section 1.2 can be simplified even further, turning the entire process into a simple one-liner:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "VR = VietorisRipsPersistence()\n", + "VR.fit_transform_plot(X, sample=i);" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/vietoris_rips_quickstart.ipynb b/examples/vietoris_rips_quickstart.ipynb index 116c28f9a..50359bfa4 100644 --- a/examples/vietoris_rips_quickstart.ipynb +++ b/examples/vietoris_rips_quickstart.ipynb @@ -4,9 +4,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Topological feature extraction using VietorisRips and PersistenceEntropy\n", + "# Topological feature extraction using `VietorisRipsPersistence` and `PersistenceEntropy`\n", "\n", - "In this notebook, we showcase the ease of use of one of the core components of `giotto-tda`: VietorisRipsPersistence, alongwith vectorisation methods. We first list steps in a typical, topological-feature extraction routine and then show to encapsulate them with a standard `scikit-learn`–like pipeline." + "In this notebook, we showcase the ease of use of one of the core components of `giotto-tda`: `VietorisRipsPersistence`, along with vectorisation methods. We first list steps in a typical, topological-feature extraction routine and then show to encapsulate them with a standard `scikit-learn`–like pipeline.\n", + "\n", + "If you are looking at a static version of this notebook and would like to run its contents, head over to [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/vietoris_rips_quickstart.ipynb).\n", + "\n", + "**License: AGPLv3**" ] }, { @@ -25,9 +29,7 @@ "from gtda.diagrams import PersistenceEntropy\n", "from gtda.homology import VietorisRipsPersistence\n", "from sklearn.ensemble import RandomForestClassifier\n", - "from sklearn.model_selection import train_test_split\n", - "\n", - "from datasets import generate_point_clouds" + "from sklearn.model_selection import train_test_split" ] }, { @@ -35,7 +37,8 @@ "metadata": {}, "source": [ "## Generate data\n", - "Let's begin by generating 3D point clouds of spheres and tori, along with a label of 0 (1) for each sphere (torus). We also add noise to each point cloud, whose effect is to displace the points sampling the surfaces by a random amount in a random direction:" + "\n", + "Let's begin by generating 3D point clouds of spheres and tori, along with a label of 0 (1) for each sphere (torus). We also add noise to each point cloud, whose effect is to displace the points sampling the surfaces by a random amount in a random direction. **Note**: You will need the auxiliary module [datasets.py](https://github.com/giotto-ai/giotto-tda/blob/master/examples/datasets.py) to run this cell." ] }, { @@ -44,6 +47,7 @@ "metadata": {}, "outputs": [], "source": [ + "from datasets import generate_point_clouds\n", "point_clouds, labels = generate_point_clouds(100, 10, 0.1)" ] }, @@ -52,7 +56,8 @@ "metadata": {}, "source": [ "## Calculate persistent homology\n", - "Instantiate a VietorisRipsPersistence transformer and calculate persistence diagrams for this collection of point clouds." + "\n", + "Instantiate a `VietorisRipsPersistence` transformer and calculate persistence diagrams for this collection of point clouds." ] }, { @@ -70,8 +75,8 @@ "metadata": {}, "source": [ "## Extract features\n", - "Instantiate a PersistenceEntropy transformer and extract features\n", - "from the persistence diagrams." + "\n", + "Instantiate a `PersistenceEntropy` transformer and extract features from the persistence diagrams." ] }, { @@ -89,7 +94,8 @@ "metadata": {}, "source": [ "## Use the new features in a standard classifier\n", - "Leverage the compatibility with scikit-learn to perform a train-test split and score the features." + "\n", + "Leverage the compatibility with `scikit-learn` to perform a train-test split and score the features." ] }, { @@ -109,6 +115,7 @@ "metadata": {}, "source": [ "## Encapsulates the steps above in a pipeline\n", + "\n", "Subdivide into train-validation first, and use the pipeline." ] }, @@ -126,7 +133,8 @@ "metadata": {}, "source": [ "## Define the pipeline\n", - "Chain transformers from giotto-tda with scikit-learn ones." + "\n", + "Chain transformers from `giotto-tda` with `scikit-learn` ones." ] }, { @@ -200,7 +208,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.1" + "version": "3.7.6" } }, "nbformat": 4, diff --git a/examples/voids_on_the_plane.ipynb b/examples/voids_on_the_plane.ipynb index 67d2a4f87..52ee302db 100644 --- a/examples/voids_on_the_plane.ipynb +++ b/examples/voids_on_the_plane.ipynb @@ -10,6 +10,8 @@ "Challenge question: **Can two-dimensional topological voids arise from point clouds in two-dimensional space?**\n", "We will answer this question programmatically by computing Vietoris–Rips persistence homology of random point clouds in the square $[0, 1] \\times [0, 1] \\subset \\mathbb{R}^2$.\n", "\n", + "If you are looking at a static version of this notebook and would like to run its contents, head over to [github](https://github.com/giotto-ai/giotto-tda/blob/master/examples/voids_on_the_plane.ipynb).\n", + "\n", "**License: AGPLv3**" ] }, @@ -27,10 +29,12 @@ "outputs": [], "source": [ "import numpy as np\n", - "from gtda.homology import VietorisRipsPersistence as VR\n", + "from gtda.homology import VietorisRipsPersistence\n", "import itertools\n", "\n", - "import matplotlib.pyplot as plt" + "import matplotlib.pyplot as plt\n", + "\n", + "np.random.seed(1) # Set numpy's random seed" ] }, { @@ -39,10 +43,8 @@ "metadata": {}, "outputs": [], "source": [ - "# Initializing the Vietoris–Rips transformer\n", - "vr = VR(homology_dimensions=(2,), max_edge_length=np.inf)\n", - "n_samples = 15000\n", - "n_points = 6" + "# Initialize the Vietoris–Rips transformer\n", + "VR = VietorisRipsPersistence(homology_dimensions=(2,), max_edge_length=np.inf)" ] }, { @@ -52,9 +54,12 @@ "outputs": [], "source": [ "# Create n_samples point clouds of n_points points\n", - "PCS = np.random.random((n_samples, n_points, 2)) \n", + "n_samples = 15000\n", + "n_points = 6\n", + "point_clouds = np.random.random((n_samples, n_points, 2))\n", + "\n", "# Compute persistence diagrams of all point clouds\n", - "DGMS = vr.fit_transform(PCS) " + "diags = VR.fit_transform(point_clouds) " ] }, { @@ -63,10 +68,10 @@ "metadata": {}, "outputs": [], "source": [ - "diffs = np.nan_to_num(DGMS[:, :, 1] - DGMS[:, :, 0]) # Compute lifetimes\n", + "diffs = np.nan_to_num(diags[:, :, 1] - diags[:, :, 0]) # Compute lifetimes\n", "indices = np.argwhere(diffs != 0) # Indices with non-zero lifetime\n", - "print('There are {} persistent homology classes in dimension 2 across all samples!'.format(len(indices[:, 0])))\n", - "print('There are {} different point clouds with at least one persistent homology class in dimension 2.'.format(len(np.unique(indices[:, 0]))))" + "print(f'There are {len(indices[:, 0])} persistent homology classes in dimension 2 across all samples.')\n", + "print(f'There are {len(np.unique(indices[:, 0]))} different point clouds with at least one persistent homology class in dimension 2.')" ] }, { @@ -84,19 +89,12 @@ "outputs": [], "source": [ "for i in indices[:, 0]:\n", - " for e in itertools.combinations(PCS[i], 2):\n", - " if np.linalg.norm(e[0] - e[1]) < DGMS[i, 0, 1] - 0.00001:\n", + " for e in itertools.combinations(point_clouds[i], 2):\n", + " if np.linalg.norm(e[0] - e[1]) < diags[i, 0, 1] - 0.00001:\n", " edge = np.stack([e[0], e[1]])\n", " plt.plot(edge[:, 0], edge[:, 1])\n", " plt.show()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -115,7 +113,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.1" } }, "nbformat": 4, diff --git a/gtda/diagrams/distance.py b/gtda/diagrams/distance.py index 184c3b6cf..32c45fd6f 100644 --- a/gtda/diagrams/distance.py +++ b/gtda/diagrams/distance.py @@ -16,7 +16,7 @@ @adapt_fit_transform_docs class PairwiseDistance(BaseEstimator, TransformerMixin): - """:ref:`Distances ` between pairs + """:ref:`Distances ` between pairs of persistence diagrams. Given two collections of persistence diagrams consisting of diff --git a/gtda/diagrams/features.py b/gtda/diagrams/features.py index ab4deb490..3d10db805 100644 --- a/gtda/diagrams/features.py +++ b/gtda/diagrams/features.py @@ -18,7 +18,7 @@ @adapt_fit_transform_docs class PersistenceEntropy(BaseEstimator, TransformerMixin): - """:ref:`Persistence entropies ` of persistence + """:ref:`Persistence entropies ` of persistence diagrams. Given a persistence diagrams consisting of birth-death-dimension triples diff --git a/gtda/diagrams/representations.py b/gtda/diagrams/representations.py index 2b8ab1657..f59329895 100644 --- a/gtda/diagrams/representations.py +++ b/gtda/diagrams/representations.py @@ -28,12 +28,12 @@ def identity(x): @adapt_fit_transform_docs class BettiCurve(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Betti curves ` of persistence diagrams. + """:ref:`Betti curves ` of persistence diagrams. Given a persistence diagram consisting of birth-death-dimension triples [b, d, q], subdiagrams corresponding to distinct homology dimensions are considered separately, and their respective Betti curves are obtained by - evenly sampling the :ref:`filtration parameter `. + evenly sampling the :ref:`filtration parameter `. Parameters ---------- @@ -230,14 +230,14 @@ def plot(self, Xt, sample=0, homology_dimensions=None): @adapt_fit_transform_docs class PersistenceLandscape(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Persistence landscapes ` of persistence + """:ref:`Persistence landscapes ` of persistence diagrams. Given a persistence diagram consisting of birth-death-dimension triples [b, d, q], subdiagrams corresponding to distinct homology dimensions are considered separately, and layers of their respective persistence landscapes are obtained by evenly sampling the :ref:`filtration parameter - `. + `. Parameters ---------- @@ -460,7 +460,7 @@ class HeatKernel(BaseEstimator, TransformerMixin, PlotterMixin): distinct homology dimensions are considered separately and regarded as sums of Dirac deltas. Then, the convolution with a Gaussian kernel is computed over a rectangular grid of locations evenly sampled from appropriate - ranges of the :ref:`filtration parameter `. The + ranges of the :ref:`filtration parameter `. The same is done with the reflected images of the subdiagrams about the diagonal, and the difference between the results of the two convolutions is computed. The result can be thought of as a (multi-channel) raster image. @@ -634,7 +634,7 @@ def plot(self, Xt, sample=0, homology_dimension_ix=0, @adapt_fit_transform_docs class PersistenceImage(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Persistence images ` of persistence + """:ref:`Persistence images ` of persistence diagrams. Based on ideas in [1]_. Given a persistence diagram consisting of @@ -644,7 +644,7 @@ class PersistenceImage(BaseEstimator, TransformerMixin, PlotterMixin): separately and regarded as sums of Dirac deltas. Then, the convolution with a Gaussian kernel is computed over a rectangular grid of locations evenly sampled from appropriate ranges of the :ref:`filtration parameter - `. The result can be thought of as a (multi-channel) + `. The result can be thought of as a (multi-channel) raster image. Parameters @@ -846,7 +846,7 @@ def plot(self, Xt, sample=0, homology_dimension_ix=0, colorscale='blues'): @adapt_fit_transform_docs class Silhouette(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Power-weighted silhouettes ` of persistence + """:ref:`Power-weighted silhouettes ` of persistence diagrams. Based on ideas in [1]_. Given a persistence diagram consisting of @@ -854,13 +854,13 @@ class Silhouette(BaseEstimator, TransformerMixin, PlotterMixin): distinct homology dimensions are considered separately, and their respective silhouette by sampling the silhouette function over evenly spaced locations from appropriate ranges of the :ref:`filtration parameter - `. + `. Parameters ---------- power: float, optional, default: ``1.`` The power to which persistence values are raised to define the - :ref:`power-weighted silhouettes `. + :ref:`power-weighted silhouettes `. n_bins : int, optional, default: ``100`` The number of filtration parameter values, per available homology diff --git a/gtda/homology/cubical.py b/gtda/homology/cubical.py index c0de03539..b7cf4ec82 100644 --- a/gtda/homology/cubical.py +++ b/gtda/homology/cubical.py @@ -17,12 +17,12 @@ class CubicalPersistence(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Persistence diagrams ` resulting from - :ref:`filtered cubical complexes `. + """:ref:`Persistence diagrams ` resulting from + :ref:`filtered cubical complexes `. - Given a :ref:`greyscale image `, + Given a :ref:`greyscale image `, information about the appearance and disappearance of topological features - (technically, :ref:`homology classes `) of various + (technically, :ref:`homology classes `) of various dimensions and at different scales is summarised in the corresponding persistence diagram. diff --git a/gtda/homology/simplicial.py b/gtda/homology/simplicial.py index af787ec91..8582924ae 100644 --- a/gtda/homology/simplicial.py +++ b/gtda/homology/simplicial.py @@ -21,15 +21,16 @@ @adapt_fit_transform_docs class VietorisRipsPersistence(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Persistence diagrams ` resulting from - :ref:`Vietoris–Rips filtrations `. - - Given a :ref:`point cloud ` in - Euclidean space, or an abstract :ref:`metric space ` encoded by a distance matrix, information about the - appearance and disappearance of topological features (technically, - :ref:`homology classes `) of various dimension + """:ref:`Persistence diagrams ` resulting from + :ref:`Vietoris–Rips filtrations + `. + + Given a :ref:`point cloud ` in + Euclidean space, or an abstract + :ref:`metric space ` encoded by a + distance matrix, information about the appearance and disappearance of + topological features (technically, + :ref:`homology classes `) of various dimension and at different scales is summarised in the corresponding persistence diagram. @@ -250,15 +251,16 @@ def plot(Xt, sample=0, homology_dimensions=None): @adapt_fit_transform_docs class SparseRipsPersistence(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Persistence diagrams ` resulting from - :ref:`Sparse Vietoris–Rips filtrations `. - - Given a :ref:`point cloud ` in - Euclidean space, or an abstract :ref:`metric space ` encoded by a distance matrix, information about the - appearance and disappearance of topological features (technically, - :ref:`homology classes `) of various dimensions + """:ref:`Persistence diagrams ` resulting from + :ref:`Sparse Vietoris–Rips filtrations + `. + + Given a :ref:`point cloud ` in + Euclidean space, or an abstract + :ref:`metric space ` + encoded by a distance matrix, information about the appearance and + disappearance of topological features (technically, + :ref:`homology classes `) of various dimensions and at different scales is summarised in the corresponding persistence diagram. @@ -495,14 +497,15 @@ def plot(Xt, sample=0, homology_dimensions=None): @adapt_fit_transform_docs class EuclideanCechPersistence(BaseEstimator, TransformerMixin, PlotterMixin): - """:ref:`Persistence diagrams ` resulting from - `Cech filtrations <>`_. + """:ref:`Persistence diagrams ` resulting from + `Cech filtrations `_. - Given a :ref:`point cloud ` in + Given a :ref:`point cloud ` in Euclidean space, information about the appearance and disappearance of - topological features (technically, :ref:`homology classes `) of various dimensions and at different scales is - summarised in the corresponding persistence diagram. + topological features (technically, + :ref:`homology classes `) of various dimensions + and at different scales is summarised in the corresponding persistence + diagram. Parameters ---------- diff --git a/gtda/images/filtrations.py b/gtda/images/filtrations.py index 5c73134de..3dee178dc 100644 --- a/gtda/images/filtrations.py +++ b/gtda/images/filtrations.py @@ -40,7 +40,6 @@ class HeightFiltration(BaseEstimator, TransformerMixin, PlotterMixin): dimension of the images of the collection (2 or 3). ``None`` is equivalent to passing ``numpy.ones(n_dimensions)``. - n_jobs : int or None, optional, default: ``None`` The number of jobs to use for the computation. ``None`` means 1 unless in a :obj:`joblib.parallel_backend` context. ``-1`` means using all @@ -51,14 +50,14 @@ class HeightFiltration(BaseEstimator, TransformerMixin, PlotterMixin): n_dimensions_ : ``2`` or ``3`` Dimension of the images. Set in :meth:`fit`. - direction_ : ndarray of shape (n_dimensions_,) + direction_ : ndarray of shape (:attr:`n_dimensions_`,) Effective direction of the height filtration. Set in :meth:`fit`. mesh_ : ndarray of shape ( n_pixels_x, n_pixels_y [, n_pixels_z]) greyscale image corresponding to the height filtration of a binary image where each pixel is activated. Set in :meth:`fit`. - max_value_: float + max_value_ : float Maximum pixel value among all pixels in all images of the collection. Set in :meth:`fit`. @@ -68,10 +67,10 @@ class HeightFiltration(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ @@ -222,11 +221,11 @@ class RadialFiltration(BaseEstimator, TransformerMixin, PlotterMixin): Parameters ---------- - center : ndarray of shape (n_dimensions,) or None, optional, default: \ - ``None`` + center : ndarray of shape (:attr:`n_dimensions_`,) or None, optional,\ + default: ``None`` Coordinates of the center pixel, where ``n_dimensions`` is the dimension of the images of the collection (2 or 3). ``None`` is - equivalent to passing ``np.zeros(n_dimensions,)``. + equivalent to passing ``np.zeros(n_dimensions,)```. radius : float or None, default: ``None`` The radius of the ball centered in `center` inside which activated @@ -260,7 +259,7 @@ class RadialFiltration(BaseEstimator, TransformerMixin, PlotterMixin): n_dimensions_ : ``2`` or ``3`` Dimension of the images. Set in :meth:`fit`. - center_ : ndarray of shape (n_dimensions_,) + center_ : ndarray of shape (:attr:`n_dimensions_`,) Effective center of the radial filtration. Set in :meth:`fit`. effective_metric_params_ : dict @@ -272,7 +271,7 @@ class RadialFiltration(BaseEstimator, TransformerMixin, PlotterMixin): greyscale image corresponding to the radial filtration of a binary image where each pixel is activated. Set in :meth:`fit`. - max_value_: float + max_value_ : float Maximum pixel value among all pixels in all images of the collection. Set in :meth:`fit`. @@ -282,10 +281,10 @@ class RadialFiltration(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ @@ -472,7 +471,7 @@ class DilationFiltration(BaseEstimator, TransformerMixin, PlotterMixin): Effective number of iterations in the dilation process. Set in :meth:`fit`. - max_value_: float + max_value_ : float Maximum pixel value among all pixels in all images of the collection. Set in :meth:`fit`. @@ -482,10 +481,10 @@ class DilationFiltration(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ @@ -645,7 +644,7 @@ class ErosionFiltration(BaseEstimator, TransformerMixin, PlotterMixin): Effective number of iterations in the erosion process. Set in :meth:`fit`. - max_value_: float + max_value_ : float Maximum pixel value among all pixels in all images of the collection. Set in :meth:`fit`. @@ -655,10 +654,10 @@ class ErosionFiltration(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ @@ -820,7 +819,7 @@ class SignedDistanceFiltration(BaseEstimator, TransformerMixin, PlotterMixin): Effective number of iterations in the dilation process. Set in :meth:`fit`. - max_value_: float + max_value_ : float Maximum pixel value among all pixels in all images of the collection. Set in :meth:`fit`. @@ -831,10 +830,10 @@ class SignedDistanceFiltration(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ diff --git a/gtda/images/preprocessing.py b/gtda/images/preprocessing.py index 3f481609e..2f40b5276 100644 --- a/gtda/images/preprocessing.py +++ b/gtda/images/preprocessing.py @@ -37,7 +37,7 @@ class Binarizer(BaseEstimator, TransformerMixin, PlotterMixin): n_dimensions_ : int Dimension of the images. Set in meth:`fit`. - max_value_: float + max_value_ : float Maximum pixel value among all pixels in all images of the collection. Set in meth:`fit`. @@ -47,10 +47,10 @@ class Binarizer(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ @@ -179,10 +179,10 @@ class Inverter(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: \ + Classification of MNIST using TDA"; 19th International \ + IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ + 2019; arXiv: `1910.08345 `_. """ @@ -303,10 +303,10 @@ class Padder(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ @@ -461,10 +461,10 @@ class ImageToPointCloud(BaseEstimator, TransformerMixin, PlotterMixin): References ---------- - .. [1] A. Garin and G. Tauzin, "A topological reading lesson: \ - Classification of MNIST using TDA"; 19th International \ - IEEE Conference on Machine Learning and Applications (ICMLA 2020), \ - 2019; arXiv: `1910.08345 `_. + [1] A. Garin and G. Tauzin, "A topological reading lesson: Classification + of MNIST using TDA"; 19th International IEEE Conference on Machine + Learning and Applications (ICMLA 2020), 2019; arXiv: `1910.08345 \ + `_. """ diff --git a/gtda/time_series/embedding.py b/gtda/time_series/embedding.py index 0de97c60e..6c37a7870 100644 --- a/gtda/time_series/embedding.py +++ b/gtda/time_series/embedding.py @@ -206,7 +206,7 @@ class TakensEmbedding(BaseEstimator, TransformerResamplerMixin): of evenly sampled times :math:`t_0, t_1, \\ldots`, one extracts a set of :math:`d`-dimensional vectors of the form :math:`(X_{t_i}, X_{t_i + \\tau}, \\ldots , X_{t_i + (d-1)\\tau})` for :math:`i = 0, 1, \\ldots`. - This set is called the :ref:`Takens embedding ` + This set is called the :ref:`Takens embedding ` of the time series and can be interpreted as a point cloud. The difference between :math:`t_{i+1}` and :math:`t_i` is called the