Repository: gsp-eeg/PyGSP2 (language: python)

Issue:
28 move metro utils out of the examples folder



Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 6e7ac06f..7d707345 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,7 @@ develop-eggs
 *.geojson
 *.xlsb
 *.mp4
-santiago_metro_stations_connections.txt
+#santiago_metro_stations_connections.txt
 
 # Results from examples
 examples/metro_simulation
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 4a4ebf8f..db4814ce 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -1,5 +1,10 @@
 version: 2
 
+build:
+  os: ubuntu-22.04
+  tools:
+    python: "3.11"
+
 formats:
   - htmlzip
 
diff --git a/.zenodo.json b/.zenodo.json
index 95d305fe..afc94656 100644
--- a/.zenodo.json
+++ b/.zenodo.json
@@ -1,6 +1,6 @@
 {
-	"title": "PyGSP: Graph Signal Processing in Python",
-	"description": "The PyGSP facilitates a wide variety of operations on graphs, like computing their Fourier basis, filtering or interpolating signals, plotting graphs, signals, and filters.",
+	"title": "PyGSP2: Graph Signal Processing in Python",
+	"description": "The PyGSP2 facilitates a wide variety of operations on graphs, like computing their Fourier basis, filtering or interpolating signals, plotting graphs, signals, and filters.",
 	"upload_type": "software",
 	"license": "BSD-3-Clause",
 	"access_right": "open",
@@ -27,7 +27,7 @@
 	"related_identifiers": [
 		{
 			"scheme": "url",
-			"identifier": "https://github.com/epfl-lts2/pygsp",
+			"identifier": "https://github.com/gsp-eeg/pygsp2",
 			"relation": "isSupplementTo"
 		},
 		{
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 9fa2efdd..bedc9269 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -3,26 +3,26 @@ Contributing
 ============
 
 Contributions are welcome, and they are greatly appreciated! The development of
-this package takes place on `GitHub <https://github.com/epfl-lts2/pygsp>`_.
+this package takes place on `GitHub <https://github.com/gsp-eeg/pygsp2>`_.
 Issues, bugs, and feature requests should be reported `there
-<https://github.com/epfl-lts2/pygsp/issues>`_.
+<https://github.com/gsp-eeg/pygsp2/issues>`_.
 Code and documentation can be improved by submitting a `pull request
-<https://github.com/epfl-lts2/pygsp/pulls>`_. Please add documentation and
+<https://github.com/gsp-eeg/pygsp2/pulls>`_. Please add documentation and
 tests for any new code.
 
 The package can be set up (ideally in a fresh virtual environment) for local
 development with the following::
 
-    $ git clone https://github.com/epfl-lts2/pygsp.git
-    $ pip install --upgrade --editable pygsp[dev]
+    $ git clone https://github.com/gsp-eeg/pygsp2.git
+    $ pip install --upgrade --editable pygsp2[dev]
 
 The ``dev`` "extras requirement" ensures that dependencies required for
 development (to run the test suite and build the documentation) are installed.
 Only `graph-tool <https://graph-tool.skewed.de>`_ will be missing: install it
 manually as it cannot be installed by pip.
 
-You can improve or add functionality in the ``pygsp`` folder, along with
-corresponding unit tests in ``pygsp/tests/test_*.py`` (with reasonable
+You can improve or add functionality in the ``pygsp2`` folder, along with
+corresponding unit tests in ``pygsp2/tests/test_*.py`` (with reasonable
 coverage).
 If you have a nice example to demonstrate the use of the introduced
 functionality, please consider adding a tutorial in ``doc/tutorials`` or a
@@ -43,34 +43,31 @@ tests reasonably cover the changes you've introduced.
 To iterate faster, you can partially run the test suite, at various degrees of
 granularity, as follows::
 
-   $ python -m unittest pygsp.tests.test_docstrings.suite_reference
-   $ python -m unittest pygsp.tests.test_graphs.TestImportExport
-   $ python -m unittest pygsp.tests.test_graphs.TestImportExport.test_save_load
+   $ python -m unittest pygsp2.tests.test_docstrings.suite_reference
+   $ python -m unittest pygsp2.tests.test_graphs.TestImportExport
+   $ python -m unittest pygsp2.tests.test_graphs.TestImportExport.test_save_load
 
 Making a release
 ----------------
 
 #. Update the version number and release date in ``setup.py``,
-   ``pygsp/__init__.py`` and ``CHANGELOG.rst``.
-#. Create a git tag with ``git tag -a v0.5.0 -m "PyGSP v0.5.0"``.
+   ``pygsp2/__init__.py`` and ``CHANGELOG.rst``.
+#. Create a git tag with ``git tag -a v0.5.0 -m "PyGSP2 v0.5.0"``.
 #. Push the tag to GitHub with ``git push github v0.5.0``. The tag should now
    appear in the releases and tags tab.
-#. `Create a release <https://github.com/epfl-lts2/pygsp/releases/new>`_ on
+#. `Create a release <https://github.com/gsp-eeg/pygsp2/releases/new>`_ on
    GitHub and select the created tag. A DOI should then be issued by Zenodo.
 #. Go on Zenodo and fix the metadata if necessary.
 #. Build the distribution with ``make dist`` and check that the
-   ``dist/PyGSP-0.5.0.tar.gz`` source archive contains all required files. The
-   binary wheel should be found as ``dist/PyGSP-0.5.0-py2.py3-none-any.whl``.
+   ``dist/PyGSP2-0.5.0.tar.gz`` source archive contains all required files. The
+   binary wheel should be found as ``dist/PyGSP2-0.5.0-py2.py3-none-any.whl``.
 #. Test the upload and installation process::
 
     $ twine upload --repository-url https://test.pypi.org/legacy/ dist/*
-    $ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple pygsp
+    $ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple pygsp2
 
    Log in as the LTS2 user.
 #. Build and upload the distribution to the real PyPI with ``make release``.
-#. Update the conda feedstock (at least the version number and sha256 in
-   ``recipe/meta.yaml``) by sending a PR to
-   `conda-forge <https://github.com/conda-forge/pygsp-feedstock>`_.
 
 Repository organization
 -----------------------
@@ -84,11 +81,11 @@ Repository organization
   .gitignore          Files ignored by the git revision control system
   .travis.yml         Defines testing on Travis continuous integration
 
-  pygsp/              Contains the modules (the actual toolbox implementation)
+  pygsp2/              Contains the modules (the actual toolbox implementation)
    __init.py__        Load modules at package import
    *.py               One file per module
 
-  pygsp/tests/        Contains the test suites (will be distributed to end user)
+  pygsp2/tests/        Contains the test suites (will be distributed to end user)
    __init.py__        Load modules at package import
    test_*.py          One test suite per module
    test_docstrings.py Test the examples in the docstrings (reference doc)
diff --git a/LICENSE.txt b/LICENSE.txt
index 77b5b51b..fabc97a2 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -11,7 +11,7 @@ modification, are permitted provided that the following conditions are met:
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 
-* Neither the name of PyGSP nor the names of its contributors may be used
+* Neither the name of PyGSP2 nor the names of its contributors may be used
   to endorse or promote products derived from this software without specific
   prior written permission.
 
diff --git a/Makefile b/Makefile
index 343e8517..1e875089 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ export DISPLAY = :99
 
 test:
 	Xvfb $$DISPLAY -screen 0 800x600x24 &
-	coverage run --branch --source pygsp setup.py test
+	coverage run --branch --source pygsp2 setup.py test
 	coverage report
 	coverage html
 	killall Xvfb
diff --git a/README.rst b/README.rst
index eeb92d8b..23a0d9af 100644
--- a/README.rst
+++ b/README.rst
@@ -1,45 +1,33 @@
-========================================
-PyGSP: Graph Signal Processing in Python
-========================================
+=========================================
+PyGSP2: Graph Signal Processing in Python
+=========================================
 
-The PyGSP is a Python package to ease
+The PyGSP2 is a Python package to ease
 `Signal Processing on Graphs <https://arxiv.org/abs/1211.0053>`_.
 The documentation is available on
-`Read the Docs <https://pygsp.readthedocs.io>`_
+`Read the Docs <https://pygsp2.readthedocs.io>`_
 and development takes place on
-`GitHub <https://github.com/epfl-lts2/pygsp>`_.
+`GitHub <https://github.com/gsp-eeg/pygsp2>`_.
 A (mostly unmaintained) `Matlab version <https://epfl-lts2.github.io/gspbox-html>`_ exists.
 
 +-----------------------------------+
-| |doc|  |pypi|  |conda|  |binder|  |
+| |doc|  |pypi|                     |
 +-----------------------------------+
 | |zenodo|  |license|  |pyversions| |
 +-----------------------------------+
-| |travis|  |coveralls|  |github|   |
-+-----------------------------------+
 
-.. |doc| image:: https://readthedocs.org/projects/pygsp/badge/?version=latest
-   :target: https://pygsp.readthedocs.io
-.. |pypi| image:: https://img.shields.io/pypi/v/pygsp.svg
-   :target: https://pypi.org/project/PyGSP
+.. |doc| image:: https://readthedocs.org/projects/pygsp2/badge/?version=latest
+   :target: https://pygsp2.readthedocs.io
+.. |pypi| image:: https://img.shields.io/pypi/v/pygsp2.svg
+   :target: https://pypi.org/project/PyGSP2
 .. |zenodo| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.1003157.svg
    :target: https://doi.org/10.5281/zenodo.1003157
-.. |license| image:: https://img.shields.io/pypi/l/pygsp.svg
-   :target: https://github.com/epfl-lts2/pygsp/blob/master/LICENSE.txt
-.. |pyversions| image:: https://img.shields.io/pypi/pyversions/pygsp.svg
-   :target: https://pypi.org/project/PyGSP
-.. |travis| image:: https://img.shields.io/travis/com/epfl-lts2/pygsp.svg
-   :target: https://app.travis-ci.com/github/epfl-lts2/pygsp
-.. |coveralls| image:: https://img.shields.io/coveralls/github/epfl-lts2/pygsp.svg
-   :target: https://coveralls.io/github/epfl-lts2/pygsp
-.. |github| image:: https://img.shields.io/github/stars/epfl-lts2/pygsp.svg?style=social
-   :target: https://github.com/epfl-lts2/pygsp
-.. |binder| image:: https://static.mybinder.org/badge_logo.svg
-   :target: https://mybinder.org/v2/gh/epfl-lts2/pygsp/master?urlpath=lab/tree/examples/playground.ipynb
-.. |conda| image:: https://img.shields.io/conda/vn/conda-forge/pygsp.svg
-   :target: https://anaconda.org/conda-forge/pygsp
-
-The PyGSP facilitates a wide variety of operations on graphs, like computing
+.. |license| image:: https://img.shields.io/pypi/l/pygsp2.svg
+   :target: https://github.com/gsp-eeg/pygsp2/blob/master/LICENSE.txt
+.. |pyversions| image:: https://img.shields.io/pypi/pyversions/pygsp2.svg
+   :target: https://pypi.org/project/PyGSP2
+
+The PyGSP2 facilitates a wide variety of operations on graphs, like computing
 their Fourier basis, filtering or interpolating signals, plotting graphs,
 signals, and filters. Its core is spectral graph theory, and many of the
 provided operations scale to very large graphs. The package includes a wide
@@ -54,7 +42,7 @@ can easily use a custom graph by defining its adjacency matrix, and a custom
 filter bank by defining a set of functions in the spectral domain.
 
 While NetworkX_ and graph-tool_ are tools to analyze the topology of graphs,
-the aim of the PyGSP is to analyze graph signals, also known as features or
+the aim of the PyGSP2 is to analyze graph signals, also known as features or
 properties (i.e., not the graph itself).
 Those three tools are complementary and work well together with the provided
 import / export facility.
@@ -65,16 +53,14 @@ import / export facility.
 The following demonstrates how to instantiate a graph and a filter, the two
 main objects of the package.
 
->>> from pygsp import graphs, filters
+>>> from pygsp2 import graphs, filters
 >>> G = graphs.Logo()
 >>> G.compute_fourier_basis()  # Fourier to plot the eigenvalues.
 >>> # G.estimate_lmax() is otherwise sufficient.
 >>> g = filters.Heat(G, scale=50)
 >>> fig, ax = g.plot()
 
-.. image:: ../pygsp/data/readme_example_filter.png
-    :alt:
-.. image:: pygsp/data/readme_example_filter.png
+.. image:: ../pygsp2/data/readme_example_filter.png
     :alt:
 
 Let's now create a graph signal: a set of three Kronecker deltas for that
@@ -89,35 +75,23 @@ structure!
 >>> s = g.filter(s)
 >>> fig, ax = G.plot(s, highlight=DELTAS)
 
-.. image:: ../pygsp/data/readme_example_graph.png
-    :alt:
-.. image:: pygsp/data/readme_example_graph.png
+.. image:: ../pygsp2/data/readme_example_graph.png
     :alt:
 
 You can
-`try it online <https://mybinder.org/v2/gh/epfl-lts2/pygsp/master?urlpath=lab/tree/examples/playground.ipynb>`_,
+`try it online <https://mybinder.org/v2/gh/epfl-lts2/pygsp2/master?urlpath=lab/tree/examples/playground.ipynb>`_,
 look at the
-`tutorials <https://pygsp.readthedocs.io/en/stable/tutorials/index.html>`_
+`tutorials <https://pygsp2.readthedocs.io/en/stable/tutorials/index.html>`_
 to learn how to use it, or look at the
-`reference guide <https://pygsp.readthedocs.io/en/stable/reference/index.html>`_
+`reference guide <https://pygsp2.readthedocs.io/en/stable/reference/index.html>`_
 for an exhaustive documentation of the API. Enjoy!
 
 Installation
 ------------
 
-The PyGSP is available on PyPI::
-
-    $ pip install pygsp
-
-The PyGSP is available on `conda-forge <https://github.com/conda-forge/pygsp-feedstock>`_::
-
-    $ conda install -c conda-forge pygsp
-
-The PyGSP is available in the `Arch User Repository <https://aur.archlinux.org/packages/python-pygsp>`_::
+The PyGSP2 is available on PyPI::
 
-   $ git clone https://aur.archlinux.org/python-pygsp.git
-   $ cd python-pygsp
-   $ makepkg -csi
+    $ pip install pygsp2
 
 Contributing
 ------------
diff --git a/doc/conf.py b/doc/conf.py
index c90e8595..5c9cec4f 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-import pygsp
+import pygsp2
 
 extensions = [
     'sphinx.ext.viewcode',
@@ -41,7 +41,7 @@
 }
 plot_pre_code = """
 import numpy as np
-from pygsp import graphs, filters, utils, plotting
+from pygsp2 import graphs, filters, utils, plotting
 """
 
 extensions.append('sphinx_gallery.gen_gallery')
@@ -49,9 +49,9 @@
     'examples_dirs': '../examples',
     'gallery_dirs': 'examples',
     'filename_pattern': '/',
-    'reference_url': {'pygsp': None},
+    'reference_url': {'pygsp2': None},
     'backreferences_dir': 'backrefs',
-    'doc_module': 'pygsp',
+    'doc_module': 'pygsp2',
     'show_memory': True,
 }
 
@@ -65,9 +65,9 @@
 source_suffix = '.rst'
 master_doc = 'index'
 
-project = 'PyGSP'
-version = pygsp.__version__
-release = pygsp.__version__
+project = 'pygsp2'
+version = pygsp2.__version__
+release = pygsp2.__version__
 copyright = 'EPFL LTS2'
 
 pygments_style = 'sphinx'
@@ -80,6 +80,6 @@
     'pointsize': '10pt',
 }
 latex_documents = [
-    ('index', 'pygsp.tex', 'PyGSP documentation',
+    ('index', 'pygsp2.tex', 'PyGSP2 documentation',
      'EPFL LTS2', 'manual'),
 ]
diff --git a/doc/reference/features.rst b/doc/reference/features.rst
index 831ebfa7..ba1f38f1 100644
--- a/doc/reference/features.rst
+++ b/doc/reference/features.rst
@@ -2,4 +2,4 @@
 Features
 ========
 
-.. automodule:: pygsp.features
+.. automodule:: pygsp2.features
diff --git a/doc/reference/filters.rst b/doc/reference/filters.rst
index bc7ccc1b..a3402c6f 100644
--- a/doc/reference/filters.rst
+++ b/doc/reference/filters.rst
@@ -2,4 +2,4 @@
 Filters
 =======
 
-.. automodule:: pygsp.filters
+.. automodule:: pygsp2.filters
diff --git a/doc/reference/graphs.rst b/doc/reference/graphs.rst
index 99d21e6b..19359edc 100644
--- a/doc/reference/graphs.rst
+++ b/doc/reference/graphs.rst
@@ -2,7 +2,7 @@
 Graphs
 ======
 
-.. automodule:: pygsp.graphs
+.. automodule:: pygsp2.graphs
     :exclude-members: Graph
 
     .. autoclass:: Graph
diff --git a/doc/reference/index.rst b/doc/reference/index.rst
index 71422b6b..a27b0d29 100644
--- a/doc/reference/index.rst
+++ b/doc/reference/index.rst
@@ -2,7 +2,7 @@
 API reference
 =============
 
-.. automodule:: pygsp
+.. automodule:: pygsp2
 
 .. toctree::
     :hidden:
diff --git a/doc/reference/learning.rst b/doc/reference/learning.rst
index 246e3fc3..d5b54182 100644
--- a/doc/reference/learning.rst
+++ b/doc/reference/learning.rst
@@ -2,4 +2,4 @@
 Learning
 ========
 
-.. automodule:: pygsp.learning
+.. automodule:: pygsp2.learning
diff --git a/doc/reference/optimization.rst b/doc/reference/optimization.rst
index 9a2a8c7e..647cefd2 100644
--- a/doc/reference/optimization.rst
+++ b/doc/reference/optimization.rst
@@ -2,4 +2,4 @@
 Optimization
 ============
 
-.. automodule:: pygsp.optimization
+.. automodule:: pygsp2.optimization
diff --git a/doc/reference/plotting.rst b/doc/reference/plotting.rst
index fb3db7e1..b0e31524 100644
--- a/doc/reference/plotting.rst
+++ b/doc/reference/plotting.rst
@@ -2,4 +2,4 @@
 Plotting
 ========
 
-.. automodule:: pygsp.plotting
+.. automodule:: pygsp2.plotting
diff --git a/doc/reference/reduction.rst b/doc/reference/reduction.rst
index d8192d10..3bf7f1c2 100644
--- a/doc/reference/reduction.rst
+++ b/doc/reference/reduction.rst
@@ -2,4 +2,4 @@
 Reduction
 =========
 
-.. automodule:: pygsp.reduction
+.. automodule:: pygsp2.reduction
diff --git a/doc/reference/utils.rst b/doc/reference/utils.rst
index 9942b1a5..04dc1d55 100644
--- a/doc/reference/utils.rst
+++ b/doc/reference/utils.rst
@@ -2,4 +2,4 @@
 Utilities
 =========
 
-.. automodule:: pygsp.utils
+.. automodule:: pygsp2.utils
diff --git a/doc/tutorials/intro.rst b/doc/tutorials/intro.rst
index 08098b1f..942720f5 100644
--- a/doc/tutorials/intro.rst
+++ b/doc/tutorials/intro.rst
@@ -1,10 +1,10 @@
-=========================
-Introduction to the PyGSP
-=========================
+==========================
+Introduction to the PyGSP2
+==========================
 
 This tutorial will show you the basic operations of the toolbox. After
 installing the package with pip, start by opening a python shell, e.g.
-a Jupyter notebook, and import the PyGSP. We will also need NumPy to create
+a Jupyter notebook, and import the PyGSP2. We will also need NumPy to create
 matrices and arrays.
 
 .. plot::
@@ -12,7 +12,7 @@ matrices and arrays.
 
     >>> import numpy as np
     >>> import matplotlib.pyplot as plt
-    >>> from pygsp import graphs, filters, plotting
+    >>> from pygsp2 import graphs, filters, plotting
 
 We then set default plotting parameters. We're using the ``matplotlib`` backend
 to embed plots in this tutorial. The ``pyqtgraph`` backend is best suited for
@@ -47,7 +47,7 @@ follows.
     >>> print('{} nodes, {} edges'.format(G.N, G.Ne))
     30 nodes, 64 edges
 
-The :class:`pygsp.graphs.Graph` class we just instantiated is the base class
+The :class:`pygsp2.graphs.Graph` class we just instantiated is the base class
 for all graph objects, which offers many methods and attributes.
 
 Given, a graph object, we can test some properties.
@@ -101,10 +101,10 @@ smoothness of a signal.
     (30, 64)
 
 .. note::
-    Note that we called :meth:`pygsp.graphs.Graph.compute_fourier_basis` and
-    :meth:`pygsp.graphs.Graph.compute_differential_operator` before accessing
-    the Fourier basis :attr:`pygsp.graphs.Graph.U` and the differential
-    operator :attr:`pygsp.graphs.Graph.D`. Doing so is however not mandatory as
+    Note that we called :meth:`pygsp2.graphs.Graph.compute_fourier_basis` and
+    :meth:`pygsp2.graphs.Graph.compute_differential_operator` before accessing
+    the Fourier basis :attr:`pygsp2.graphs.Graph.U` and the differential
+    operator :attr:`pygsp2.graphs.Graph.D`. Doing so is however not mandatory as
     those matrices would have been computed when requested (lazy evaluation).
     Omitting to call the *compute* functions does print a warning to tell you
     that a potentially heavy computation is taking place under the hood (that's
@@ -115,7 +115,7 @@ smoothness of a signal.
 To be able to plot a graph, we need to embed its nodes in a 2D or 3D space.
 While most included graph models define these coordinates, the graph we just
 created do not. We only passed a weight matrix after all. Let's set some
-coordinates with :meth:`pygsp.graphs.Graph.set_coordinates` and plot our graph.
+coordinates with :meth:`pygsp2.graphs.Graph.set_coordinates` and plot our graph.
 
 .. plot::
     :context: close-figs
@@ -125,7 +125,7 @@ coordinates with :meth:`pygsp.graphs.Graph.set_coordinates` and plot our graph.
 
 While we created our first graph ourselves, many standard models of graphs are
 implemented as subclasses of the Graph class and can be easily instantiated.
-Check the :mod:`pygsp.graphs` module to get a list of them and learn more about
+Check the :mod:`pygsp2.graphs` module to get a list of them and learn more about
 the Graph object.
 
 Fourier basis
@@ -135,7 +135,7 @@ As in classical signal processing, the Fourier transform plays a central role
 in graph signal processing. Getting the Fourier basis is however
 computationally intensive as it needs to fully diagonalize the Laplacian. While
 it can be used to filter signals on graphs, a better alternative is to use one
-of the fast approximations (see :meth:`pygsp.filters.Filter.filter`). Let's
+of the fast approximations (see :meth:`pygsp2.filters.Filter.filter`). Let's
 compute it nonetheless to visualize the eigenvectors of the Laplacian.
 Analogous to classical Fourier analysis, they look like sinuses on the graph.
 Let's plot the second and third eigenvectors (the first is constant). Those are
@@ -177,7 +177,7 @@ Filters
 -------
 
 To filter signals on graphs, we need to define filters. They are represented in
-the toolbox by the :class:`pygsp.filters.Filter` class. Filters are usually
+the toolbox by the :class:`pygsp2.filters.Filter` class. Filters are usually
 defined in the spectral domain. Given the transfer function
 
 .. math:: g(x) = \frac{1}{1 + \tau x},
@@ -204,7 +204,7 @@ filter will be evaluated to create a discrete filter.
 .. _filter bank: https://en.wikipedia.org/wiki/Filter_bank
 
 .. note::
-    The :mod:`pygsp.filters` module implements various standard filters.
+    The :mod:`pygsp2.filters` module implements various standard filters.
 
 Let's create a graph signal and add some random noise.
 
@@ -237,7 +237,7 @@ While the noise is largely removed thanks to the filter, some energy is
 diffused between the letters. This is the typical behavior of a low-pass
 filter.
 
-So here are the basics for the PyGSP. Please check the other tutorials and the
+So here are the basics for the PyGSP2. Please check the other tutorials and the
 reference guide for more. Enjoy!
 
 .. note::
diff --git a/doc/tutorials/optimization.rst b/doc/tutorials/optimization.rst
index fc5bf0ac..dbedf440 100644
--- a/doc/tutorials/optimization.rst
+++ b/doc/tutorials/optimization.rst
@@ -13,7 +13,7 @@ This tutorial focuses on the problem of recovering a label signal on a graph fro
     :context: reset
 
     >>> import numpy as np
-    >>> from pygsp import graphs, plotting
+    >>> from pygsp2 import graphs, plotting
     >>>
     >>> # Create a random sensor graph
     >>> G = graphs.Sensor(N=256, distributed=True, seed=42)
@@ -43,7 +43,7 @@ The first figure shows a plot of the original label signal, that we wish to reco
 
 This figure shows the label signal on the graph after the application of the subsampling mask and the addition of noise. The label of more than half of the vertices has been set to :math:`0`.
 
-Since the problem is ill-posed, we will use some regularization to reach a solution that is more in tune with what we expect a label signal to look like. We will compare two approaches, but they are both based on measuring local differences on the label signal. Those differences are essentially an edge signal: to each edge we can associate the difference between the label signals of its associated nodes. The linear operator that does such a mapping is called the graph gradient :math:`\nabla_G`, and, fortunately for us, it is available under the :attr:`pygsp.graphs.Graph.D` (for differential) attribute of any :mod:`pygsp.graphs` graph.
+Since the problem is ill-posed, we will use some regularization to reach a solution that is more in tune with what we expect a label signal to look like. We will compare two approaches, but they are both based on measuring local differences on the label signal. Those differences are essentially an edge signal: to each edge we can associate the difference between the label signals of its associated nodes. The linear operator that does such a mapping is called the graph gradient :math:`\nabla_G`, and, fortunately for us, it is available under the :attr:`pygsp2.graphs.Graph.D` (for differential) attribute of any :mod:`pygsp2.graphs` graph.
 
 The reason for measuring local differences comes from prior knowledge: we assume label signals don't vary too much locally. The precise measure of such variation is what distinguishes the two regularization approaches we'll use.
 
diff --git a/doc/tutorials/pyramid.rst b/doc/tutorials/pyramid.rst
index 2417eb3b..9ef062ba 100644
--- a/doc/tutorials/pyramid.rst
+++ b/doc/tutorials/pyramid.rst
@@ -2,11 +2,11 @@
 Graph multiresolution: Kron pyramid
 ===================================
 
-In this demonstration file, we show how to reduce a graph using the PyGSP. Then we apply the pyramid to simple signal.
+In this demonstration file, we show how to reduce a graph using the PyGSP2. Then we apply the pyramid to simple signal.
 To start open a python shell (IPython is recommended here) and import the required packages. You would probably also import numpy as you will need it to create matrices and arrays.
 
 >>> import numpy as np
->>> from pygsp import graphs, reduction
+>>> from pygsp2 import graphs, reduction
 
 For this demo we will be using a sensor graph with 400 nodes.
 
diff --git a/doc/tutorials/wavelet.rst b/doc/tutorials/wavelet.rst
index 287a0118..bd643f8a 100644
--- a/doc/tutorials/wavelet.rst
+++ b/doc/tutorials/wavelet.rst
@@ -16,7 +16,7 @@ As usual, we first have to import some packages.
 
     >>> import numpy as np
     >>> import matplotlib.pyplot as plt
-    >>> from pygsp import graphs, filters, plotting, utils
+    >>> from pygsp2 import graphs, filters, plotting, utils
 
 Then we can load a graph. The graph we'll use is a nearest-neighbor graph of a
 point cloud of the Stanford bunny. It will allow us to get interesting visual
@@ -29,10 +29,10 @@ results using wavelets.
 
 .. note::
     At this stage we could compute the Fourier basis using
-    :meth:`pygsp.graphs.Graph.compute_fourier_basis`, but this would take some
+    :meth:`pygsp2.graphs.Graph.compute_fourier_basis`, but this would take some
     time, and can be avoided with a Chebychev polynomials approximation to
     graph filtering. See the documentation of the
-    :meth:`pygsp.filters.Filter.filter` filtering function and
+    :meth:`pygsp2.filters.Filter.filter` filtering function and
     :cite:`hammond2011wavelets` for details on how it is down.
 
 Simple filtering: heat diffusion
@@ -81,7 +81,7 @@ scales.
     >>> fig.tight_layout()
 
 .. note::
-    The :meth:`pygsp.filters.Filter.localize` method can be used to visualize a
+    The :meth:`pygsp2.filters.Filter.localize` method can be used to visualize a
     filter in the vertex domain instead of doing it manually.
 
 Visualizing wavelets atoms
@@ -89,7 +89,7 @@ Visualizing wavelets atoms
 
 Let's now replace the Heat filter by a filter bank of wavelets. We can create a
 filter bank using one of the predefined filters, such as
-:class:`pygsp.filters.MexicanHat` to design a set of `Mexican hat wavelets`_.
+:class:`pygsp2.filters.MexicanHat` to design a set of `Mexican hat wavelets`_.
 
 .. _Mexican hat wavelets:
     https://en.wikipedia.org/wiki/Mexican_hat_wavelet
@@ -110,8 +110,8 @@ Then plot the frequency response of those filters.
 .. note::
     We can see that the wavelet atoms are stacked on the low frequency part of
     the spectrum. A better coverage could be obtained by adapting the filter
-    bank with :class:`pygsp.filters.WarpedTranslates` or by using another
-    filter bank like :class:`pygsp.filters.Itersine`.
+    bank with :class:`pygsp2.filters.WarpedTranslates` or by using another
+    filter bank like :class:`pygsp2.filters.Itersine`.
 
 We can visualize the atoms as we did with the heat kernel, by filtering
 a Kronecker delta placed at one specific vertex.
diff --git a/examples/eigenvalue_concentration.py b/examples/eigenvalue_concentration.py
index c372bf2a..6a4ef72e 100644
--- a/examples/eigenvalue_concentration.py
+++ b/examples/eigenvalue_concentration.py
@@ -8,11 +8,12 @@
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 n_neighbors = [1, 2, 5, 8]
 fig, axes = plt.subplots(3, len(n_neighbors), figsize=(15, 8))
 
+
 for k, ax in zip(n_neighbors, axes.T):
 
     graph = pg.graphs.Ring(17, k=k)
@@ -36,3 +37,4 @@
     assert np.all(np.abs(LambdaM - Lambda) < 1e-10)
 
 fig.tight_layout()
+plt.show()
diff --git a/examples/eigenvector_localization.py b/examples/eigenvector_localization.py
index 9722201d..22b03ed2 100644
--- a/examples/eigenvector_localization.py
+++ b/examples/eigenvector_localization.py
@@ -11,7 +11,7 @@
 mode will be localized on it.
 
 The mutual coherence between the basis of Kronecker deltas and the basis formed
-by the eigenvectors of the Laplacian, :attr:`pygsp.graphs.Graph.coherence`, is
+by the eigenvectors of the Laplacian, :attr:`pygsp2.graphs.Graph.coherence`, is
 a measure of the localization of the Fourier modes. The larger the value, the
 more localized the eigenvectors can be.
 
@@ -22,7 +22,7 @@
 import numpy as np
 import matplotlib as mpl
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 fig, axes = plt.subplots(2, 2, figsize=(8, 8))
 
@@ -64,3 +64,4 @@
                 horizontalalignment='center')
 
 fig.tight_layout()
+plt.show()
\ No newline at end of file
diff --git a/examples/filtering.py b/examples/filtering.py
index cac74d3d..6e4c3538 100644
--- a/examples/filtering.py
+++ b/examples/filtering.py
@@ -19,7 +19,7 @@
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 G = pg.graphs.Sensor(seed=42)
 G.compute_fourier_basis()
@@ -64,3 +64,4 @@
 axes[2].set_axis_off()
 
 fig.tight_layout()
+plt.show()
\ No newline at end of file
diff --git a/examples/fourier_basis.py b/examples/fourier_basis.py
index 2877c282..daf48224 100644
--- a/examples/fourier_basis.py
+++ b/examples/fourier_basis.py
@@ -9,12 +9,12 @@
 
 In classical signal processing, Fourier modes are completely delocalized, like
 on the grid graph. For general graphs however, Fourier modes might be
-localized. See :attr:`pygsp.graphs.Graph.coherence`.
+localized. See :attr:`pygsp2.graphs.Graph.coherence`.
 """
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 n_eigenvectors = 7
 
@@ -40,3 +40,4 @@ def plot_eigenvectors(G, axes):
 fig.subplots_adjust(hspace=0.5, right=0.8)
 cax = fig.add_axes([0.82, 0.16, 0.01, 0.26])
 _ = fig.colorbar(axes[1, -1].collections[1], cax=cax, ticks=[-0.4, 0, 0.4])
+plt.show()
\ No newline at end of file
diff --git a/examples/fourier_transform.py b/examples/fourier_transform.py
index ac89563c..b64c6035 100644
--- a/examples/fourier_transform.py
+++ b/examples/fourier_transform.py
@@ -2,15 +2,15 @@
 Fourier transform
 =================
 
-The graph Fourier transform :meth:`pygsp.graphs.Graph.gft` transforms a
+The graph Fourier transform :meth:`pygsp2.graphs.Graph.gft` transforms a
 signal from the vertex domain to the spectral domain. The smoother the signal
-(see :meth:`pygsp.graphs.Graph.dirichlet_energy`), the lower in the frequencies
+(see :meth:`pygsp2.graphs.Graph.dirichlet_energy`), the lower in the frequencies
 its energy is concentrated.
 """
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 G = pg.graphs.Sensor(seed=42)
 G.compute_fourier_basis()
@@ -44,3 +44,4 @@
 # axes[1, 0].set_title(r'$\hat{x}$: signal in the spectral domain')
 
 fig.tight_layout()
+plt.show()
\ No newline at end of file
diff --git a/examples/graph_learning.py b/examples/graph_learning.py
index 5904e7f4..efff5640 100644
--- a/examples/graph_learning.py
+++ b/examples/graph_learning.py
@@ -10,7 +10,7 @@
 import numpy as np
 from scipy import spatial
 import matplotlib.pyplot as plt
-from pygsp import graphs, graph_learning
+from pygsp2 import graphs, graph_learning
 
 # %% Create a ring graph
 G = graphs.ring.Ring(10)
diff --git a/examples/heat_diffusion.py b/examples/heat_diffusion.py
index 3dd65859..702d309d 100644
--- a/examples/heat_diffusion.py
+++ b/examples/heat_diffusion.py
@@ -3,14 +3,14 @@
 ==============
 
 Solve the heat equation by filtering the initial conditions with the heat
-kernel :class:`pygsp.filters.Heat`.
+kernel :class:`pygsp2.filters.Heat`.
 """
 
 from os import path
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 n_side = 13
 G = pg.graphs.Grid2d(n_side)
@@ -43,3 +43,4 @@
     axes[1, i].set_axis_off()
 
 fig.tight_layout()
+plt.show()
\ No newline at end of file
diff --git a/examples/kernel_localization.py b/examples/kernel_localization.py
index d9484fa9..0ea2ae71 100644
--- a/examples/kernel_localization.py
+++ b/examples/kernel_localization.py
@@ -4,14 +4,14 @@
 
 In classical signal processing, a filter can be translated in the vertex
 domain. We cannot do that on graphs. Instead, we can
-:meth:`~pygsp.filters.Filter.localize` a filter kernel. Note how on classic
+:meth:`~pygsp2.filters.Filter.localize` a filter kernel. Note how on classic
 structures (like the ring), the localized kernel is the same everywhere, while
 it changes when localized on irregular graphs.
 """
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 fig, axes = plt.subplots(2, 4, figsize=(10, 4))
 
@@ -38,3 +38,4 @@
         ax.set_axis_off()
 
 fig.tight_layout()
+plt.show()
\ No newline at end of file
diff --git a/examples/metro_graph_signal.py b/examples/metro_graph_signal.py
index de557612..b0dc1e54 100644
--- a/examples/metro_graph_signal.py
+++ b/examples/metro_graph_signal.py
@@ -1,4 +1,8 @@
-"""Example of a graph signal for the Santiago Metro.
+r"""
+Metro Graph Signal
+==================
+
+Example of a graph signal for the Santiago Metro.
 
 This example shows a graph signal defined over a graph induced by the Santiago
 Metro (https://en.wikipedia.org/wiki/Santiago_Metro). Each station is a
@@ -29,12 +33,26 @@
 import pandas as pd
 from unidecode import unidecode
 import matplotlib.pyplot as plt
-from utils import make_metro_graph, metro_database_preprocessing, plot_signal_in_graph
-os.chdir(os.path.dirname(__file__))
+
+from pygsp2.utils_examples import (
+    make_metro_graph, 
+    metro_database_preprocessing, 
+    plot_signal_in_graph,
+    fetch_data
+)
+
+current_dir = os.getcwd()
+os.chdir(current_dir)
+
+# %% Load data
+assets_dir = os.path.join(current_dir, 'examples')
+fetch_data(assets_dir, "metro")
 
 try:
-    commutes = pd.read_excel('2023.11 Matriz_baj_SS_MH.xlsb', header=1,
-                             sheet_name='bajadas_prom_laboral')
+    commutes = pd.read_excel(
+        os.path.join(assets_dir, '2023.11 Matriz_baj_SS_MH.xlsb'),
+        header=1,
+        sheet_name='bajadas_prom_laboral')
 except FileNotFoundError:
     print(f'Data file was not found in:\n {os.getcwd()}')
     print('Download it from:\n' +
@@ -43,7 +61,10 @@
 
 # %% Load graph
 
-G, pos = make_metro_graph()
+G, pos = make_metro_graph(
+    edgesfile=os.path.join(assets_dir, 'santiago_metro_stations_connections.txt'),
+    coordsfile=os.path.join(assets_dir, 'santiago_metro_stations_coords.geojson')
+)
 
 stations = [name.upper() for name in list(G.nodes)]
 stations = [unidecode(station) for station in stations]
@@ -64,6 +85,6 @@
      for i, station in enumerate(stations_missing)]
 
 # %% Plot signal in graph
-
 fig, ax = plot_signal_in_graph(G, signal, 'Promedio Diario\nBajadas de Metro')
-plt.show()
+#fig.savefig('metro_graph_signal.png')
+plt.show()
\ No newline at end of file
diff --git a/examples/metro_regression.py b/examples/metro_regression.py
index 36c1de04..e8bf8c0d 100644
--- a/examples/metro_regression.py
+++ b/examples/metro_regression.py
@@ -1,4 +1,8 @@
-"""Data imputing example in a  Santiago Metro station.
+r"""
+Metro Regression
+================
+
+Data imputing example in a  Santiago Metro station.
 
 Compute the number of exits in a random metro station. Then, compute the
 regression over the whole network and plot the error of the regression. Here,
@@ -31,13 +35,26 @@
 from unidecode import unidecode
 import networkx as nx
 import matplotlib.pyplot as plt
-from utils import make_metro_graph, plot_signal_in_graph, metro_database_preprocessing
-from pygsp import graphs, learning
-os.chdir(os.path.dirname(__file__))
+from pygsp2.utils_examples import (
+    make_metro_graph, 
+    plot_signal_in_graph, 
+    metro_database_preprocessing,
+    fetch_data
+)
+from pygsp2 import graphs, learning
+
+current_dir = os.getcwd()
+os.chdir(current_dir)
+
+# %% Load data
+assets_dir = os.path.join(current_dir, 'examples')
+fetch_data(assets_dir, "metro")
 
 try:
-    commutes = pd.read_excel('2023.11 Matriz_baj_SS_MH.xlsb', header=1,
-                             sheet_name='bajadas_prom_laboral')
+    commutes = pd.read_excel(
+        os.path.join(assets_dir, '2023.11 Matriz_baj_SS_MH.xlsb'),
+        header=1,
+        sheet_name='bajadas_prom_laboral')
 except FileNotFoundError:
     print(f'Data file was not found in:\n {os.getcwd()}')
     print('Download it from:\n' +
@@ -45,7 +62,10 @@
     sys.exit(1)
 
 # %% Load graph
-G, pos = make_metro_graph()
+G, pos = make_metro_graph(
+    edgesfile=os.path.join(assets_dir, 'santiago_metro_stations_connections.txt'),
+    coordsfile=os.path.join(assets_dir, 'santiago_metro_stations_coords.geojson')
+)
 pos_list = [(G.nodes[node]['y'], G.nodes[node]['x']) for node in G.nodes]
 
 # Extract adjacency matrix
@@ -108,16 +128,16 @@
 abs_err = np.abs(tikhonov_estimation - signal)
 
 # %% Plot Tikhonov error in graph
-plot_signal_in_graph(G, abs_err,
+fig, ax = plot_signal_in_graph(G, abs_err,
                      title='Error of Tikhonov Regression',
                      label='Error absoluto')
-
+#fig.savefig('metro_regression_tikhonov_error.png', dpi=300)
 # %% Plot Average error in graph
 # Change variable to error with average estimation
 abs_err = np.abs(average_estimation - signal)
 
-plot_signal_in_graph(G, abs_err,
+fig, ax = plot_signal_in_graph(G, abs_err,
                      title=r'Error of $y = AD^{-1}x$',
                      label='Error absoluto')
-
-plt.show()
+#fig.savefig('metro_regression_error_abs.png', dpi=300)
+plt.show()
\ No newline at end of file
diff --git a/examples/metro_simulation.py b/examples/metro_simulation.py
index 71b02882..05db5265 100644
--- a/examples/metro_simulation.py
+++ b/examples/metro_simulation.py
@@ -1,4 +1,8 @@
-"""Example of a simulation of the evolution of a graph signal over the Santiago Metro
+r"""
+Metro simulation
+================
+
+Example of a simulation of the evolution of a graph signal over the Santiago Metro
 network.
 
 The initial condition is a graph signal with only one positive integer value
@@ -31,14 +35,27 @@
 import networkx as nx
 import matplotlib.pyplot as plt
 from matplotlib import animation
-from utils import make_metro_graph
+from pygsp2.utils_examples import make_metro_graph, fetch_data
+import pygsp2 as pg
+
+current_dir = os.getcwd()
+os.chdir(current_dir)
+
 
 # If set to true make animation,
 # otherwise store each frame as png
 MAKE_ANIMATION = True
 
+# %% Download data
+assets_dir = os.path.join(current_dir, 'examples')
+fetch_data(assets_dir, "metro")
+
+
 # %% Load graph and compute adjacency and node degree
-G, pos = make_metro_graph()
+G, pos = make_metro_graph(
+    edgesfile=os.path.join(assets_dir, 'santiago_metro_stations_connections.txt'),
+    coordsfile=os.path.join(assets_dir, 'santiago_metro_stations_coords.geojson')
+)
 
 W = nx.adjacency_matrix(G).toarray()
 D = np.diag(W.sum(1))
@@ -93,9 +110,10 @@ def update(frame):
                                    interval=50)
 
     # saving to gif using ffmpeg writer
-    writervideo = animation.FFMpegWriter(fps=5)
+    writervideo = animation.PillowWriter(fps=5)
 
     anim.save('metro_simulation.gif', writer=writervideo)
+    plt.show()
 
 else:
     try:
diff --git a/examples/metro_simulation2.py b/examples/metro_simulation2.py
index 4514d659..04eecd7c 100644
--- a/examples/metro_simulation2.py
+++ b/examples/metro_simulation2.py
@@ -1,4 +1,8 @@
-"""Example of a simulation of the evolution of a graph signal over the Santiago Metro
+r"""
+Metro simulation 2
+==================
+
+Example of a simulation of the evolution of a graph signal over the Santiago Metro
 network.
 
 Simulation of the distribution of a signal over the metro network. The starting
@@ -54,7 +58,10 @@
 import numpy as np
 import networkx as nx
 import matplotlib.pyplot as plt
-from utils import make_metro_graph
+from pygsp2.utils_examples import make_metro_graph, fetch_data
+
+current_dir = os.getcwd()
+os.chdir(current_dir)
 
 try:
     os.mkdir('metro_simulation2/')
@@ -62,8 +69,14 @@
     print(
         'Warning: It seems like this folder already exists. Overwritting...')
 
+# %% Download data
+assets_dir = os.path.join(current_dir, 'examples')
+fetch_data(assets_dir, "metro")
 # %% Load graph and compute adjacency and node degree
-G, pos = make_metro_graph()
+G, pos = make_metro_graph(
+    edgesfile=os.path.join(assets_dir, 'santiago_metro_stations_connections.txt'),
+    coordsfile=os.path.join(assets_dir, 'santiago_metro_stations_coords.geojson')
+)
 stations = list(G)
 
 W0 = nx.adjacency_matrix(G).toarray()
diff --git a/examples/playground.ipynb b/examples/playground.ipynb
index 21222c77..e198599f 100644
--- a/examples/playground.ipynb
+++ b/examples/playground.ipynb
@@ -4,8 +4,8 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# Playing with the PyGSP\n",
-    "<https://github.com/epfl-lts2/pygsp>"
+    "# Playing with the PyGSP2\n",
+    "<https://github.com/gsp-eeg/pygsp2>"
    ]
   },
   {
@@ -18,7 +18,7 @@
     "\n",
     "import numpy as np\n",
     "import matplotlib.pyplot as plt\n",
-    "from pygsp import graphs, filters\n",
+    "from pygsp2 import graphs, filters\n",
     "\n",
     "plt.rcParams['figure.figsize'] = (17, 5)"
    ]
@@ -40,7 +40,7 @@
    "source": [
     "G = graphs.Logo()\n",
     "G.estimate_lmax()\n",
-    "g = filters.Heat(G, tau=100)"
+    "g = filters.Heat(G, scale=100)"
    ]
   },
   {
@@ -69,7 +69,7 @@
    "source": [
     "## 2 Tutorials and examples\n",
     "\n",
-    "Try our [tutorials](https://pygsp.readthedocs.io/en/stable/tutorials/index.html) or [examples](https://pygsp.readthedocs.io/en/stable/examples/index.html)."
+    "Try our [tutorials](https://pygsp2.readthedocs.io/en/stable/tutorials/index.html) or [examples](https://pygsp2.readthedocs.io/en/stable/examples/index.html)."
    ]
   },
   {
@@ -88,7 +88,7 @@
     "## 3 Playground\n",
     "\n",
     "Try something of your own!\n",
-    "The [API reference](https://pygsp.readthedocs.io/en/stable/reference/index.html) is your friend."
+    "The [API reference](https://pygsp2.readthedocs.io/en/stable/reference/index.html) is your friend."
    ]
   },
   {
@@ -122,6 +122,18 @@
    "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.10.14"
   }
  },
  "nbformat": 4,
