Extract data from DataVolley .dvw files and VolleyStation .vsm files
Project description
py-datavolley
TLDR;
uv add openvolley-pydatavolley
# data = dv.read_dv(path_of_dvw_file)
data = dv.read_dv(dv.example_file())
print(data)
Will return (this is a sample and not the entire example file)
[
{
"match_id": "106859",
"video_time": 495,
"code": "a02RM-~~~58AM~~00B",
"team": "University of Dayton",
"player_number": 2,
"player_name": "Maura Collins",
"player_id": "-230138",
"skill": "Reception",
"skill_type": "Jump-float serve reception",
"skill_subtype": "Jump Float",
"evaluation_code": "-",
"setter_position": "6",
"attack_code": null,
"set_code": null,
"set_type": null,
"start_zone": "5",
"end_zone": "8",
"end_subzone": "A",
"num_players_numeric": null,
"home_team_score": "0",
"visiting_team_score": "0",
"home_setter_position": "1",
"visiting_setter_position": "6",
"custom_code": "00B",
"home_p1": "19",
"home_p2": "9",
"home_p3": "11",
"home_p4": "15",
"home_p5": "10",
"home_p6": "7",
"visiting_p1": "1",
"visiting_p2": "16",
"visiting_p3": "17",
"visiting_p4": "10",
"visiting_p5": "6",
"visiting_p6": "8",
"start_coordinate": "0431",
"mid_coordinate": "-1-1",
"end_coordinate": "7642",
"point_phase": "Reception",
"attack_phase": null,
"start_coordinate_x": 1.26875,
"start_coordinate_y": 0.092596,
"mid_coordinate_x": null,
"mid_coordinate_y": null,
"end_coordinate_x": 1.68125,
"end_coordinate_y": 5.425924,
"set_number": "1",
"home_team": "University of Louisville",
"visiting_team": "University of Dayton",
"home_team_id": 17,
"visiting_team_id": 42,
"point_won_by": "University of Louisville",
"serving_team": "University of Louisville",
"receiving_team": "University of Dayton",
"rally_number": 1,
"possession_number": 1
}
]
py-datavolley package
A Python package for parsing and analyzing volleyball scouting data from DataVolley files (*.dvw).
Rebuilt pydatavolley with modern Python tooling (Astral ecosystem) for improved experience: UV for package management, Ruff for linting/formatting and Ty for type checking.
Quick Reference
# Start a new project
uv init my-analysis && cd my-analysis
uv add openvolley-pydatavolley[plot]
# Load and analyze data
uv run python -c "
import datavolley as dv
data = dv.read_dv('match.dvw')
print(f'Loaded {len(data)} plays')
"
Table of Contents
Prerequisites
This package works best with uv - a fast Python package manager.
Install uv
# macOS and Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
See uv documentation for more details.
Usage
Quick Start
If you have uv installed (recommended):
# Create a new project
uv init my-volleyball-analysis
cd my-volleyball-analysis
# Add the package
uv add openvolley-pydatavolley
# Plotting: Add plotting dependencies
uv add openvolley-pydatavolley[plot]
Create main.py:
import datavolley as dv
# Load a match
data = dv.read_dv('path/to/match.dvw')
# data = dv.read_dv(dv.example_file())
# Access play data
for play in data[:5]:
print(f"{play['skill']}: {play['player_name']} - {play['evaluation_code']}")
# Filter by skill
serves = [p for p in data if p.get('skill') == 'Serve']
attacks = [p for p in data if p.get('skill') == 'Attack']
print(f"Total serves: {len(serves)}")
print(f"Total attacks: {len(attacks)}")
Run your analysis:
uv run main.py
With Pandas or Polars
Convert to DataFrame for easier analysis:
import datavolley as dv
import pandas as pd
data = dv.read_dv('match.dvw')
df = pd.DataFrame(data)
# Analyze attacks
attacks = df[df['skill'] == 'Attack']
print(attacks.groupby('player_name')['evaluation_code'].value_counts())
Or with Polars:
import datavolley as dv
import polars as pl
data = dv.read_dv('match.dvw')
df = pl.DataFrame(data)
# Fast filtering and aggregation
attacks = df.filter(pl.col('skill') == 'Attack')
print(attacks.group_by('player_name').agg(pl.len()))
Without uv
If you prefer pip:
pip install openvolley-pydatavolley
pip install openvolley-pydatavolley[plot] # With plotting
Development
Want to contribute or modify the package? Here's how to set up a development environment:
-
Clone the repository:
git clone https://github.com/openvolley/py-datavolley.git cd py-datavolley
-
Install dependencies:
# UV automatically creates and manages virtual environments uv sync
-
Run the example:
uv run main.py
-
Run linting and formatting:
ruff check datavolley/ ruff format datavolley/ ty check datavolley/
Example Output
Running uv run main.py with the included example file will output:
Sample Play Data
[
{
"match_id": "106859",
"video_time": 495,
"code": "a02RM-~~~58AM~~00B",
"team": "University of Dayton",
"player_number": 2,
"player_name": "Maura Collins",
"player_id": "-230138",
"skill": "Reception",
"skill_type": "Jump-float serve reception",
"skill_subtype": "Jump Float",
"evaluation_code": "-",
"setter_position": "6",
"attack_code": null,
"set_code": null,
"set_type": null,
"start_zone": "5",
"end_zone": "8",
"end_subzone": "A",
"num_players_numeric": null,
"home_team_score": "0",
"visiting_team_score": "0",
"home_setter_position": "1",
"visiting_setter_position": "6",
"custom_code": "00B",
"home_p1": "19",
"home_p2": "9",
"home_p3": "11",
"home_p4": "15",
"home_p5": "10",
"home_p6": "7",
"visiting_p1": "1",
"visiting_p2": "16",
"visiting_p3": "17",
"visiting_p4": "10",
"visiting_p5": "6",
"visiting_p6": "8",
"start_coordinate": "0431",
"mid_coordinate": "-1-1",
"end_coordinate": "7642",
"point_phase": "Reception",
"attack_phase": null,
"start_coordinate_x": 1.26875,
"start_coordinate_y": 0.092596,
"mid_coordinate_x": null,
"mid_coordinate_y": null,
"end_coordinate_x": 1.68125,
"end_coordinate_y": 5.425924,
"set_number": "1",
"home_team": "University of Louisville",
"visiting_team": "University of Dayton",
"home_team_id": 17,
"visiting_team_id": 42,
"point_won_by": "University of Louisville",
"serving_team": "University of Louisville",
"receiving_team": "University of Dayton",
"rally_number": 1,
"possession_number": 1
}
]
Plotting
The package includes plotting capabilities for visualizing volleyball match data on court diagrams.
Installation
Install with plotting dependencies:
uv add openvolley-pydatavolley[plot]
Or install dependencies separately:
uv add matplotlib numpy shapely
Examples
Draw a Court
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import datavolley as dv
# Draw a basic court
ax = dv.dv_court(zones=True, zone_labels=True)
plt.savefig('court.png')
Create Attack Heatmaps
import datavolley as dv
# Load match data
data = dv.read_dv('match.dvw')
# Get attack landing coordinates
attacks = [p for p in data if p.get('skill') == 'Attack']
coords = [(p['end_coordinate_x'], p['end_coordinate_y'])
for p in attacks if p.get('end_coordinate_x')]
# Create heatmap
ax = dv.dv_heatmap(coords, zones=True)
plt.title(f'Attack Landing Zones (n={len(coords)})')
plt.savefig('attack_heatmap.png')
Plot Attack Trajectories
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import datavolley as dv
data = dv.read_dv(dv.example_file())
# Filter X5 attacks
attacks = [p for p in data
if p.get('skill') == 'Attack' and p.get('attack_code') == 'X5']
# Plot trajectories
fig, ax = plt.subplots(figsize=(6, 10))
dv.dv_court(zones=True, ax=ax)
for attack in attacks:
if all([attack.get('start_coordinate_x'), attack.get('end_coordinate_x')]):
# Plot start (red) and end (blue) points
ax.scatter(attack['start_coordinate_x'], attack['start_coordinate_y'],
color='red', s=50, alpha=0.6)
ax.scatter(attack['end_coordinate_x'], attack['end_coordinate_y'],
color='blue', s=50, alpha=0.6)
# Draw trajectory line
ax.plot([attack['start_coordinate_x'], attack['end_coordinate_x']],
[attack['start_coordinate_y'], attack['end_coordinate_y']],
color='gray', linestyle='--', linewidth=1, alpha=0.5)
ax.set_title('X5 Attack Trajectories')
plt.savefig('x5_attacks.png', dpi=150)
Example Outputs
| X5 Attack Trajectories Shows ball path from set to landing |
Attack Code Comparison Compare patterns across attack types |
More examples available in the examples/ directory:
attack_analysis_complete.py- Complete attack trajectory analysisattack_comparison.py- Compare multiple attack codes side-by-side zonesattack_heatmap.py- Heatmaps for attack set locations and landingteam_attacks.py- Compare attack patterns between teams
See examples/README.md for detailed documentation.
Contributing
Please create an issue, fork and create a pull request.
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 openvolley_pydatavolley-0.2.1.tar.gz.
File metadata
- Download URL: openvolley_pydatavolley-0.2.1.tar.gz
- Upload date:
- Size: 459.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ecfbf9eba340a9fd32611e87aa7c644611c59d14dba531086388509b3671af4
|
|
| MD5 |
31aa9639d3394ff733f32aa6a5af9d3c
|
|
| BLAKE2b-256 |
379a3fc13012e422f941af8a4fc4bc3c01a2596a728e0b79c927cca039b650ef
|
File details
Details for the file openvolley_pydatavolley-0.2.1-py3-none-any.whl.
File metadata
- Download URL: openvolley_pydatavolley-0.2.1-py3-none-any.whl
- Upload date:
- Size: 54.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cdb7001d7bd8b1f2bb8a0e7a97b51e6a1130d2a4e2125310c9eccf3dcc11c17
|
|
| MD5 |
ee842636717577aa3fca869ae4da4094
|
|
| BLAKE2b-256 |
f7d78ff84336aa786240e7ece4af579f2d1cfdeaa60477531e9b646a0ad93d9c
|