Skip to content

Commit 08ec98a

Browse files
authored
Merge pull request #81 from InfoMusCP/dev
Dev
2 parents 5727bf8 + 85b8fc6 commit 08ec98a

211 files changed

Lines changed: 141251 additions & 6978 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/gh-pages.yml

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- main
7+
- dev
78

89
jobs:
910
build-deploy:
@@ -12,6 +13,9 @@ jobs:
1213
# 1. Checkout repo (code + docs)
1314
- name: Checkout repository
1415
uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
token: ${{ secrets.GH_PAGES_TOKEN || github.token }}
1519

1620
# 2. Set up Python
1721
- name: Set up Python
@@ -23,19 +27,19 @@ jobs:
2327
- name: Install dependencies
2428
run: |
2529
python -m pip install --upgrade pip
26-
pip install .[dev] # installs mkdocs and all extras
30+
pip install .[dev] mike
2731
28-
# 4. Build doc
29-
- name: Build MkDocs site
32+
# 4. Deploy MkDocs site with mike
33+
- name: Deploy with mike 🚀
3034
env:
3135
PYTHONPATH: ${{ github.workspace }}/PyEyesWeb
32-
run: mkdocs build --verbose
33-
34-
# 5. Push to gh-pages
35-
- name: Deploy to GitHub Pages 🚀
36-
uses: peaceiris/actions-gh-pages@v3
37-
with:
38-
github_token: ${{ secrets.GH_PAGES_TOKEN }}
39-
publish_dir: ./site
40-
publish_branch: gh-pages
41-
force_orphan: true
36+
run: |
37+
git config user.name "github-actions[bot]"
38+
git config user.email "github-actions[bot]@users.noreply.github.com"
39+
40+
if [ "${{ github.ref_name }}" = "main" ]; then
41+
mike deploy --push --update-aliases main latest
42+
mike set-default --push latest
43+
else
44+
mike deploy --push ${{ github.ref_name }}
45+
fi

.gitignore

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,9 @@ Thumbs.db
2727
*.swp
2828

2929
# Test data or large media files
30-
*.mp4
31-
*.avi
32-
*.mov
33-
*.csv
3430
*.npy
3531
*.h5
32+
*.pytest.py
3633

3734
# Python virtualenv/poetry
3835
poetry.lock
@@ -44,4 +41,10 @@ dist/
4441
*.egg
4542

4643
demos/Backup
47-
demos/Lib
44+
demos/Lib
45+
46+
# Ignore specific files or directories
47+
__*
48+
49+
# Ignore the site directory
50+
site/

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,20 @@ from pyeyesweb.data_models import SlidingWindow
2828
from pyeyesweb.low_level import Smoothness
2929

3030
# Movement smoothness analysis
31+
# 1. Initialize the feature extractor (e.g., 50Hz sampling rate)
3132
smoothness = Smoothness(rate_hz=50.0)
32-
window = SlidingWindow(max_length=100, n_columns=1)
33-
window.append([motion_data])
34-
# here `motion_data` is a float representing a single sample of motion data
35-
# (e.g., the x coordinate of the left hand at time t).
3633