diff --git a/examples/random_walk.py b/examples/random_walk.py
index 9fc69456..8f50c25a 100644
--- a/examples/random_walk.py
+++ b/examples/random_walk.py
@@ -11,7 +11,7 @@
 import numpy as np
 from scipy import sparse
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 N = 7
 steps = [0, 1, 2, 3]
@@ -65,3 +65,4 @@
     ax.set_axis_off()
 
 fig.tight_layout()
+plt.show()
diff --git a/examples/wave_propagation.py b/examples/wave_propagation.py
index d04ac5f2..2a943f53 100644
--- a/examples/wave_propagation.py
+++ b/examples/wave_propagation.py
@@ -3,14 +3,14 @@
 ================
 
 Solve the wave equation by filtering the initial conditions with the wave
-kernel :class:`pygsp.filters.Wave`.
+kernel :class:`pygsp2.filters.Wave`.
 """
 
 from os import path
 
 import numpy as np
 from matplotlib import pyplot as plt
-import pygsp as pg
+import pygsp2 as pg
 
 n_side = 13
 G = pg.graphs.Grid2d(n_side)
@@ -43,3 +43,4 @@
     axes[1, i].set_axis_off()
 
 fig.tight_layout()
+plt.show()
\ No newline at end of file
diff --git a/pygsp/__init__.py b/pygsp2/__init__.py
similarity index 89%
rename from pygsp/__init__.py
rename to pygsp2/__init__.py
index d76b16b9..23b4077a 100644
--- a/pygsp/__init__.py
+++ b/pygsp2/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp` package is mainly organized around the following two modules:
+The :mod:`pygsp2` package is mainly organized around the following two modules:
 
 * :mod:`.graphs` to create and manipulate various kinds of graphs,
 * :mod:`.filters` to create and manipulate various graph filters.
@@ -14,6 +14,7 @@
 * :mod:`.learning` to solve learning problems,
 * :mod:`.optimization` to help solving convex optimization problems,
 * :mod:`.utils` for various utilities.
+* :mod:`.utils_examples` for metro applications.
 
 """
 
