Plots and visualizations

import numpy as np
import matplotlib.pyplot as plt
import multipers as mp
from multipers.data import noisy_annulus
from multipers.filtrations.density import KDE
np.random.seed(1)
X = noisy_annulus(n1=200, n2=200) 
codensity = - (KDE(bandwidth=0.2, return_log=True).fit(X).score_samples(X))
plt.scatter(X[:,0], X[:,1], s=20, c=-codensity);
plt.gca().set_aspect(1);
[KeOps] Warning : CUDA libraries not found or could not be loaded; Switching to CPU only.
../_images/b5cd5a99c0da23c04c61b65fc9056869db3ee9cc00e36ee4ebaa0f25012ac9e8.png

Rips complex

from multipers.filtrations import RipsLowerstar
st = RipsLowerstar(points=X, function=codensity).collapse_edges(-2).expansion(2)
mma = mp.module_approximation(st)
mma.plot(degree = 1)
../_images/c36cf77e522b18e4862aa17dd5ad1c4270b4fc1061b5761990c2664a7c1f2926.png
from multipers.plots import plot_simplicial_complex
radius = .5
codens = 2.85
plot_simplicial_complex(st,X, radius, codens, mma=mma, degree=1)
plt.gcf().set_size_inches(9, 4)
../_images/a502cebe34f6ee00b3c90a0b570f4570a424f6f66d1223a830bc18c7eb7375db.png
from multipers.plots import plot_simplicial_complex
radius = .6
codens = 3
plot_simplicial_complex(st,X, radius, codens, mma=mma, degree=1)
plt.gcf().set_size_inches(9, 4)
../_images/a21796e7a592e0a967cead3a2459be96b21cf02bd947929e8aa6d407623bdbce.png
from multipers.plots import plot_simplicial_complex
radius = 2.5
codens = 2.4
plot_simplicial_complex(st,X, radius, codens, mma=mma, degree=1)
plt.gcf().set_size_inches(9, 4)
../_images/09cb10122a10298e2eb06278106fc4bd3d4789f2e94f9a2a36178804316056ea.png
from multipers.plots import plot_simplicial_complex
radius = .5
codens = 2.75
plot_simplicial_complex(st,X, radius, codens, mma=mma, degree=1)
plt.gcf().set_size_inches(9, 4)
../_images/f7c0b99f1c7b9b6c9e11a426eca9d78862d5330ce81116673c332d095a96627b.png

Delaunay-Lowerstar

from multipers.filtrations import DelaunayLowerstar
st_delaunay = DelaunayLowerstar(points = X, function=codensity)
mma = mp.module_approximation(st_delaunay)
from multipers.plots import plot_point_cloud
radius = .25
codens = 2.85
plot_point_cloud(X, codensity,radius,codens, mma=mma,degree=1)
plt.gcf().set_size_inches(9, 4)
../_images/039d56ca51d983ac6c3574e4c08e45945884c8a0d0de96325df5b87a6f851134.png
from multipers.plots import plot_point_cloud
radius = .6
codens = 2.85
plot_point_cloud(X, codensity,radius,codens, mma=mma,degree=1)
plt.gcf().set_size_inches(9, 4)
../_images/8811f6b5349b6889c800e6f14515269dc6a8443a2870c6c1e3c9993ed5a3ba90.png

Signed measures

fig, (a,b) = plt.subplots(ncols=2, figsize=(12,5))
plt.sca(a)
sm, = mp.signed_measure(st, degree=1, plot=True, invariant="hilbert");
plt.sca(b)
mp.point_measure.integrate_measure(*sm, plot=True);
../_images/0c95e39ba26921cbec73472931c2d210c5fe0e041895d262f78062ec7a59e7ed.png
fig, (a,b) = plt.subplots(ncols=2, figsize=(12,5))
plt.sca(a)
(pts,w), = mp.signed_measure(st_delaunay,  plot=True, invariant="euler");
plt.sca(b)
mp.point_measure.integrate_measure(pts, w, plot=True); # only the positive part here
../_images/8a107195e7b6f5d30acced4a98645723bac09902c80cbb20fecf933506774c2e.png

Line slices

s = mp.Slicer(st_delaunay).minpres(1)
sm, = mp.signed_measure(
    s.grid_squeeze(strategy="regular_closest", resolution=50),
    plot=True,
    degree=1,
    invariant="rectangle"
);

basepoint= np.asarray([1,4.1])
direction= np.array([.5,1.])
bc = mp.point_measure.barcode_from_rank_sm(sm=sm, basepoint=basepoint, direction=direction)
slope=direction[1]/direction[0]
plt.axline(basepoint,slope=slope,c="k")
for bar in bc:
    bar = basepoint[None] + direction[None]*bar[:,None]
    plt.plot(bar[:,0], bar[:,1], 'ro-', lw=5)
../_images/96bdeabb33a888d17a742c7dff78d1bc15432940487f6021ed06eb5d4c6f705c.png
sm_hook, = mp.signed_measure(
    s.grid_squeeze(strategy="regular", resolution=50),
    degree=1,
    invariant="hook",
)
mp.plots.plot_signed_measure(sm_hook, alpha=.5)
../_images/55a8f9c8a1899270660249b18d072ca2e3eea4a8016dddd085be7ab2592edd8c.png
from gudhi.wasserstein import wasserstein_distance
bc_ground_truth = s.persistence_on_line(basepoint=basepoint, direction=direction)[1]
print("Bottleneck error:",wasserstein_distance(bc,bc_ground_truth)) # the `grid_squeeze` introduced an error 
Bottleneck error: 0.11974205620221257
mma_delaunay = mp.module_approximation(s)
mma_delaunay.plot(1)
bc2 = mma_delaunay.barcode2(basepoint=basepoint, direction=direction, keep_inf=False)[1]
slope=direction[1]/direction[0]
plt.axline(basepoint,slope=slope,c="k")
for bar in bc2:
    bar = basepoint[None] + direction[None]*bar[:,None]
    plt.plot(bar[:,0], bar[:,1], 'ro-', lw=5)
    
print("Bottleneck error:", wasserstein_distance(bc2, bc_ground_truth))
Bottleneck error: 0.0007861602741707774
../_images/8270ff3734e39e6541c651d64d636d9f6a7130c63add849a0fe4bafbd0a4a4ef.png