Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Authored by Souvik Mandal, Ph.D.

Project Leader & Instructor, Computational Behavioral Sciences, LS100, FAS, Harvard University | Linkedin ID: souvik-mandal-phd


Last updated: 2026-07-02

Open in Colab Open in GitHub Codespaces

Goal

Compute biomechanical joint angles from pose landmark data deried from MediaPipe.

This notebook takes 2D pose landmarks produced by previous notebooks and computes biomechanical joint angles per frame. It also provides plotting utilities to visualize angle trajectories over time.

You will define which angles to compute (e.g., left elbow, right knee) by specifying three landmarks (A, B, C) that form the angle at B (∠ABC).

Imports and Environment Check (Code)

Python: 3.12.12 (main, Oct  9 2025, 11:07:00) [Clang 16.0.0 (clang-1600.0.26.6)]
Pandas: 2.3.3
NumPy : 1.26.4
Plotly: 6.3.1
Seaborn available: True

Load 2D Pose CSV

Loaded: /Users/souvikmandal/Documents/06_Teaching_Mentoring/LS100_comp_etho/2025/LS100_Python_Notebooks/outputs/Kevin_2022_Day5_CRNCH_pose2d.csv shape: (63558, 9)
Columns: ['video', 'frame', 'time_ms', 'landmark_index', 'landmark_name', 'x', 'y', 'z', 'visibility']
Landmark names: ['nose' 'left_eye_inner' 'left_eye' 'left_eye_outer' 'right_eye_inner'
 'right_eye' 'right_eye_outer' 'left_ear' 'right_ear' 'mouth_left'
 'mouth_right' 'left_shoulder' 'right_shoulder' 'left_elbow' 'right_elbow'
 'left_wrist' 'right_wrist' 'left_pinky' 'right_pinky' 'left_index'
 'right_index' 'left_thumb' 'right_thumb' 'left_hip' 'right_hip'
 'left_knee' 'right_knee' 'left_ankle' 'right_ankle' 'left_heel'
 'right_heel' 'left_foot_index' 'right_foot_index']
Loading...

Define Custom Angles

Provide a list of angle definitions. Each item defines the angle at B formed by points A–B–C.

Example:

angle_defs = [
    {"name": "left_elbow",  "A": "left_shoulder", "B": "left_elbow", "C": "left_wrist"},
    {"name": "right_knee",  "A": "right_hip",     "B": "right_knee", "C": "right_ankle"},
]
[{'name': 'left_elbow', 'A': 'left_shoulder', 'B': 'left_elbow', 'C': 'left_wrist'}, {'name': 'right_elbow', 'A': 'right_shoulder', 'B': 'right_elbow', 'C': 'right_wrist'}, {'name': 'left_knee', 'A': 'left_hip', 'B': 'left_knee', 'C': 'left_ankle'}, {'name': 'right_knee', 'A': 'right_hip', 'B': 'right_knee', 'C': 'right_ankle'}]

Computation Angles

Angle Computation Function

  • The following function calculates the angles you defined.

  • Please change the visibility_thresh according to your desire. This will determine the ‘confidence’ in each angle in each frame.

“good” → all three landmarks ≥ threshold
“low” → exactly one landmark < threshold
“least” → two or three landmarks < threshold

6.b Core logic to compute ∠ABC

Angles shape: (1926, 11)
Loading...

Save and Inspect Output

Saved angles to: /Users/souvikmandal/Documents/06_Teaching_Mentoring/LS100_comp_etho/2025/LS100_Python_Notebooks/outputs/Kevin_2022_Day5_CRNCH_pose2d_angles.csv
Loading...

Plotting the computed angles over time (matplotlib AND seaborn)

8) Plot Angles with Confidence Highlights

In this section, we visualize the computed joint angles for each frame.
You can choose between Matplotlib, Seaborn, or Plotly for plotting:

  • Matplotlib → simple, fast static plots.

  • Seaborn → adds smoothing and styling for a cleaner look.

  • Plotly → fully interactive charts with zoom, hover, and export options.

Each plot corresponds to one computed angle (e.g., angle_left_knee, angle_right_elbow, etc.).
Colored transparent vertical patches mark frames with lower landmark visibility confidence:

  • 🟡 Yellow → “low” confidence (one landmark below threshold)

  • 🟠 Orange → “least” confidence (two or three landmarks below threshold)

Loading...
Loading...
Loading...
Loading...

Batch Angle Computation for a Folder of *_pose2d.csv Files

This section processes all 2D landmark CSVs in a directory and computes the defined joint angles for each file.

How it works

  • You provide a directory path that contains files named like: *_pose2d.csv.

  • For each file, we compute angles using your angle_defs and visibility_thresh.

  • We save a per-file output next to the input as: *_pose2d_angles.csv.

  • We also write a batch manifest CSV in the same directory summarizing the results and any errors.

Tip: you can point this to a directory of filtered outputs as well (e.g., *_pose2d_filtered.csv) by adjusting the pattern.

Found 2 file(s) in /Users/souvikmandal/Documents/06_Teaching_Mentoring/LS100_comp_etho/2025/LS100_Python_Notebooks/outputs matching '*_pose2d.csv'.
[1/2] Kevin_2022_Day5_CRNCH_pose2d.csv
   → Saved: Kevin_2022_Day5_CRNCH_pose2d_angles.csv  (1926 rows, 0.14s)
[2/2] sprintblockstart_221008_clip017_isaiah_pose2d.csv
   → Saved: sprintblockstart_221008_clip017_isaiah_pose2d_angles.csv  (336 rows, 0.02s)

✔ Batch complete. Manifest saved to: /Users/souvikmandal/Documents/06_Teaching_Mentoring/LS100_comp_etho/2025/LS100_Python_Notebooks/outputs/batch_angles_manifest.csv
Total elapsed: 0.2s

Conclusion

Congratulations! You’ve now completed a full pose analysis workflow in Python:

  1. Extracted 2D body landmark data from videos using MediaPipe (Notebook 1).

  2. Computed joint angles and derived confidence metrics based on landmark visibility.

  3. Visualized these angles interactively and in batches across multiple recordings.

What You’ve Learned

  • How pose landmarks are represented as normalized 2D coordinates.

  • How to calculate geometric angles (∠ABC) for any combination of body joints.

  • How to assess data reliability using a visibility-based confidence system (good, low, least).

  • How to produce meaningful visualizations and batch-process datasets efficiently.

Next Steps

In the next notebook, we will:

  • Derive custom biomechanical indices (e.g., symmetry or smoothness metrics).

  • Explore statistical summaries and comparisons across individuals or sessions.

Remember: Confidence flags and visualization overlays are not just for aesthetics—
they teach you to interpret pose-estimation data critically, separating signal from noise.