@@ -25,6 +26,7 @@
 from . import learning  # noqa: F401
 from . import optimization  # noqa: F401
 from . import utils  # noqa: F401
+from . import utils_examples # noqa: F401
 
 # Users only call the plot methods from the objects.
 # It's thus more convenient for them to have the doc there.
@@ -47,5 +49,5 @@ def test():  # pragma: no cover
     """Run the test suite."""
     import unittest
     # Lazy as it might be slow and require additional dependencies.
-    from pygsp.tests import suite
+    from pygsp2.tests import suite
     unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/pygsp/data/pointclouds/airfoil.mat b/pygsp2/data/pointclouds/airfoil.mat
similarity index 100%
rename from pygsp/data/pointclouds/airfoil.mat
rename to pygsp2/data/pointclouds/airfoil.mat
diff --git a/pygsp/data/pointclouds/bunny.mat b/pygsp2/data/pointclouds/bunny.mat
similarity index 100%
rename from pygsp/data/pointclouds/bunny.mat
rename to pygsp2/data/pointclouds/bunny.mat
diff --git a/pygsp/data/pointclouds/david500.mat b/pygsp2/data/pointclouds/david500.mat
similarity index 100%
rename from pygsp/data/pointclouds/david500.mat
rename to pygsp2/data/pointclouds/david500.mat
diff --git a/pygsp/data/pointclouds/david64.mat b/pygsp2/data/pointclouds/david64.mat
similarity index 100%
rename from pygsp/data/pointclouds/david64.mat
rename to pygsp2/data/pointclouds/david64.mat
diff --git a/pygsp/data/pointclouds/logogsp.mat b/pygsp2/data/pointclouds/logogsp.mat
similarity index 100%
rename from pygsp/data/pointclouds/logogsp.mat
rename to pygsp2/data/pointclouds/logogsp.mat
diff --git a/pygsp/data/pointclouds/minnesota.mat b/pygsp2/data/pointclouds/minnesota.mat
similarity index 100%
rename from pygsp/data/pointclouds/minnesota.mat
rename to pygsp2/data/pointclouds/minnesota.mat
diff --git a/pygsp/data/pointclouds/two_moons.mat b/pygsp2/data/pointclouds/two_moons.mat
similarity index 100%
rename from pygsp/data/pointclouds/two_moons.mat
rename to pygsp2/data/pointclouds/two_moons.mat
diff --git a/pygsp/data/readme_example_filter.png b/pygsp2/data/readme_example_filter.png
similarity index 100%
rename from pygsp/data/readme_example_filter.png
rename to pygsp2/data/readme_example_filter.png
diff --git a/pygsp/data/readme_example_graph.png b/pygsp2/data/readme_example_graph.png
similarity index 100%
rename from pygsp/data/readme_example_graph.png
rename to pygsp2/data/readme_example_graph.png
diff --git a/pygsp/features.py b/pygsp2/features.py
similarity index 84%
rename from pygsp/features.py
rename to pygsp2/features.py
index 76071316..84e756a9 100644
--- a/pygsp/features.py
+++ b/pygsp2/features.py
@@ -1,13 +1,13 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.features` module implements different feature extraction
-techniques based on :mod:`pygsp.graphs` and :mod:`pygsp.filters`.
+The :mod:`pygsp2.features` module implements different feature extraction
+techniques based on :mod:`pygsp2.graphs` and :mod:`pygsp2.filters`.
 """
 
 import numpy as np
 
-from pygsp import filters, utils
+from pygsp2 import filters, utils
 
 
 def compute_avg_adj_deg(G):
@@ -35,10 +35,10 @@ def compute_tig(g, **kwargs):
     Parameters
     ----------
     g: Filter
-        One of :mod:`pygsp.filters`.
+        One of :mod:`pygsp2.filters`.
     kwargs: dict
         Additional parameters to be passed to the
-        :func:`pygsp.filters.Filter.filter` method.
+        :func:`pygsp2.filters.Filter.filter` method.
     """
     return g.compute_frame()
 
@@ -55,7 +55,7 @@ def compute_norm_tig(g, **kwargs):
         The filter or filter bank.
     kwargs: dict
         Additional parameters to be passed to the
-        :func:`pygsp.filters.Filter.filter` method.
+        :func:`pygsp2.filters.Filter.filter` method.
     """
     tig = compute_tig(g, **kwargs)
     return np.linalg.norm(tig, axis=1, ord=2)
@@ -76,7 +76,7 @@ def compute_spectrogram(G, atom=None, M=100, **kwargs):
         Number of samples on the spectral scale. (default = 100)
     kwargs: dict
         Additional parameters to be passed to the
-        :func:`pygsp.filters.Filter.filter` method.
+        :func:`pygsp2.filters.Filter.filter` method.
     """
 
     if not atom:
diff --git a/pygsp/filters/__init__.py b/pygsp2/filters/__init__.py
similarity index 97%
rename from pygsp/filters/__init__.py
rename to pygsp2/filters/__init__.py
index 9853f4cb..ae50eda7 100644
--- a/pygsp/filters/__init__.py
+++ b/pygsp2/filters/__init__.py
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.filters` module implements methods used for filtering and
-defines commonly used filters that can be applied to :mod:`pygsp.graphs`. A
+The :mod:`pygsp2.filters` module implements methods used for filtering and
+defines commonly used filters that can be applied to :mod:`pygsp2.graphs`. A
 filter is associated to a graph and is defined with one or several functions.
 We define by filter bank a list of filters, usually centered around different
 frequencies, applied to a single graph.