37-
sparc, jerk = smoothness(window)
34+
# 2. Initialize a sliding window for speed data (1 signal, 1 dimension)
35+
window = SlidingWindow(max_length=60, n_signals=1, n_dims=1)
36+
37+
# 3. Process data frame by frame (simulating a real-time loop)
38+
# here `speed_value` is a float representing the instantaneous speed
39+
window.append(speed_value)
40+
41+
# 4. Compute the feature (only after the window is full)
42+
if len(window) >= window.max_length:
43+
result = smoothness(window)
44+
print(f"SPARC: {result.sparc}, Jerk: {result.jerk_rms}")
3845
```
3946
> [!TIP]
4047
> For more advanced and complete use cases see the [Documentation](https://infomuscp.github.io/PyEyesWeb/)

docs/javascripts/version-select.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
document.addEventListener("DOMContentLoaded", function() {
2+
// Determine base URL based on environment (localhost vs GitHub Pages)
3+
var isLocalhost = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1";
4+
var baseUrl = isLocalhost ? "" : "/PyEyesWeb";
5+
6+
// Attempt to fetch the versions.json generated by mike
7+
fetch(baseUrl + "/versions.json").then(response => {
8+
if (!response.ok) return null;
9+
return response.json();
10+
}).then(versions => {
11+
if (!versions || versions.length === 0) return;
12+
13+
// Find the current version from the URL path.
14+
var pathSegments = window.location.pathname.split('/').filter(p => p !== "");
15+
// If localhost: /dev/ -> pathSegments[0] is "dev"
16+
// If GitHub: /PyEyesWeb/dev/ -> pathSegments[1] is "dev"
17+
var currentVersion = isLocalhost ? pathSegments[0] : pathSegments[1];
18+
19+
if (!currentVersion) {
20+
currentVersion = versions[0].version; // fallback if at root
21+
}
22+
23+
var select = document.createElement("select");
24+
select.style.margin = "10px auto";
25+
select.style.display = "block";
26+
select.style.width = "90%";
27+
select.style.padding = "5px";
28+
select.style.color = "#000";
29+
select.style.borderRadius = "3px";
30+
select.style.border = "1px solid #ccc";
31+
32+
versions.forEach(function(version) {
33+
var option = document.createElement("option");
34+
option.value = version.version;
35+
option.text = "Version: " + version.title;
36+
if (version.version === currentVersion || version.aliases.includes(currentVersion)) {
37+
option.selected = true;
38+
}
39+
select.appendChild(option);
40+
});
41+
42+
select.addEventListener("change", function() {
43+
window.location.href = baseUrl + "/" + this.value + "/";
44+
});
45+
46+
// Add the dropdown to the readthedocs sidebar search box or navigation container
47+
var searchBox = document.querySelector(".wy-side-nav-search");
48+
if (searchBox) {
49+
searchBox.appendChild(select);
50+
}
51+
}).catch(e => console.error("Error loading versions.json:", e));
52+
});

docs/scripts/gen_pages.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def format_module_name(name):
2121

2222

2323
# Generate individual module pages and build nav
24-
for path in sorted(SRC_DIR.rglob("*.py")):
24+
for path in sorted(SRC_DIR.rglob("[!.]*.py")): # Exclude files starting with . (e.g., .pytest.py) from nav
2525
module_path = path.relative_to(SRC_DIR).with_suffix("")
2626
doc_path = API_DOCS_PATH / path.relative_to(SRC_DIR).with_suffix(".md")
2727
module_name = ".".join(module_path.parts)
@@ -38,7 +38,9 @@ def format_module_name(name):
3838
doc_path.parent.mkdir(parents=True, exist_ok=True)
3939
with mkdocs_gen_files.open(doc_path, "w") as f:
4040
f.write(f"# {format_module_name(module_path.name)}\n\n")
41-
print(f"::: {PACKAGE_NAME}.{module_name}", file=f)
41+
f.write(f"::: {PACKAGE_NAME}.{module_name}\n")
42+
f.write(f" options:\n")
43+
f.write(f" filters: [\"!^_[^_]\"]\n")
4244

4345
mkdocs_gen_files.set_edit_path(doc_path, path)
4446

docs/user_guide/getting_started.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ from pyeyesweb.low_level import Smoothness
4646
smoothness = Smoothness(rate_hz=50.0)
4747

4848
# 2. Create a sliding window to store the last 100 frames of data
49-
window = SlidingWindow(max_length=100, n_columns=1)
49+
window = SlidingWindow(max_length=100, n_signals=1, n_dims=1)
5050

5151
# 3. Simulate a real-time loop reading from a CSV
5252
with open('velocity_data.csv', 'r') as f:
@@ -57,23 +57,23 @@ with open('velocity_data.csv', 'r') as f:
5757
velocity_val = float(row[0])
5858

5959
# Append the new frame to the sliding window
60-
window.append([velocity_val]) #(1)!
60+
window.append(velocity_val) #(1)!
6161

6262
# Compute smoothness features on the current window
63-
sparc, jerk = smoothness(window) #(2)!
63+
result = smoothness(window) #(2)!
6464

6565
# Check if a valid result was returned
66-
# (feature may return None if window has not enough samples)
67-
if sparc is not None and jerk is not None:
68-
print(f"SPARC: {sparc:.3f} | Jerk: {jerk:.3f}")
66+
# (feature fields may be None if window has not enough samples)
67+
if result.sparc is not None and result.jerk_rms is not None:
68+
print(f"SPARC: {result.sparc:.3f} | Jerk: {result.jerk_rms:.3f}")
6969
```
7070

71-
1. The `SlidingWindow` expects a list of values for every frame (even if there is only 1 sample).
71+
1. `SlidingWindow` automatically handles the data shape. Since we initialized it with `n_signals=1` and `n_dims=1`, we can append a scalar value directly.
7272
As the loop runs, new data is added to the end, and old data is automatically discarded once the max_length is reached.
7373

7474
2. The `smoothness` callable processes the current state of the window.
75-
It returns the SPARC (Spectral Arc Length) and Jerk RMS.
76-
If the window does not yet contain enough data to compute the metric, it may return None.
75+
It returns a result object containing the SPARC (Spectral Arc Length) and Jerk RMS.
76+
If the window does not yet contain enough data to compute the metric, the result fields will be `None`.
7777

7878
## Subpackages
7979

docs/user_guide/theoretical_framework/analysis_primitives/analysis_primitives.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,21 @@ They summarize, transform, or model data at various temporal and spatial scales.
3737

