Toroidal coordinates on surface of genus two

An example of how, in the presence of more than one prominent circular feature in the data, the toroidal coordinates algorithm returns circle-valued maps that are geometrically less correlated and easier to interpret than the ones returned by running the circular coordinates algorithm on each individual class.

[1]:
import matplotlib.pyplot as plt
from dreimac import CircularCoords, ToroidalCoords, GeometryExamples, PlotUtils, CircleMapUtils
from persim import plot_diagrams

We start by displaying the data, which consists of a pointcloud in 3D.

[2]:
X = GeometryExamples.genus_two_surface()

fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(projection="3d")
ax.scatter(X[:,0], X[:,1], X[:,2], s=0.1)
PlotUtils.set_axes_equal(ax) ; plt.axis("off") ; fig.subplots_adjust(top=1, bottom=0, left=0, right=1)
../_images/notebooks_genusTwoSurface_3_0.png

Compute and display the Rips persistent cohomology.

[3]:
n_landmarks = 750

tc = ToroidalCoords(X, n_landmarks=n_landmarks)
plot_diagrams(tc._dgms)
../_images/notebooks_genusTwoSurface_5_0.png

We now construct two sets of four circle-valued maps. For the first set, we use the toroidal coordinates with input the four most prominent persistent cohomology classes; for the second, we run the circular coordinates algorithm on each of the four individual classes.

[4]:
cohomology_classes = [0, 1, 2, 3]
toroidal_coords = tc.get_coordinates(cocycle_idxs=cohomology_classes)

We display the circle-valued representations obtained with toroidal coordinates using two different colorings.

[5]:
fig = plt.figure(figsize=(9,4))
fig.suptitle("Toroidal coordinates with cyclic colormap", fontsize=20)
for i, coordinate in enumerate(toroidal_coords):
    plt.subplot(1, len(toroidal_coords), i + 1)
    plt.scatter(X[:, 1], X[:, 0], s=20, c=CircleMapUtils.to_sinebow(CircleMapUtils.center(coordinate)))
    plt.title("toroidal\ncoordinate " + str(i+1))
    plt.gca().set_aspect("equal") ; _ = plt.axis("off")
../_images/notebooks_genusTwoSurface_9_0.png
[6]:
fig = plt.figure(figsize=(9, 4))
fig.suptitle("Toroidal coordinates with levelset colormap", fontsize=20)
for i, coordinate in enumerate(toroidal_coords):
    plt.subplot(1, len(toroidal_coords), i + 1)
    plt.scatter(
        X[:, 1],
        X[:, 0],
        s=2,
        c=CircleMapUtils.levelset_coloring(CircleMapUtils.center(coordinate)),
    )
    plt.title("toroidal\ncoordinate " + str(i + 1))
    plt.gca().set_aspect("equal")
    _ = plt.axis("off")
../_images/notebooks_genusTwoSurface_10_0.png
[7]:
cc = CircularCoords(X, n_landmarks=n_landmarks)
circular_coords1 = cc.get_coordinates(cocycle_idx=cohomology_classes[0])
circular_coords2 = cc.get_coordinates(cocycle_idx=cohomology_classes[1])
circular_coords3 = cc.get_coordinates(cocycle_idx=cohomology_classes[2])
circular_coords4 = cc.get_coordinates(cocycle_idx=cohomology_classes[3])
circular_coords = [ circular_coords1, circular_coords2, circular_coords3, circular_coords4 ]

We display the circle-valued representations obtained with circular coordinates.

[8]:
fig = plt.figure(figsize=(9,4))
fig.suptitle("Circular coordinates with cyclic colormap", fontsize=20)
for i, coordinate in enumerate(circular_coords):
    plt.subplot(1, len(toroidal_coords), i + 1)
    plt.scatter(X[:, 1], X[:, 0], s=2, c=CircleMapUtils.to_sinebow(coordinate))
    plt.title("circular\ncoordinate " + str(i+1))
    plt.gca().set_aspect("equal") ; _ = plt.axis("off")
../_images/notebooks_genusTwoSurface_13_0.png
[9]:
fig = plt.figure(figsize=(9, 4))
fig.suptitle("Circular coordinates with levelset colormap", fontsize=20)
for i, coordinate in enumerate(circular_coords):
    plt.subplot(1, len(toroidal_coords), i + 1)
    plt.scatter(
        X[:, 1],
        X[:, 0],
        s=2,
        c=CircleMapUtils.levelset_coloring(CircleMapUtils.center(coordinate)),
    )
    plt.title("toroidal\ncoordinate " + str(i + 1))
    plt.gca().set_aspect("equal")
    _ = plt.axis("off")
../_images/notebooks_genusTwoSurface_14_0.png