diff --git a/pygsp/filters/abspline.py b/pygsp2/filters/abspline.py
similarity index 96%
rename from pygsp/filters/abspline.py
rename to pygsp2/filters/abspline.py
index 2bd23e33..4f580139 100644
--- a/pygsp/filters/abspline.py
+++ b/pygsp2/filters/abspline.py
@@ -5,7 +5,7 @@
 import numpy as np
 from scipy import optimize
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Filter  # prevent circular import in Python < 3.5
 
 
@@ -23,7 +23,7 @@ class Abspline(Filter):
         (default = 20)
     scales : ndarray
         Vector of scales to be used.
-        By default, initialized with :func:`pygsp.utils.compute_log_scales`.
+        By default, initialized with :func:`pygsp2.utils.compute_log_scales`.
 
     Examples
     --------
diff --git a/pygsp/filters/approximations.py b/pygsp2/filters/approximations.py
similarity index 99%
rename from pygsp/filters/approximations.py
rename to pygsp2/filters/approximations.py
index 2c383760..2bc07945 100644
--- a/pygsp/filters/approximations.py
+++ b/pygsp2/filters/approximations.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 
 
 _logger = utils.build_logger(__name__)
diff --git a/pygsp/filters/expwin.py b/pygsp2/filters/expwin.py
similarity index 100%
rename from pygsp/filters/expwin.py
rename to pygsp2/filters/expwin.py
diff --git a/pygsp/filters/filter.py b/pygsp2/filters/filter.py
similarity index 99%
rename from pygsp/filters/filter.py
rename to pygsp2/filters/filter.py
index 1fd3ba0c..6cb04ea5 100644
--- a/pygsp/filters/filter.py
+++ b/pygsp2/filters/filter.py
@@ -4,7 +4,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 # prevent circular import in Python < 3.5
 from . import approximations
 from ..graphs import Graph
