Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move tutorials to Quarto #638

Merged
merged 15 commits into from
Jul 11, 2023
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Manifolds"
uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"
authors = ["Seth Axen <[email protected]>", "Mateusz Baran <[email protected]>", "Ronny Bergmann <[email protected]>", "Antoine Levitt <[email protected]>"]
version = "0.8.73"
version = "0.8.74"

[deps]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Expand Down
6 changes: 5 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ makedocs(
sitename="Manifolds.jl",
pages=[
"Home" => "index.md",
"How to..." => ["🚀 Get Started with `Manifolds.jl`" => "tutorials/getstarted.md"],
"How to..." => [
"🚀 Get Started with `Manifolds.jl`" => "tutorials/getstarted.md",
"work in charts" => "tutorials/working-in-charts.md",
"perform Hand gesture analysis" => "tutorials/hand-gestures.md",
],
"Manifolds" => [
"Basic manifolds" => [
"Centered matrices" => "manifolds/centeredmatrices.md",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions tutorials/Project.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
[deps]
BoundaryValueDiffEq = "764a87c0-6b3e-53db-9096-fe964310641d"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"
ManifoldsBase = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"

[compat]
kellertuer marked this conversation as resolved.
Show resolved Hide resolved
CSV = "0.10"
DataFrames = "1"
IJulia = "1"
Manifolds = "0.8.46"
ManifoldsBase = "0.14.5"
MultivariateStats = "0.10"
71 changes: 0 additions & 71 deletions tutorials/hand-gestures.jl

This file was deleted.

110 changes: 110 additions & 0 deletions tutorials/hand-gestures.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: Hand gesture analysis
---

In this tutorial we will learn how to use Kendall's shape space to analyze hand gesture data.

```{julia}
#| echo: false
#| code-fold: true
#| output: false
using Pkg;
cd(@__DIR__)
Pkg.activate("."); # for reproducibility use the local tutorial environment.
using Markdown
```

Let's start by loading libraries required for our work.

```{julia}
using Manifolds, CSV, DataFrames, Plots, MultivariateStats
```

Our first function loads dataset of hand gestures, described [here](https://geomstats.github.io/notebooks/14_real_world_applications__hand_poses_analysis_in_kendall_shape_space.html).

```{julia}

kellertuer marked this conversation as resolved.
Show resolved Hide resolved
function load_hands()
hands_url = "https://raw.githubusercontent.com/geomstats/geomstats/master/geomstats/datasets/data/hands/hands.txt"
hand_labels_url = "https://raw.githubusercontent.com/geomstats/geomstats/master/geomstats/datasets/data/hands/labels.txt"

hands = Matrix(CSV.read(download(hands_url), DataFrame, header=false))
hands = reshape(hands, size(hands, 1), 3, 22)
hand_labels = CSV.read(download(hand_labels_url), DataFrame, header=false).Column1
return hands, hand_labels
end
```

The following code plots a sample gesture as a 3D scatter plot of points.
```{julia}
hands, hand_labels = load_hands()
scatter3d(hands[1, 1, :], hands[1, 2, :], hands[1, 3, :])
```

Each gesture is represented by 22 landmarks in $ℝ³$, so we use the appropriate Kendall's shape space
```{julia}
Mshape = KendallsShapeSpace(3, 22)
```

Hands read from the dataset are projected to the shape space to remove translation
and scaling variability. Rotational variability is then handled using the quotient
structure of ``[`KendallsShapeSpace`](@ref)``{=commonmark}
```{julia}
#| output: false
hands_projected = [project(Mshape, hands[i, :, :]) for i in axes(hands, 1)]
```

In the next part let's do tangent space PCA. This starts with computing a mean point and computing
logithmic maps at mean to each point in the dataset.
```{julia}
#| output: false
mean_hand = mean(Mshape, hands_projected)
hand_logs = [log(Mshape, mean_hand, p) for p in hands_projected]
```

For a tangent PCA, we need coordinates in a basis.
Some libraries skip this step because the representation of tangent vectors
forms a linear subspace of an Euclidean space so PCA automatically detects
which directions have no variance but this is a more generic way to solve
this issue.
```{julia}
#| output: false
B = get_basis(Mshape, mean_hand, ProjectedOrthonormalBasis(:svd))
hand_log_coordinates = [get_coordinates(Mshape, mean_hand, X, B) for X in hand_logs]
```

This code prepares data for MultivariateStats -- `mean=0` is set because we've centered
the data geometrically to `mean_hand` in the code above.
```{julia}
red_coords = reduce(hcat, hand_log_coordinates)
fp = fit(PCA, red_coords; mean=0)
```

Now let's show explained variance of each principal component.
```{julia}
plot(principalvars(fp), title="explained variance", label="Tangent PCA")
```

The next plot shows how projections on the first two pricipal components look like.
```{julia}
fig = plot(; title="coordinates per gesture of the first two principal components")
for label_num in [0, 1]
mask = hand_labels .== label_num
cur_hand_logs = red_coords[:, mask]
cur_t = MultivariateStats.transform(fp, cur_hand_logs)
scatter!(fig, cur_t[1, :], cur_t[2, :], label="gesture " * string(label_num))
end
xlabel!(fig, "principal component 1")
ylabel!(fig, "principal component 2")
fig
```

The following heatmap displays pairwise distances between gestures.
We can use them for clustering, classification, etc.
```{julia}
hand_distances = [
distance(Mshape, hands_projected[i], hands_projected[j]) for
i in eachindex(hands_projected), j in eachindex(hands_projected)
]
heatmap(hand_distances, aspect_ratio=:equal)
```
Loading
Loading