Triangular heatmap visualization for quantile distributions across a 2D parameter space.
Project description
quantile-cube
A Python package for visualizing the distribution of 3D movement data — velocity, acceleration, and angle — collapsed into a 2D heatmap.
Movement observations are binned into quantiles along three dimensions: velocity (x-axis), acceleration (y-axis), and angle of movement (the four triangles within each cell). Each triangle's color represents the density of observations — the proportion of total time spent in that specific combination of velocity, acceleration, and angle quantile. This makes it possible to see at a glance where movement is concentrated across all three dimensions simultaneously.
Table of Contents
Installation
Install from PyPI (no repo cloning needed):
pip install quantile-cube
Requirements: Python 3.9+, NumPy ≥ 1.21, Matplotlib ≥ 3.5, Pandas ≥ 1.3
If you'd like to explore the source, run examples, or contribute:
git clone https://github.com/kelanethomas/quantile-cube.git
cd quantile-cube
pip install -e .
Quick Start
Option 1 — Raw arrays
from quantile_cube import plot_cube
import numpy as np
q1 = np.random.rand(25)
q2 = np.random.rand(25)
q3 = np.random.rand(25)
q4 = np.random.rand(25)
plot_cube(
values=[q1, q2, q3, q4],
M=5,
N=5,
title="My Quantile Cube",
colorbar_label="Value",
cmap="viridis",
)
Option 2 — DataFrame (recommended)
If your data is in a DataFrame with columns named like Q1_vel_Q1_acc_Q1_angle:
from quantile_cube import plot_cube
plot_cube(
cube_data=df,
M=5,
N=5,
title="Game 5 Quantile Cube",
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
values |
list of 4 arrays | None |
One array per quantile, each of length M×N |
cube_data |
DataFrame | None |
Single-row DataFrame with columns Q{vel}_vel_Q{acc}_acc_Q{angle}_angle |
M |
int | 5 |
Number of columns |
N |
int | 5 |
Number of rows |
minimum |
float | 0 |
Colormap lower bound |
maximum |
float | data max rounded up to nearest 0.01 | Colormap upper bound |
cmap |
str or Colormap | "Reds" |
Matplotlib colormap |
title |
str | "Quantile Cube" |
Plot title and default save filename |
colorbar_label |
str | "" |
Colorbar label |
xlabel |
str | "Velocity" |
X-axis label |
ylabel |
str | "Acceleration" |
Y-axis label |
quantile_labels |
list of 4 str | ["Q1","Q2","Q3","Q4"] |
Triangle labels |
show_quantile_labels |
bool | False |
Show label-only summary view |
show_values |
bool | False |
Print numeric value at center of each triangle |
value_fmt |
str | ".4f" |
Format string for numeric labels when show_values=True |
grey_nonsignificant |
bool | False |
Render NaN values in grey |
save |
bool | False |
Save figure to file |
save_path |
str | "<title>.png" |
Custom save path |
show |
bool | True |
Call plt.show() |
figsize |
tuple | (7, 7) |
Figure size in inches |
Advanced Usage
Custom axis labels
plot_cube(
values=[q1, q2, q3, q4],
xlabel="Speed Bins",
ylabel="Acceleration Bins",
)
Custom quantile labels
plot_cube(
values=[q1, q2, q3, q4],
quantile_labels=["Low", "Mid-Low", "Mid-High", "High"],
show_quantile_labels=True,
)
Handling non-significant values
import numpy as np
q1_with_nans = np.where(pvalues > 0.05, np.nan, q1)
plot_cube(
values=[q1_with_nans, q2, q3, q4],
grey_nonsignificant=True,
)
Saving figures
plot_cube(
values=[q1, q2, q3, q4],
title="my_plot",
save=True,
save_path="outputs/my_plot.png",
show=False,
)
How It Works
Each cell in the grid corresponds to a (velocity, acceleration) quantile bin. Within each cell, four triangles represent four angle quantiles — encoding directional movement. Color intensity reflects the proportion of total observations falling in that bin, making relative density immediately readable across all three movement dimensions at once.
Tip: Values across all triangles sum to 1.0, so the colormap reflects relative time spent rather than absolute counts.
Contributing
Contributions, bug reports, and feature requests are welcome!
- Fork the repo: github.com/kelanethomas/quantile-cube
- Create a branch:
git checkout -b feature/your-feature - Commit your changes and open a pull request
Please open an issue first if you're planning a larger change.
Citation
This package accompanies the following paper:
Thomas, K. & Hannig, J. (2025). Movement Dynamics in Elite Female Soccer Athletes: The Quantile Cube Approach. arXiv preprint arXiv:2503.11815. https://arxiv.org/abs/2503.11815
Accepted at the Journal of Quantitative Analysis in Sports — full publication coming soon.
@misc{thomas2025quantilecube_paper,
author = {Thomas, Kendall and Hannig, Jan},
title = {Movement Dynamics in Elite Female Soccer Athletes: The Quantile Cube Approach},
year = {2025},
eprint = {2503.11815},
archivePrefix = {arXiv},
url = {https://arxiv.org/abs/2503.11815},
}
To also cite the software package:
@software{thomas2026quantilecube_pkg,
author = {Thomas, Kendall},
title = {quantile-cube: 3D Movement Distribution Visualization},
year = {2026},
url = {https://github.com/kelanethomas/quantile-cube},
version = {0.1.0},
}
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quantile_cube-0.1.2.tar.gz.
File metadata
- Download URL: quantile_cube-0.1.2.tar.gz
- Upload date:
- Size: 46.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55e1ec688c61ce55a3fcfa5089ef1cde955b9a95601d3c083c0da4c2e88346aa
|
|
| MD5 |
b64c552dc8bf907bd7ee57688d6abcc4
|
|
| BLAKE2b-256 |
3c9c661695c05bb7f3e9c4586e2a783a0d905f3821874f65b4da8ae0a171580a
|
File details
Details for the file quantile_cube-0.1.2-py3-none-any.whl.
File metadata
- Download URL: quantile_cube-0.1.2-py3-none-any.whl
- Upload date:
- Size: 9.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b578f3e35cfafa1271725df48dbfd8a4203653483ddce4f968f5b4ee0ad32b05
|
|
| MD5 |
6440c1220c8c6eed8807ace771004989
|
|
| BLAKE2b-256 |
308ee1c7ed0ff4584d216361dbec86b64cbebd37d67b7b015b7e58589942a463
|