@@ -700,7 +700,7 @@ def inverse(self):
 
         Returns
         -------
-        inverse : :class:`pygsp.filters.Filter`
+        inverse : :class:`pygsp2.filters.Filter`
             The pseudo-inverse filter bank, which synthesizes (or reconstructs)
             a signal from its coefficients using the canonical dual frame.
 
@@ -753,6 +753,6 @@ def kernel(g, i, x):
     def plot(self, n=500, eigenvalues=None, sum=None, labels=None, title=None,
              ax=None, **kwargs):
         r"""Docstring overloaded at import time."""
-        from pygsp.plotting import _plot_filter
+        from pygsp2.plotting import _plot_filter
         return _plot_filter(self, n=n, eigenvalues=eigenvalues, sum=sum,
                             labels=labels, title=title, ax=ax, **kwargs)
diff --git a/pygsp/filters/gabor.py b/pygsp2/filters/gabor.py
similarity index 94%
rename from pygsp/filters/gabor.py
rename to pygsp2/filters/gabor.py
index 6b1a8883..997e3876 100644
--- a/pygsp/filters/gabor.py
+++ b/pygsp2/filters/gabor.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Filter  # prevent circular import in Python < 3.5
 
 
@@ -28,12 +28,12 @@ class Gabor(Filter):
 
     While :math:`g_{i,k}` should ideally be localized in both the spectral and
     vertex domains, that is impossible for some graphs due to the localization
-    of some eigenvectors. See :attr:`pygsp.graphs.Graph.coherence`.
+    of some eigenvectors. See :attr:`pygsp2.graphs.Graph.coherence`.
 
     Parameters
     ----------
-    graph : :class:`pygsp.graphs.Graph`
-    kernel : :class:`pygsp.filters.Filter`
+    graph : :class:`pygsp2.graphs.Graph`
+    kernel : :class:`pygsp2.filters.Filter`
         Kernel function to be centered at each graph frequency (eigenvalue of
         the graph Laplacian).
 
diff --git a/pygsp/filters/halfcosine.py b/pygsp2/filters/halfcosine.py
similarity index 100%
rename from pygsp/filters/halfcosine.py
rename to pygsp2/filters/halfcosine.py
diff --git a/pygsp/filters/heat.py b/pygsp2/filters/heat.py
similarity index 100%
rename from pygsp/filters/heat.py
rename to pygsp2/filters/heat.py
diff --git a/pygsp/filters/held.py b/pygsp2/filters/held.py
similarity index 100%
rename from pygsp/filters/held.py
rename to pygsp2/filters/held.py
diff --git a/pygsp/filters/itersine.py b/pygsp2/filters/itersine.py
similarity index 100%
rename from pygsp/filters/itersine.py
rename to pygsp2/filters/itersine.py
diff --git a/pygsp/filters/mexicanhat.py b/pygsp2/filters/mexicanhat.py
similarity index 96%
rename from pygsp/filters/mexicanhat.py
rename to pygsp2/filters/mexicanhat.py
index e0c43c56..8421b78c 100644
--- a/pygsp/filters/mexicanhat.py
+++ b/pygsp2/filters/mexicanhat.py
@@ -4,7 +4,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Filter  # prevent circular import in Python < 3.5
 
 
@@ -34,7 +34,7 @@ class MexicanHat(Filter):
         The scaling function will be created to fill the low-pass gap.
     scales : array_like
         Scales to be used.
-        By default, initialized with :func:`pygsp.utils.compute_log_scales`.
+        By default, initialized with :func:`pygsp2.utils.compute_log_scales`.
     normalize : bool
         Whether to normalize the wavelet by the factor ``sqrt(scales)``.
 
diff --git a/pygsp/filters/meyer.py b/pygsp2/filters/meyer.py
similarity index 99%
rename from pygsp/filters/meyer.py
rename to pygsp2/filters/meyer.py
index e54f5314..50ed0a9b 100644
--- a/pygsp/filters/meyer.py
+++ b/pygsp2/filters/meyer.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Filter  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/filters/modulation.py b/pygsp2/filters/modulation.py
similarity index 96%
rename from pygsp/filters/modulation.py
rename to pygsp2/filters/modulation.py
index f33c20ed..6e077d5b 100644
--- a/pygsp/filters/modulation.py
+++ b/pygsp2/filters/modulation.py
@@ -13,7 +13,7 @@ class Modulation(Filter):
     The mother filter is translated to each eigenvalue of the Laplacian via
     modulation. A signal is modulated by multiplying it with an eigenvector.
     Similarly to localization, it is an element-wise multiplication of a kernel
-    with the columns of :attr:`pygsp.graphs.Graph.U`, i.e., the eigenvectors,
+    with the columns of :attr:`pygsp2.graphs.Graph.U`, i.e., the eigenvectors,
     in the vertex domain.
 
     This filter bank can be used to compute the frequency content of a signal
@@ -27,7 +27,7 @@ class Modulation(Filter):
 
     While :math:`g_{i,k}` should ideally be localized in both the spectral and
     vertex domains, that is impossible for some graphs due to the localization
-    of some eigenvectors. See :attr:`pygsp.graphs.Graph.coherence`.
+    of some eigenvectors. See :attr:`pygsp2.graphs.Graph.coherence`.
 
     As modulation and localization don't commute, one can define the frame as
     :math:`g_{i,k} = T_i M_k g` (modulation first) or :math:`g_{i,k} = M_k T_i
@@ -49,8 +49,8 @@ class Modulation(Filter):
 
     Parameters
     ----------
-    graph : :class:`pygsp.graphs.Graph`
-    kernel : :class:`pygsp.filters.Filter`
+    graph : :class:`pygsp2.graphs.Graph`
+    kernel : :class:`pygsp2.filters.Filter`
         Kernel function to be modulated.
     modulation_first : bool
         First modulate then localize the kernel if True, first localize then
diff --git a/pygsp/filters/papadakis.py b/pygsp2/filters/papadakis.py
similarity index 100%
rename from pygsp/filters/papadakis.py
rename to pygsp2/filters/papadakis.py
diff --git a/pygsp/filters/rectangular.py b/pygsp2/filters/rectangular.py
similarity index 100%
rename from pygsp/filters/rectangular.py
rename to pygsp2/filters/rectangular.py
diff --git a/pygsp/filters/regular.py b/pygsp2/filters/regular.py
similarity index 100%
rename from pygsp/filters/regular.py
rename to pygsp2/filters/regular.py
diff --git a/pygsp/filters/simoncelli.py b/pygsp2/filters/simoncelli.py
similarity index 100%
rename from pygsp/filters/simoncelli.py
rename to pygsp2/filters/simoncelli.py
diff --git a/pygsp/filters/simpletight.py b/pygsp2/filters/simpletight.py
similarity index 99%
rename from pygsp/filters/simpletight.py
rename to pygsp2/filters/simpletight.py
index 32b2989e..652cd3ef 100644
--- a/pygsp/filters/simpletight.py
+++ b/pygsp2/filters/simpletight.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Filter  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/filters/wave.py b/pygsp2/filters/wave.py
similarity index 100%
rename from pygsp/filters/wave.py
rename to pygsp2/filters/wave.py
diff --git a/pygsp/graph_learning.py b/pygsp2/graph_learning.py
similarity index 97%
rename from pygsp/graph_learning.py
rename to pygsp2/graph_learning.py
index a3fa5685..b5a4d70f 100644
--- a/pygsp/graph_learning.py
+++ b/pygsp2/graph_learning.py
@@ -1,5 +1,5 @@
 r"""
-The :mod:`pygsp.graph_learning` module provides functions
+The :mod:`pygsp2.graph_learning` module provides functions
 to estimate a graph based on a distance matrix Z.
 
 .. autosummary::
@@ -9,7 +9,7 @@
 """
 import numpy as np
 from scipy.spatial.distance import squareform
-from pygsp.utils import sum_squareform
+from pygsp2.utils import sum_squareform
 
 
 def graph_log_degree(Z, a=1.0, b=1.0, w_0='zeros', w_max=np.inf, tol=1e-5,
diff --git a/pygsp/graphs/__init__.py b/pygsp2/graphs/__init__.py
similarity index 93%
rename from pygsp/graphs/__init__.py
rename to pygsp2/graphs/__init__.py
index 1a95557e..6f30775d 100644
--- a/pygsp/graphs/__init__.py
+++ b/pygsp2/graphs/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.graphs` module implements the graph class hierarchy. A graph
+The :mod:`pygsp2.graphs` module implements the graph class hierarchy. A graph
 object is either constructed from an adjacency matrix, or by instantiating one
 of the built-in graph models.
 
@@ -67,8 +67,8 @@
     Graph.igft
 
 Vertex-frequency transforms are implemented as filter banks and are found in
-:mod:`pygsp.filters` (such as :class:`~pygsp.filters.Gabor` and
-:class:`~pygsp.filters.Modulation`).
+:mod:`pygsp2.filters` (such as :class:`~pygsp2.filters.Gabor` and
+:class:`~pygsp2.filters.Modulation`).
 
 Checks
 ------
@@ -93,9 +93,9 @@
 
 We provide import and export facility to two well-known Python packages for
 network analysis: NetworkX_ and graph-tool_.
-Those packages and the PyGSP are fundamentally different in their goals (graph
+Those packages and the PyGSP2 are fundamentally different in their goals (graph
 analysis versus graph signal analysis) and graph representations (if in the
-PyGSP everything is an ndarray, in NetworkX everything is a dictionary).
+PyGSP2 everything is an ndarray, in NetworkX everything is a dictionary).
 Those tools are complementary and good interoperability is necessary to exploit
 the strengths of each tool.
 We ourselves leverage NetworkX and graph-tool to save and load graphs.
@@ -133,7 +133,7 @@
 generators from NetworkX (see `NetworkX's documentation`_) and graph-tool (see
 :mod:`graph_tool.generation`), as well as graph-tool's assortment of standard
 networks (see :mod:`graph_tool.collection`).
-Any graph created by NetworkX or graph-tool can be imported in the PyGSP with
+Any graph created by NetworkX or graph-tool can be imported in the PyGSP2 with
 :meth:`Graph.from_networkx` and :meth:`Graph.from_graphtool`.
 
 .. _NetworkX's documentation: https://networkx.org/documentation/stable/reference/generators.html
diff --git a/pygsp/graphs/_io.py b/pygsp2/graphs/_io.py
similarity index 98%
rename from pygsp/graphs/_io.py
rename to pygsp2/graphs/_io.py
index 5a0a8c04..b88754cd 100644
--- a/pygsp/graphs/_io.py
+++ b/pygsp2/graphs/_io.py
@@ -93,7 +93,7 @@ def to_networkx(self):
         >>> # nx.draw(graph, with_labels=True)
 
         Another common goal is to use NetworkX to compute some properties to be
-        be imported back in the PyGSP as signals.
+        be imported back in the PyGSP2 as signals.
 
         >>> import networkx as nx
         >>> from matplotlib import pyplot as plt
@@ -176,7 +176,7 @@ def to_graphtool(self):
         >>> # gt.draw.graph_draw(graph, vertex_text=graph.vertex_index)
 
         Another common goal is to use graph-tool to compute some properties to
-        be imported back in the PyGSP as signals.
+        be imported back in the PyGSP2 as signals.
 
         >>> import graph_tool as gt
         >>> import graph_tool.centrality
@@ -234,8 +234,8 @@ def from_networkx(cls, graph, weight='weight'):
 
         Returns
         -------
-        graph : :class:`~pygsp.graphs.Graph`
-            A PyGSP graph object.
+        graph : :class:`~pygsp2.graphs.Graph`
+            A PyGSP2 graph object.
 
         Notes
         -----
@@ -315,8 +315,8 @@ def from_graphtool(cls, graph, weight='weight'):
 
         Returns
         -------
-        graph : :class:`~pygsp.graphs.Graph`
-            A PyGSP graph object.
+        graph : :class:`~pygsp2.graphs.Graph`
+            A PyGSP2 graph object.
 
         Notes
         -----
@@ -395,8 +395,8 @@ def load(cls, path, fmt=None, backend=None):
         See Also
         --------
         save : save a graph to a file
-        from_networkx : load with NetworkX then import in the PyGSP
-        from_graphtool : load with graph-tool then import in the PyGSP
+        from_networkx : load with NetworkX then import in the PyGSP2
+        from_graphtool : load with graph-tool then import in the PyGSP2
 
         Notes
         -----
@@ -405,7 +405,7 @@ def load(cls, path, fmt=None, backend=None):
         is saved and loaded with the same backend.
 
         Loading from other formats is possible by loading in NetworkX or
-        graph-tool, and importing to the PyGSP.
+        graph-tool, and importing to the PyGSP2.
         The proposed formats are however tested for faithful round-trips.
 
         Examples
@@ -475,7 +475,7 @@ def save(self, path, fmt=None, backend=None):
 
         .. _GraphML: https://en.wikipedia.org/wiki/GraphML
         .. _GML: https://en.wikipedia.org/wiki/Graph_Modelling_Language
-        .. _GEXF: https://gephi.org/gexf/format
+        .. _GEXF: https://gephi.org/gexf
         .. _NetworkX: https://networkx.org
         .. _graph-tool: https://graph-tool.skewed.de
         .. _NetworKit: https://networkit.github.io