3838
| Primitive Type | Description | Implemented |
3939
|-------------------------------|--------------------------------------------------------------------------------------------------------------|------------------|
40-
| **Statistical Moments** | Unary operators summarizing distributions (mean, variance, skewness, kurtosis). | :material-close: |
40+
| [**Statistical Moments**](statistical_moments.md) | Unary operators summarizing distributions (mean, variance, skewness, kurtosis). | :material-check: |
4141
| **Shape Descriptors** | Peaks, slopes, valleys in time-series; geometric descriptors of movement curves. | :material-close: |
42-
| **Entropy** [^1] | Approximate/sample entropy, recurrence analysis; quantify predictability or irregularity. | :material-close: |
42+
| [**Entropy**](mse_dominance.md) [^1] | Approximate/sample entropy, recurrence analysis; quantify predictability or irregularity. | :material-check: |
4343
| **Time-Frequency Transforms** | Fourier or wavelet transforms to detect rhythm, periodicity, or temporal structures. | :material-close: |
44-
| **Symmetry** [^2] | Unary/binary operators measuring geometric or dynamic balance (e.g., left vs. right entropy or energy). | :material-close: |
45-
| **Synchronization** [^3][^4] | Binary/n-ary operators measuring alignment of signals (cross-correlation, phase-locking, group entrainment). | :material-close: |
46-
| **Causality** [^4] | Directional relationships (e.g., Granger causality, transfer entropy) to detect leader–follower dynamics. | :material-close: |
47-
| **Clusterability** [^5] | Measures the tendency of data points to form clusters by means of the Hopkins statistics. | :material-close: |
44+
| [**Synchronization**](synchronization.md) [^2][^3] | Binary/n-ary operators measuring alignment of signals (cross-correlation, phase-locking, group entrainment). | :material-check: |
45+
| **Causality** [^3] | Directional relationships (e.g., Granger causality, transfer entropy) to detect leader–follower dynamics. | :material-close: |
46+
| [**Clusterability**](clusterability.md) [^4] | Measures the tendency of data points to form clusters by means of the Hopkins statistics. | :material-check: |
4847
| **Predictive Models** | Hidden Markov Models, classifiers, neural networks; used for gesture segmentation or quality inference. | :material-close: |
49-
| **Saliency / Rarity** [^6] | Detecting unusual occurrences in movement with respect to most frequent patterns. | :material-close: |
48+
| [**Rarity**](rarity.md) [^5] | Detecting unusual occurrences in movement with respect to most frequent patterns. | :material-check: |
5049

5150

5251
## References
5352

5453
[^1]: Glowinski, D., Mancini, M., & Camurri, A. (2013, March). Studying the effect of creative joint action on musicians’ behavior. In International Conference on Arts and Technology (pp. 113-119). Berlin, Heidelberg: Springer Berlin Heidelberg.
55-
[^2]: Glowinski, D., Dael, N., Camurri, A., Volpe, G., Mortillaro, M., & Scherer, K. (2011). Toward a minimal representation of affective gestures. IEEE Transactions on Affective Computing, 2(2), 106-118.
56-
[^3]: Varni, G., Volpe, G., & Camurri, A. (2010). A system for real-time multimodal analysis of nonverbal affective social interaction in user-centric media. IEEE Transactions on Multimedia, 12(6), 576-590.
57-
[^4]: Sabharwal, S. R., Varlet, M., Breaden, M., Volpe, G., Camurri, A., & Keller, P. E. (2022). huSync-A model and system for the measure of synchronization in small groups: A case study on musical joint action. IEEE Access, 10, 92357-92372.
58-
[^5]: Corbellini, N., Ceccaldi, E., Varni, G., & Volpe, G. (2022, August). An exploratory study on group potency classification from non-verbal social behaviours. In International Conference on Pattern Recognition (pp. 240-255). Cham: Springer Nature Switzerland.
59-
[^6]: Niewiadomski, R., Mancini, M., Cera, A., Piana, S., Canepa, C., & Camurri, A. (2019). Does embodied training improve the recognition of mid-level expressive movement qualities sonification?. Journal on Multimodal User Interfaces, 13, 191-203.
54+
[^2]: Varni, G., Volpe, G., & Camurri, A. (2010). A system for real-time multimodal analysis of nonverbal affective social interaction in user-centric media. IEEE Transactions on Multimedia, 12(6), 576-590.
55+
[^3]: Sabharwal, S. R., Varlet, M., Breaden, M., Volpe, G., Camurri, A., & Keller, P. E. (2022). huSync-A model and system for the measure of synchronization in small groups: A case study on musical joint action. IEEE Access, 10, 92357-92372.
56+
[^4]: Corbellini, N., Ceccaldi, E., Varni, G., & Volpe, G. (2022, August). An exploratory study on group potency classification from non-verbal social behaviours. In International Conference on Pattern Recognition (pp. 240-255). Cham: Springer Nature Switzerland.
57+
[^5]: Niewiadomski, R., Mancini, M., Cera, A., Piana, S., Canepa, C., & Camurri, A. (2019). Does embodied training improve the recognition of mid-level expressive movement qualities sonification?. Journal on Multimodal User Interfaces, 13, 191-203.

0 commit comments

Comments
 (0)