diff --git a/pygsp/graphs/_layout.py b/pygsp2/graphs/_layout.py
similarity index 100%
rename from pygsp/graphs/_layout.py
rename to pygsp2/graphs/_layout.py
diff --git a/pygsp/graphs/airfoil.py b/pygsp2/graphs/airfoil.py
similarity index 97%
rename from pygsp/graphs/airfoil.py
rename to pygsp2/graphs/airfoil.py
index 0bbc8140..682c0d24 100644
--- a/pygsp/graphs/airfoil.py
+++ b/pygsp2/graphs/airfoil.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/barabasialbert.py b/pygsp2/graphs/barabasialbert.py
similarity index 100%
rename from pygsp/graphs/barabasialbert.py
rename to pygsp2/graphs/barabasialbert.py
diff --git a/pygsp/graphs/comet.py b/pygsp2/graphs/comet.py
similarity index 100%
rename from pygsp/graphs/comet.py
rename to pygsp2/graphs/comet.py
diff --git a/pygsp/graphs/community.py b/pygsp2/graphs/community.py
similarity index 99%
rename from pygsp/graphs/community.py
rename to pygsp2/graphs/community.py
index 60a4a07e..0aba743b 100644
--- a/pygsp/graphs/community.py
+++ b/pygsp2/graphs/community.py
@@ -8,7 +8,7 @@
 import numpy as np
 from scipy import sparse, spatial
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/davidsensornet.py b/pygsp2/graphs/davidsensornet.py
similarity index 98%
rename from pygsp/graphs/davidsensornet.py
rename to pygsp2/graphs/davidsensornet.py
index 6e0731f1..c9be549d 100644
--- a/pygsp/graphs/davidsensornet.py
+++ b/pygsp2/graphs/davidsensornet.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/difference.py b/pygsp2/graphs/difference.py
similarity index 99%
rename from pygsp/graphs/difference.py
rename to pygsp2/graphs/difference.py
index 0cf2a3c2..ac2921c7 100644
--- a/pygsp/graphs/difference.py
+++ b/pygsp2/graphs/difference.py
@@ -5,7 +5,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 
 
 logger = utils.build_logger(__name__)
diff --git a/pygsp/graphs/erdosrenyi.py b/pygsp2/graphs/erdosrenyi.py
similarity index 100%
rename from pygsp/graphs/erdosrenyi.py
rename to pygsp2/graphs/erdosrenyi.py
diff --git a/pygsp/graphs/fourier.py b/pygsp2/graphs/fourier.py
similarity index 99%
rename from pygsp/graphs/fourier.py
rename to pygsp2/graphs/fourier.py
index 9611a55c..24ef700e 100644
--- a/pygsp/graphs/fourier.py
+++ b/pygsp2/graphs/fourier.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse, linalg
 
-from pygsp import utils
+from pygsp2 import utils
 
 
 logger = utils.build_logger(__name__)
diff --git a/pygsp/graphs/fullconnected.py b/pygsp2/graphs/fullconnected.py
similarity index 100%
rename from pygsp/graphs/fullconnected.py
rename to pygsp2/graphs/fullconnected.py
diff --git a/pygsp/graphs/graph.py b/pygsp2/graphs/graph.py
similarity index 99%
rename from pygsp/graphs/graph.py
rename to pygsp2/graphs/graph.py
index 4090181b..48fbf6a0 100644
--- a/pygsp/graphs/graph.py
+++ b/pygsp2/graphs/graph.py
@@ -8,7 +8,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from .fourier import FourierMixIn
 from .difference import DifferenceMixIn
 from ._io import IOMixIn
@@ -870,7 +870,7 @@ def estimate_lmax(self, method='lanczos'):
         Runs the implicitly restarted Lanczos method (as implemented in
         :func:`scipy.sparse.linalg.eigsh`) with a large tolerance, then
         increases the calculated largest eigenvalue by 1 percent. For much of
-        the PyGSP machinery, we need to approximate filter kernels on an
+        the PyGSP2 machinery, we need to approximate filter kernels on an
         interval that contains the spectrum of L. The only cost of using a
         larger interval is that the polynomial approximation over the larger
         interval may be a slightly worse approximation on the actual spectrum.
@@ -1023,7 +1023,7 @@ def plot(self, vertex_color=None, vertex_size=None, highlight=[],
              indices=False, colorbar=True, limits=None, ax=None,
              title=None, backend=None):
         r"""Docstring overloaded at import time."""
-        from pygsp.plotting import _plot_graph
+        from pygsp2.plotting import _plot_graph
         return _plot_graph(self, vertex_color=vertex_color,
                            vertex_size=vertex_size, highlight=highlight,
                            edges=edges, indices=indices, colorbar=colorbar,
@@ -1036,5 +1036,5 @@ def plot_signal(self, *args, **kwargs):
 
     def plot_spectrogram(self, node_idx=None):
         r"""Docstring overloaded at import time."""
-        from pygsp.plotting import _plot_spectrogram
+        from pygsp2.plotting import _plot_spectrogram
         _plot_spectrogram(self, node_idx=node_idx)
diff --git a/pygsp/graphs/grid2d.py b/pygsp2/graphs/grid2d.py
similarity index 96%
rename from pygsp/graphs/grid2d.py
rename to pygsp2/graphs/grid2d.py
index 26bef79b..babafeb6 100644
--- a/pygsp/graphs/grid2d.py
+++ b/pygsp2/graphs/grid2d.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
@@ -11,7 +11,7 @@ class Grid2d(Graph):
     r"""2-dimensional grid graph.
 
     On the 2D grid, the graph Fourier transform (GFT) is the Kronecker product
-    between the GFT of two :class:`~pygsp.graphs.Path` graphs.
+    between the GFT of two :class:`~pygsp2.graphs.Path` graphs.
 
     Parameters
     ----------
diff --git a/pygsp/graphs/linegraph.py b/pygsp2/graphs/linegraph.py
similarity index 98%
rename from pygsp/graphs/linegraph.py
rename to pygsp2/graphs/linegraph.py
index 93809067..7ca5813d 100644
--- a/pygsp/graphs/linegraph.py
+++ b/pygsp2/graphs/linegraph.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/logo.py b/pygsp2/graphs/logo.py
similarity index 97%
rename from pygsp/graphs/logo.py
rename to pygsp2/graphs/logo.py
index 8d2c47e2..83740add 100644
--- a/pygsp/graphs/logo.py
+++ b/pygsp2/graphs/logo.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/lowstretchtree.py b/pygsp2/graphs/lowstretchtree.py
similarity index 100%
rename from pygsp/graphs/lowstretchtree.py
rename to pygsp2/graphs/lowstretchtree.py
diff --git a/pygsp/graphs/minnesota.py b/pygsp2/graphs/minnesota.py
similarity index 98%
rename from pygsp/graphs/minnesota.py
rename to pygsp2/graphs/minnesota.py
index 6e429c8e..135e5f74 100644
--- a/pygsp/graphs/minnesota.py
+++ b/pygsp2/graphs/minnesota.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/nngraphs/__init__.py b/pygsp2/graphs/nngraphs/__init__.py
similarity index 100%
rename from pygsp/graphs/nngraphs/__init__.py
rename to pygsp2/graphs/nngraphs/__init__.py
diff --git a/pygsp/graphs/nngraphs/bunny.py b/pygsp2/graphs/nngraphs/bunny.py
similarity index 90%
rename from pygsp/graphs/nngraphs/bunny.py
rename to pygsp2/graphs/nngraphs/bunny.py
index d9dac407..e0d3d0c2 100644
--- a/pygsp/graphs/nngraphs/bunny.py
+++ b/pygsp2/graphs/nngraphs/bunny.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
-from pygsp import utils
-from pygsp.graphs import NNGraph  # prevent circular import in Python < 3.5
+from pygsp2 import utils
+from pygsp2.graphs import NNGraph  # prevent circular import in Python < 3.5
 
 
 class Bunny(NNGraph):
diff --git a/pygsp/graphs/nngraphs/cube.py b/pygsp2/graphs/nngraphs/cube.py
similarity index 97%
rename from pygsp/graphs/nngraphs/cube.py
rename to pygsp2/graphs/nngraphs/cube.py
index 820e401c..4fd99bb4 100644
--- a/pygsp/graphs/nngraphs/cube.py
+++ b/pygsp2/graphs/nngraphs/cube.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp.graphs import NNGraph  # prevent circular import in Python < 3.5
+from pygsp2.graphs import NNGraph  # prevent circular import in Python < 3.5
 
 
 class Cube(NNGraph):
diff --git a/pygsp/graphs/nngraphs/grid2dimgpatches.py b/pygsp2/graphs/nngraphs/grid2dimgpatches.py
similarity index 96%
rename from pygsp/graphs/nngraphs/grid2dimgpatches.py
rename to pygsp2/graphs/nngraphs/grid2dimgpatches.py
index 34168c00..576eca3e 100644
--- a/pygsp/graphs/nngraphs/grid2dimgpatches.py
+++ b/pygsp2/graphs/nngraphs/grid2dimgpatches.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 # prevent circular import in Python < 3.5
-from pygsp.graphs import Graph, Grid2d, ImgPatches
+from pygsp2.graphs import Graph, Grid2d, ImgPatches
 
 
 class Grid2dImgPatches(Graph):
diff --git a/pygsp/graphs/nngraphs/imgpatches.py b/pygsp2/graphs/nngraphs/imgpatches.py
similarity index 97%
rename from pygsp/graphs/nngraphs/imgpatches.py
rename to pygsp2/graphs/nngraphs/imgpatches.py
index 73cb6abd..f05f42ba 100644
--- a/pygsp/graphs/nngraphs/imgpatches.py
+++ b/pygsp2/graphs/nngraphs/imgpatches.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp.graphs import NNGraph  # prevent circular import in Python < 3.5
+from pygsp2.graphs import NNGraph  # prevent circular import in Python < 3.5
 
 
 class ImgPatches(NNGraph):
diff --git a/pygsp/graphs/nngraphs/nngraph.py b/pygsp2/graphs/nngraphs/nngraph.py
similarity index 97%
rename from pygsp/graphs/nngraphs/nngraph.py
rename to pygsp2/graphs/nngraphs/nngraph.py
index d14757c0..cb0b67d1 100644
--- a/pygsp/graphs/nngraphs/nngraph.py
+++ b/pygsp2/graphs/nngraphs/nngraph.py
@@ -5,8 +5,8 @@
 import numpy as np
 from scipy import sparse, spatial
 
-from pygsp import utils
-from pygsp.graphs import Graph  # prevent circular import in Python < 3.5
+from pygsp2 import utils
+from pygsp2.graphs import Graph  # prevent circular import in Python < 3.5
 
 _logger = utils.build_logger(__name__)
 
@@ -49,11 +49,11 @@ class NNGraph(Graph):
     epsilon : float, optional
         Radius for the epsilon-neighborhood search (default is 0.01)
     plotting : dict, optional
-        Dictionary of plotting parameters. See :obj:`pygsp.plotting`.
+        Dictionary of plotting parameters. See :obj:`pygsp2.plotting`.
         (default is {})
     symmetrize_type : string, optional
         Type of symmetrization to use for the adjacency matrix. See
-        :func:`pygsp.utils.symmetrization` for the options.
+        :func:`pygsp2.utils.symmetrization` for the options.
         (default is 'average')
     dist_type : string, optional
         Type of distance to compute. See
diff --git a/pygsp/graphs/nngraphs/sensor.py b/pygsp2/graphs/nngraphs/sensor.py
similarity index 94%
rename from pygsp/graphs/nngraphs/sensor.py
rename to pygsp2/graphs/nngraphs/sensor.py
index 3bb957a0..5f0ba9f8 100644
--- a/pygsp/graphs/nngraphs/sensor.py
+++ b/pygsp2/graphs/nngraphs/sensor.py
@@ -4,7 +4,7 @@
 
 import numpy as np
 
-from pygsp.graphs import NNGraph  # prevent circular import in Python < 3.5
+from pygsp2.graphs import NNGraph  # prevent circular import in Python < 3.5
 
 
 class Sensor(NNGraph):
@@ -33,7 +33,7 @@ class Sensor(NNGraph):
     -----
 
     The definition of this graph changed in February 2019.
-    See the `GitHub PR <https://github.com/epfl-lts2/pygsp/pull/19>`_.
+    See the `GitHub PR <https://github.com/epfl-lts2/pygsp2/pull/19>`_.
 
     Examples
     --------
diff --git a/pygsp/graphs/nngraphs/sphere.py b/pygsp2/graphs/nngraphs/sphere.py
similarity index 96%
rename from pygsp/graphs/nngraphs/sphere.py
rename to pygsp2/graphs/nngraphs/sphere.py
index e375b5b4..f6c641ea 100644
--- a/pygsp/graphs/nngraphs/sphere.py
+++ b/pygsp2/graphs/nngraphs/sphere.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp.graphs import NNGraph  # prevent circular import in Python < 3.5
+from pygsp2.graphs import NNGraph  # prevent circular import in Python < 3.5
 
 
 class Sphere(NNGraph):
diff --git a/pygsp/graphs/nngraphs/twomoons.py b/pygsp2/graphs/nngraphs/twomoons.py
similarity index 97%
rename from pygsp/graphs/nngraphs/twomoons.py
rename to pygsp2/graphs/nngraphs/twomoons.py
index 72fe45cc..2ad41734 100644
--- a/pygsp/graphs/nngraphs/twomoons.py
+++ b/pygsp2/graphs/nngraphs/twomoons.py
@@ -2,8 +2,8 @@
 
 import numpy as np
 
-from pygsp import utils
-from pygsp.graphs import NNGraph  # prevent circular import in Python < 3.5
+from pygsp2 import utils
+from pygsp2.graphs import NNGraph  # prevent circular import in Python < 3.5
 
 
 class TwoMoons(NNGraph):
diff --git a/pygsp/graphs/path.py b/pygsp2/graphs/path.py
similarity index 100%
rename from pygsp/graphs/path.py
rename to pygsp2/graphs/path.py
diff --git a/pygsp/graphs/randomregular.py b/pygsp2/graphs/randomregular.py
similarity index 99%
rename from pygsp/graphs/randomregular.py
rename to pygsp2/graphs/randomregular.py
index d9d728c0..fb10ce9d 100644
--- a/pygsp/graphs/randomregular.py
+++ b/pygsp2/graphs/randomregular.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/randomring.py b/pygsp2/graphs/randomring.py
similarity index 99%
rename from pygsp/graphs/randomring.py
rename to pygsp2/graphs/randomring.py
index 4c45a0e8..84f07a6d 100644
--- a/pygsp/graphs/randomring.py
+++ b/pygsp2/graphs/randomring.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/ring.py b/pygsp2/graphs/ring.py
similarity index 100%
rename from pygsp/graphs/ring.py
rename to pygsp2/graphs/ring.py
diff --git a/pygsp/graphs/star.py b/pygsp2/graphs/star.py
similarity index 100%
rename from pygsp/graphs/star.py
rename to pygsp2/graphs/star.py
diff --git a/pygsp/graphs/stochasticblockmodel.py b/pygsp2/graphs/stochasticblockmodel.py
similarity index 99%
rename from pygsp/graphs/stochasticblockmodel.py
rename to pygsp2/graphs/stochasticblockmodel.py
index c18aa55b..1b26cf41 100644
--- a/pygsp/graphs/stochasticblockmodel.py
+++ b/pygsp2/graphs/stochasticblockmodel.py
@@ -3,7 +3,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/swissroll.py b/pygsp2/graphs/swissroll.py
similarity index 99%
rename from pygsp/graphs/swissroll.py
rename to pygsp2/graphs/swissroll.py
index 8ec573b2..974af0cf 100644
--- a/pygsp/graphs/swissroll.py
+++ b/pygsp2/graphs/swissroll.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 from . import Graph  # prevent circular import in Python < 3.5
 
 
diff --git a/pygsp/graphs/torus.py b/pygsp2/graphs/torus.py
similarity index 98%
rename from pygsp/graphs/torus.py
rename to pygsp2/graphs/torus.py
index 1124b7a9..625f4104 100644
--- a/pygsp/graphs/torus.py
+++ b/pygsp2/graphs/torus.py
@@ -10,7 +10,7 @@ class Torus(Graph):
     r"""Sampled torus manifold.
 
     On the torus, the graph Fourier transform (GFT) is the Kronecker product
-    between the GFT of two :class:`~pygsp.graphs.Ring` graphs.
+    between the GFT of two :class:`~pygsp2.graphs.Ring` graphs.
 
     Parameters
     ----------
diff --git a/pygsp/learning.py b/pygsp2/learning.py
similarity index 96%
rename from pygsp/learning.py
rename to pygsp2/learning.py
index 79423408..fb422bee 100644
--- a/pygsp/learning.py
+++ b/pygsp2/learning.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.learning` module provides functions to solve learning problems.
+The :mod:`pygsp2.learning` module provides functions to solve learning problems.
 
 Semi-supervized learning
 ========================
@@ -52,7 +52,7 @@ def classification_tikhonov_simplex(G, y, M, tau=0.1, **kwargs):
 
     Parameters
     ----------
-    G : :class:`pygsp.graphs.Graph`
+    G : :class:`pygsp2.graphs.Graph`
     y : array, length G.n_vertices
         Measurements.
     M : array of boolean, length G.n_vertices
@@ -69,7 +69,7 @@ def classification_tikhonov_simplex(G, y, M, tau=0.1, **kwargs):
 
     Examples
     --------
-    >>> from pygsp import graphs, learning
+    >>> from pygsp2 import graphs, learning
     >>> import matplotlib.pyplot as plt
     >>>
     >>> G = graphs.Logo()
@@ -196,7 +196,7 @@ def classification_tikhonov(G, y, M, tau=0):
 
     Parameters
     ----------
-    G : :class:`pygsp.graphs.Graph`
+    G : :class:`pygsp2.graphs.Graph`
     y : array, length G.n_vertices
         Measurements.
     M : array of boolean, length G.n_vertices
@@ -211,7 +211,7 @@ def classification_tikhonov(G, y, M, tau=0):
 
     Examples
     --------
-    >>> from pygsp import graphs, learning
+    >>> from pygsp2 import graphs, learning
     >>> import matplotlib.pyplot as plt
     >>>
     >>> G = graphs.Logo()
@@ -268,7 +268,7 @@ def regression_tikhonov(G, y, M, tau=0):
 
     Parameters
     ----------
-    G : :class:`pygsp.graphs.Graph`
+    G : :class:`pygsp2.graphs.Graph`
     y : array, length G.n_vertices
         Measurements.
     M : array of boolean, length G.n_vertices
@@ -283,7 +283,7 @@ def regression_tikhonov(G, y, M, tau=0):
 
     Examples
     --------
-    >>> from pygsp import graphs, filters, learning
+    >>> from pygsp2 import graphs, filters, learning
     >>> import matplotlib.pyplot as plt
     >>>
     >>> G = graphs.Sensor(N=100, seed=42)
diff --git a/pygsp/optimization.py b/pygsp2/optimization.py
similarity index 94%
rename from pygsp/optimization.py
rename to pygsp2/optimization.py
index d296ebcb..b48a10a6 100644
--- a/pygsp/optimization.py
+++ b/pygsp2/optimization.py
@@ -1,11 +1,11 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.optimization` module provides tools to solve convex
+The :mod:`pygsp2.optimization` module provides tools to solve convex
 optimization problems on graphs.
 """
 
-from pygsp import utils
+from pygsp2 import utils
 
 
 logger = utils.build_logger(__name__)
@@ -28,7 +28,7 @@ def prox_tv(x, gamma, G, A=None, At=None, nu=1, tol=10e-4, maxit=200, use_matrix
 
     This function computes the TV proximal operator for graphs. The TV norm
     is the one norm of the gradient. The gradient is defined in the
-    function :meth:`pygsp.graphs.Graph.grad`.
+    function :meth:`pygsp2.graphs.Graph.grad`.
     This function requires the PyUNLocBoX to be executed.
 
     This function solves:
diff --git a/pygsp/plotting.py b/pygsp2/plotting.py
similarity index 97%
rename from pygsp/plotting.py
rename to pygsp2/plotting.py
index 4dab717b..315091fb 100644
--- a/pygsp/plotting.py
+++ b/pygsp2/plotting.py
@@ -1,17 +1,17 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.plotting` module implements functionality to plot PyGSP objects
+The :mod:`pygsp2.plotting` module implements functionality to plot PyGSP2 objects
 with a `pyqtgraph <https://www.pyqtgraph.org>`_ or `matplotlib
 <https://matplotlib.org>`_ drawing backend (which can be controlled by the
 :data:`BACKEND` constant or individually for each plotting call).
 
 Most users won't use this module directly.
-Graphs (from :mod:`pygsp.graphs`) are to be plotted with
-:meth:`pygsp.graphs.Graph.plot` and
-:meth:`pygsp.graphs.Graph.plot_spectrogram`.
-Filters (from :mod:`pygsp.filters`) are to be plotted with
-:meth:`pygsp.filters.Filter.plot`.
+Graphs (from :mod:`pygsp2.graphs`) are to be plotted with
+:meth:`pygsp2.graphs.Graph.plot` and
+:meth:`pygsp2.graphs.Graph.plot_spectrogram`.
+Filters (from :mod:`pygsp2.filters`) are to be plotted with
+:meth:`pygsp2.filters.Filter.plot`.
 
 .. data:: BACKEND
 
@@ -28,7 +28,7 @@
 
 import numpy as np
 
-from pygsp import utils
+from pygsp2 import utils
 
 
 _logger = utils.build_logger(__name__)
@@ -190,7 +190,7 @@ def _plot_filter(filters, n, eigenvalues, sum, labels, title, ax, **kwargs):
     eigenvalues : boolean
         Whether to show the eigenvalues of the graph Laplacian.
         The eigenvalues should have been computed with
-        :meth:`~pygsp.graphs.Graph.compute_fourier_basis`.
+        :meth:`~pygsp2.graphs.Graph.compute_fourier_basis`.
         By default, the eigenvalues are shown if they are available.
     sum : boolean
         Whether to plot the sum of the squared magnitudes of the filters.
@@ -356,7 +356,7 @@ def _plot_graph(G, vertex_color, vertex_size, highlight,
         Title of the figure.
     backend: {'matplotlib', 'pyqtgraph', None}
         Defines the drawing backend to use.
-        Defaults to :data:`pygsp.plotting.BACKEND`.
+        Defaults to :data:`pygsp2.plotting.BACKEND`.
 
     Returns
     -------
@@ -415,7 +415,8 @@ def normalize(x):
         Set intercept value in G.plotting["normalize_intercept"]
         with value in [0, 1], default is .25.
         """
-        ptp = x.ptp()
+        #ptp = x.ptp()
+        ptp = np.ptp(x)
         if ptp == 0:
             return np.full(x.shape, 0.5)
         else:
@@ -652,7 +653,7 @@ def _plot_spectrogram(G, node_idx):
     >>> G.plot_spectrogram()
 
     """
-    from pygsp import features
+    from pygsp2 import features
 
     qtg, _, _ = _import_qtg()
 
diff --git a/pygsp/reduction.py b/pygsp2/reduction.py
similarity index 98%
rename from pygsp/reduction.py
rename to pygsp2/reduction.py
index 65660dcd..611e9f73 100644
--- a/pygsp/reduction.py
+++ b/pygsp2/reduction.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.reduction` module implements functionalities for the reduction
+The :mod:`pygsp2.reduction` module implements functionalities for the reduction
 of graphs' vertex set while keeping the graph structure.
 
 .. autosummary::
@@ -20,7 +20,7 @@
 from scipy import sparse, stats
 from scipy.sparse import linalg
 
-from pygsp import graphs, filters, utils
+from pygsp2 import graphs, filters, utils
 
 
 logger = utils.build_logger(__name__)
@@ -55,7 +55,7 @@ def graph_sparsify(M, epsilon, maxiter=10, seed=None):
 
     Examples
     --------
-    >>> from pygsp import reduction
+    >>> from pygsp2 import reduction
     >>> from matplotlib import pyplot as plt
     >>> G = graphs.Sensor(100, k=20, distributed=True, seed=1)
     >>> Gs = reduction.graph_sparsify(G, epsilon=0.4, seed=1)
@@ -115,7 +115,8 @@ def graph_sparsify(M, epsilon, maxiter=10, seed=None):
         q = round(N * np.log(N) * 9 * C**2 / (epsilon**2))
 
         results = dist.rvs(size=int(q))
-        spin_counts = stats.itemfreq(results).astype(int)
+        spin_values, spin_counts = np.unique(results, return_counts=True)
+        spin_counts = np.column_stack((spin_values, spin_counts)).astype(int)
         per_spin_weights = weights / (q * Pe)
 
         counts = np.zeros(np.shape(weights)[0])
@@ -240,7 +241,7 @@ def graph_multiresolution(G, levels, sparsify=True, sparsify_eps=None,
 
     Examples
     --------
-    >>> from pygsp import reduction
+    >>> from pygsp2 import reduction
     >>> levels = 5
     >>> G = graphs.Sensor(N=512)
     >>> G.compute_fourier_basis()
diff --git a/pygsp/utils.py b/pygsp2/utils.py
similarity index 96%
rename from pygsp/utils.py
rename to pygsp2/utils.py
index 291f78b2..ff443118 100644
--- a/pygsp/utils.py
+++ b/pygsp2/utils.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 r"""
-The :mod:`pygsp.utils` module implements some utility functions used throughout
+The :mod:`pygsp2.utils` module implements some utility functions used throughout
 the package.
 """
 
@@ -76,13 +76,13 @@ def loadmat(path):
 
     Examples
     --------
-    >>> from pygsp import utils
+    >>> from pygsp2 import utils
     >>> data = utils.loadmat('pointclouds/bunny')
     >>> data['bunny'].shape
     (2503, 3)
 
     """
-    data = pkgutil.get_data('pygsp', 'data/' + path + '.mat')
+    data = pkgutil.get_data('pygsp2', 'data/' + path + '.mat')
     data = io.BytesIO(data)
     return scipy.io.loadmat(data)
 
@@ -105,7 +105,7 @@ def distanz(x, y=None):
 
     Examples
     --------
-    >>> from pygsp import utils
+    >>> from pygsp2 import utils
     >>> x = np.arange(3)
     >>> utils.distanz(x, x)
     array([[0., 1., 2.],
@@ -213,7 +213,7 @@ def symmetrize(W, method='average'):
 
     Examples
     --------
-    >>> from pygsp import utils
+    >>> from pygsp2 import utils
     >>> W = np.array([[0, 3, 0], [3, 1, 6], [4, 2, 3]], dtype=float)
     >>> W
     array([[0., 3., 0.],
@@ -297,7 +297,7 @@ def rescale_center(x):
 
     Examples
     --------
-    >>> from pygsp import utils
+    >>> from pygsp2 import utils
     >>> x = np.array([[1, 6], [2, 5], [3, 4]])
     >>> utils.rescale_center(x)
     array([[-1. ,  1. ],
@@ -322,7 +322,7 @@ def compute_log_scales(lmin, lmax, Nscales, t1=1, t2=2):
     lmin : float
         Smallest non-zero eigenvalue.
     lmax : float
-        Largest eigenvalue, i.e. :py:attr:`pygsp.graphs.Graph.lmax`.
+        Largest eigenvalue, i.e. :py:attr:`pygsp2.graphs.Graph.lmax`.
     Nscales : int
         Number of scales.
 
@@ -333,7 +333,7 @@ def compute_log_scales(lmin, lmax, Nscales, t1=1, t2=2):
 
     Examples
     --------
-    >>> from pygsp import utils
+    >>> from pygsp2 import utils
     >>> utils.compute_log_scales(1, 10, 3)
     array([2.       , 0.4472136, 0.1      ])
 
diff --git a/examples/utils.py b/pygsp2/utils_examples.py
similarity index 78%
rename from examples/utils.py
rename to pygsp2/utils_examples.py
index a737edb7..23ff6343 100644
--- a/examples/utils.py
+++ b/pygsp2/utils_examples.py
@@ -1,4 +1,8 @@
-"""Utils functions used in the examples.
+r"""
+Utils Examples
+=====
+
+Utils functions used in the examples.
 
 This module contains functions to run examples of graph signal processing.
 
@@ -11,6 +15,7 @@
 * metro_simulation.py
 * metro_simulation2.py
 """
+import os
 import json
 import utm
 import networkx as nx
@@ -19,6 +24,24 @@
 import matplotlib.pyplot as plt
 import numpy as np
 
+ASSETS_METRO = [
+    {
+        "filename": "2023.11 Matriz_baj_SS_MH.xlsb",
+        "url": r"https://www.dtpm.cl/descargas/modelos_y_matrices/Tablas%20de%20subidas%20y%20bajadas%20nov23.zip"
+    },
+    {
+        "filename": "santiago_metro_stations_coords.geojson",
+        "url": r"https://zenodo.org/records/11637462/files/santiago_metro_stations_coords.geojson"
+    },
+    {
+        "filename": "santiago_metro_stations_connections.txt",
+        "url": r"https://zenodo.org/records/11637462/files/santiago_metro_stations_connections.txt"
+    }
+]
+
+ASSETS = {
+    "metro": ASSETS_METRO
+}
 
 def make_metro_graph(edgesfile='santiago_metro_stations_connections.txt',
                      coordsfile='santiago_metro_stations_coords.geojson'):
@@ -173,3 +196,32 @@ def plot_signal_in_graph(G, signal, title='Graph Signal', label=''):
     plt.tight_layout()
 
     return fig, ax
+
+def fetch_data(output_dir, database="metro"):
+    """ 
+    Fetch data from the internet and save it in the output_dir.
+
+    Parameters
+    ----------
+    output_dir : str
+        Directory where the data will be saved.
+    database : str, optional
+        Database to fetch data from. Options are: "metro".
+    """ 
+    for asset_dict in ASSETS[database]:
+        filename = asset_dict["filename"]
+        url = asset_dict["url"]
+        assets_filepath = os.path.join(output_dir, filename)
+        if not os.path.isfile(assets_filepath):
+            import requests
+            import zipfile
+            import io
+            print(f'Downloading data file to:\n {assets_filepath}')
+            r = requests.get(url)
+            if url.endswith('.zip'):
+                z = zipfile.ZipFile(io.BytesIO(r.content))
+                z.extractall(output_dir)
+            else:
+                with open(assets_filepath, 'wb') as f:
+                    f.write(r.content)
+
diff --git a/setup.py b/setup.py
index 7389b433..bf0a825e 100644
--- a/setup.py
+++ b/setup.py
@@ -5,33 +5,40 @@
 
 
 setup(
-    name='PyGSP',
-    version='0.5.1',
+    name='pygsp2',
+    version='2.0.3',
     description='Graph Signal Processing in Python',
     long_description=open('README.rst').read(),
     long_description_content_type='text/x-rst',
     author='EPFL LTS2',
-    url='https://github.com/epfl-lts2/pygsp',
+    url='https://github.com/gsp-eeg/pygsp2',
     project_urls={
-        'Documentation': 'https://pygsp.readthedocs.io',
-        'Download': 'https://pypi.org/project/PyGSP',
-        'Source Code': 'https://github.com/epfl-lts2/pygsp',
-        'Bug Tracker': 'https://github.com/epfl-lts2/pygsp/issues',
-        'Try It Online': 'https://mybinder.org/v2/gh/epfl-lts2/pygsp/master?urlpath=lab/tree/examples/playground.ipynb',
+        'Documentation': 'https://pygsp2.readthedocs.io',
+        'Download': 'https://pypi.org/project/pygsp2',
+        'Source Code': 'https://github.com/gsp-eeg/pygsp2',
+        'Bug Tracker': 'https://github.com/gsp-eeg/pygsp2/issues',
+        'Try It Online': 'https://mybinder.org/v2/gh/epfl-lts2/pygsp2/master?urlpath=lab/tree/examples/playground.ipynb',
     },
     packages=[
-        'pygsp',
-        'pygsp.graphs',
-        'pygsp.graphs.nngraphs',
-        'pygsp.filters',
-        'pygsp.tests',
+        'pygsp2',
+        'pygsp2.graphs',
+        'pygsp2.graphs.nngraphs',
+        'pygsp2.filters',
+        'pygsp2.tests',
     ],
-    package_data={'pygsp': ['data/pointclouds/*.mat']},
-    test_suite='pygsp.tests.suite',
+    package_data={'pygsp2': ['data/pointclouds/*.mat']},
+    test_suite='pygsp2.tests.suite',
     python_requires='>=3.7',
     install_requires=[
         'numpy',
         'scipy',
+        'pandas',
+        'networkx',
+        'geopy',
+        'matplotlib',
+        'unidecode',
+        'utm',
+        'pyxlsb'
     ],
     extras_require={
         # Optional dependencies for development. Some bring additional
@@ -39,7 +46,7 @@
         'dev': [
             # Import and export.
             'networkx',
-            'json',
+            #'json',
             'utm',
             'geopy',
             'pyxlsb',
@@ -90,5 +97,7 @@
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
+        'Programming Language :: Python :: 3.10',
+        'Programming Language :: Python :: 3.11',
     ],
 )


Test patch:
diff --git a/pygsp/tests/__init__.py b/pygsp2/tests/__init__.py
similarity index 75%
rename from pygsp/tests/__init__.py
rename to pygsp2/tests/__init__.py
index c5a958a3..9639690c 100644
--- a/pygsp/tests/__init__.py
+++ b/pygsp2/tests/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite of the PyGSP package, broken by modules.
+Test suite of the PyGSP2 package, broken by modules.
 
 """
 
@@ -13,6 +13,7 @@
 from . import test_learning
 from . import test_docstrings
 from . import test_plotting
+from . import test_utils_examples
 
 
 suite = unittest.TestSuite([
@@ -22,4 +23,5 @@
     test_learning.suite,
     test_docstrings.suite,
     test_plotting.suite,  # TODO: can SIGSEGV if not last
+    test_utils_examples.suite, # TODO: test function
 ])
diff --git a/pygsp/tests/test_docstrings.py b/pygsp2/tests/test_docstrings.py
similarity index 76%
rename from pygsp/tests/test_docstrings.py
rename to pygsp2/tests/test_docstrings.py
index 205f14d5..f14ba7f3 100644
--- a/pygsp/tests/test_docstrings.py
+++ b/pygsp2/tests/test_docstrings.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite for the docstrings of the pygsp package.
+Test suite for the docstrings of the pygsp2 package.
 
 """
 
@@ -25,23 +25,23 @@ def test_docstrings(root, ext, setup=None):
 
 def setup(doctest):
     import numpy
-    import pygsp
+    import pygsp2
     doctest.globs = {
-        'graphs': pygsp.graphs,
-        'filters': pygsp.filters,
-        'utils': pygsp.utils,
+        'graphs': pygsp2.graphs,
+        'filters': pygsp2.filters,
+        'utils': pygsp2.utils,
         'np': numpy,
     }
 
 
 def teardown(doctest):
     """Close matplotlib figures to avoid warning and save memory."""
-    import pygsp
-    pygsp.plotting.close_all()
+    import pygsp2
+    pygsp2.plotting.close_all()
 
 
 # Docstrings from API reference.
-suite_reference = test_docstrings('pygsp', '.py', setup)
+suite_reference = test_docstrings('pygsp2', '.py', setup)
 
 # Docstrings from tutorials. No setup to not forget imports.
 suite_tutorials = test_docstrings('.', '.rst')
diff --git a/pygsp/tests/test_filters.py b/pygsp2/tests/test_filters.py
similarity index 99%
rename from pygsp/tests/test_filters.py
rename to pygsp2/tests/test_filters.py
index ba6c2d3e..5b189ce7 100644
--- a/pygsp/tests/test_filters.py
+++ b/pygsp2/tests/test_filters.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite for the filters module of the pygsp package.
+Test suite for the filters module of the pygsp2 package.
 
 """
 
@@ -10,7 +10,7 @@
 
 import numpy as np
 
-from pygsp import graphs, filters
+from pygsp2 import graphs, filters
 
 
 class TestCase(unittest.TestCase):
diff --git a/pygsp/tests/test_graphs.py b/pygsp2/tests/test_graphs.py
similarity index 99%
rename from pygsp/tests/test_graphs.py
rename to pygsp2/tests/test_graphs.py
index 31ada6ec..1006409a 100644
--- a/pygsp/tests/test_graphs.py
+++ b/pygsp2/tests/test_graphs.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite for the graphs module of the pygsp package.
+Test suite for the graphs module of the pygsp2 package.
 
 """
 
@@ -20,7 +20,7 @@
 import graph_tool.generation
 from skimage import data, img_as_float
 
-from pygsp import graphs
+from pygsp2 import graphs
 
 
 class TestCase(unittest.TestCase):
@@ -691,7 +691,7 @@ def test_grid2d_diagonals(self):
 class TestImportExport(unittest.TestCase):
 
     def test_networkx_export_import(self):
-        # Export to networkx and reimport to PyGSP
+        # Export to networkx and reimport to PyGSP2
 
         # Exporting the Bunny graph
         g = graphs.Bunny()
@@ -708,7 +708,7 @@ def test_networkx_import_export(self):
                                       nx.adjacency_matrix(g).todense())
 
     def test_graphtool_export_import(self):
-        # Export to graph tool and reimport to PyGSP directly
+        # Export to graph tool and reimport to PyGSP2 directly
         # The exported graph is a simple one without an associated Signal
         g = graphs.Bunny()
         g_gt = g.to_graphtool()
@@ -737,7 +737,7 @@ def test_graphtool_multiedge_import(self):
         self.assertEqual(g3.W[3, 6], 9.0)
 
     def test_graphtool_import_export(self):
-        # Import to PyGSP and export again to graph tool directly
+        # Import to PyGSP2 and export again to graph tool directly
         # create a random graphTool graph that does not contain multiple edges and no signal
         rng = np.random.default_rng(42)
         graph_gt = gt.generation.random_graph(100, lambda: (rng.poisson(4), rng.poisson(4)))
diff --git a/pygsp/tests/test_learning.py b/pygsp2/tests/test_learning.py
similarity index 98%
rename from pygsp/tests/test_learning.py
rename to pygsp2/tests/test_learning.py
index 3d18b4df..ac845340 100644
--- a/pygsp/tests/test_learning.py
+++ b/pygsp2/tests/test_learning.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite for the learning module of the pygsp package.
+Test suite for the learning module of the pygsp2 package.
 
 """
 
@@ -9,7 +9,7 @@
 
 import numpy as np
 
-from pygsp import graphs, filters, learning
+from pygsp2 import graphs, filters, learning
 from scipy import spatial
 
 
diff --git a/pygsp/tests/test_plotting.py b/pygsp2/tests/test_plotting.py
similarity index 98%
rename from pygsp/tests/test_plotting.py
rename to pygsp2/tests/test_plotting.py
index 5c46ac12..7d3ef65b 100644
--- a/pygsp/tests/test_plotting.py
+++ b/pygsp2/tests/test_plotting.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite for the plotting module of the pygsp package.
+Test suite for the plotting module of the pygsp2 package.
 
 """
 
@@ -12,7 +12,7 @@
 from matplotlib import pyplot as plt
 from skimage import data, img_as_float
 
-from pygsp import graphs, filters, plotting
+from pygsp2 import graphs, filters, plotting
 
 
 class TestGraphs(unittest.TestCase):
diff --git a/pygsp/tests/test_utils.py b/pygsp2/tests/test_utils.py
similarity index 89%
rename from pygsp/tests/test_utils.py
rename to pygsp2/tests/test_utils.py
index af23f4b8..194cb503 100644
--- a/pygsp/tests/test_utils.py
+++ b/pygsp2/tests/test_utils.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 """
-Test suite for the utils module of the pygsp package.
+Test suite for the utils module of the pygsp2 package.
 
 """
 
@@ -10,7 +10,7 @@
 import numpy as np
 from scipy import sparse
 
-from pygsp import graphs, utils
+from pygsp2 import graphs, utils
 
 
 class TestCase(unittest.TestCase):
diff --git a/pygsp2/tests/test_utils2.py b/pygsp2/tests/test_utils2.py
new file mode 100644
index 00000000..7416d7b0
--- /dev/null
+++ b/pygsp2/tests/test_utils2.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+
+"""
+Test suite for the utils module of the pygsp2 package.
+
+"""
+
+import unittest
+import pandas as pd
+from unidecode import unidecode
+
+from pygsp2 import utils_examples
+
+
+class TestCase(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        pass
+
+    @classmethod
+    def tearDownClass(cls):
+        pass
+
+    def test_graphs(self):
+        edgesfile='../data/santiago_metro_stations_connections.txt',
+        coordsfile='../data/santiago_metro_stations_coords.geojson'
+        G, pos = utils_examples.make_metro_graph(edgesfile, coordsfile)
+        self.assertRaises(ValueError, utils_examples.make_metro_graph, (edgesfile, coordsfile), 'sum')
+
+        commutes = pd.read_excel('data/2023.11 Matriz_baj_SS_MH.xlsb', header=1,
+                             sheet_name='bajadas_prom_laboral')
+        stations = [name.upper() for name in list(G.nodes)]
+        stations = [unidecode(station) for station in stations]
+        mc, s = utils_examples.metro_database_preprocessing(commutes, stations)
+        fig, ax = utils_examples.plot_signal_in_graph(G, s, 'utils_examples test')
+
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestCase)