Video Analysis XML Export#

databallpy can export event data to XML files compatible with video analysis tools such as SportsCode and Longomatch. This lets you automatically tag match footage from your existing data, turning every pass, shot, or custom event into a labelled video clip — without manual tagging.

There are two workflows:

  1. Export from EventData — filter and export events that already live in your game.event_data DataFrame.

  2. Custom events — define your own events (e.g. from your own detection logic) and export them via events_to_xml().

Both produce the same XML format; the right choice depends on whether you want to use events that databallpy has already parsed or events you have computed yourself.

import os
from databallpy import get_saved_game

game = get_saved_game("not_synced_game", os.path.join(os.getcwd(), "../saved_games"))

Workflow 1: Export from EventData#

game.event_data is a specialised DataFrame that exposes a to_video_analysis_xml() method. Calling it with no arguments exports every event in the dataset:

xml_str = game.event_data.to_video_analysis_xml()
print(xml_str[:800])
<?xml version="1.0" encoding="utf-8"?>
<file>
	<SORT_INFO>
		<sort_type>sort order</sort_type>
	</SORT_INFO>
	<ALL_INSTANCES>
		<instance>
			<ID>p1</ID>
			<start>0.00</start>
			<end>3.00</end>
			<code>1H</code>
			<label>
				<group>Period</group>
				<text>1</text>
			</label>
		</instance>
		<instance>
			<ID>0</ID>
			<start>-4320.75</start>
			<end>-4314.75</end>
			<code>team set up</code>
			<label>
				<group>Team</group>
				<text>T-3f505904</text>
			</label>
			<label>
				<group>Original Event</group>
				<text>team set up</text>
			</label>
		</instance>
		<instance>
			<ID>1</ID>
			<start>-4167.35</start>
			<end>-4161.35</end>
			<code>team set up</code>
			<label>
				<group>Team</group>
				<text>T-4266dd74</text>
			</label>
			<label>
				<group>Original Event</group
print(f"Generated XML with {xml_str.count('<instance>')} instance(s)")
Generated XML with 155 instance(s)

The XML contains one <instance> per event plus a period-start marker per half. Each instance carries a <code> (the event type used for colour grouping in the video tool) and one <label> per piece of metadata — player name, team, outcome, etc.

Filtering and clip windows#

In practice you usually want a subset. The method accepts several keyword-only filters:

xml_shots = game.event_data.to_video_analysis_xml(
    databallpy_events=["shot"],   # only shots
    before_seconds=5.0,           # clip starts 5 s before the event
    after_seconds=3.0,            # clip ends 3 s after
    tag_period_starts=False,      # omit period markers
)
print(f"Generated XML with {xml_shots.count('<instance>')} shot instance(s)")
Generated XML with 2 shot instance(s)

You can layer multiple filters at once:

home_passes_xml = game.event_data.to_video_analysis_xml(
    team_id=game.home_team_id,    # home team only
    databallpy_events=["pass"],   # passes only
    is_successful=True,           # successful passes only
    before_seconds=3.0,
    after_seconds=5.0,
)
print(f"Generated XML with {home_passes_xml.count('<instance>')} instance(s)")
Generated XML with 49 instance(s)

Writing to a file#

Pass a file path to output instead of "string" to write directly to disk:

path = game.event_data.to_video_analysis_xml(
    databallpy_events=["shot"],
    output="shots.xml",
)

Workflow 2: Custom Events#

When the events you want to tag do not come directly from the parsed event data — for example, pressing sequences detected from tracking data, or events from your own model — use events_to_xml() with manually constructed Event dicts.

Two TypedDicts define the structure:

Type

Fields

LabelDict

group (str), name (str)

Event

id (str), code (str), start_t (float), end_t (float), labels (list[LabelDict])

Times are in seconds relative to the start of the relevant half — the same convention used by SportsCode and Longomatch.

from databallpy import events_to_xml, Event, LabelDict

# Imagine these pressing events were detected from tracking data
pressing_events: dict[str, Event] = {
    "0": Event(
        id="0",
        code="Press",
        start_t=312.0,   # seconds from half-start
        end_t=320.0,
        labels=[
            LabelDict(group="Team", name="Home"),
            LabelDict(group="Outcome", name="Ball won"),
        ],
    ),
    "1": Event(
        id="1",
        code="Press",
        start_t=874.5,
        end_t=882.0,
        labels=[
            LabelDict(group="Team", name="Away"),
            LabelDict(group="Outcome", name="Unsuccessful"),
        ],
    ),
}

xml_str = events_to_xml(pressing_events)
print(xml_str)
<?xml version="1.0" encoding="utf-8"?>
<file>
	<SORT_INFO>
		<sort_type>sort order</sort_type>
	</SORT_INFO>
	<ALL_INSTANCES>
		<instance>
			<ID>0</ID>
			<start>312.00</start>
			<end>320.00</end>
			<code>Press</code>
			<label>
				<group>Team</group>
				<text>Home</text>
			</label>
			<label>
				<group>Outcome</group>
				<text>Ball won</text>
			</label>
		</instance>
		<instance>
			<ID>1</ID>
			<start>874.50</start>
			<end>882.00</end>
			<code>Press</code>
			<label>
				<group>Team</group>
				<text>Away</text>
			</label>
			<label>
				<group>Outcome</group>
				<text>Unsuccessful</text>
			</label>
		</instance>
	</ALL_INSTANCES>
	<ROWS>
		<row>
			<code>Press</code>
			<R>96077</R>
			<G>70587</G>
			<B>61568</B>
			<sort_order>0</sort_order>
		</row>
	</ROWS>
</file>

Tip

You can mix both workflows: use to_video_analysis_xml() for the bulk of your events and add hand-crafted entries on top by combining the resulting dicts before calling events_to_xml().

Summary#

Task

Method

Export parsed events from a game

game.event_data.to_video_analysis_xml(...)

Filter by team, player, minute, event type, outcome

keyword arguments on to_video_analysis_xml()

Write directly to a file

output="path/to/file.xml"

Export fully custom events

events_to_xml(my_events_dict)

For the full parameter reference see the Event Data API documentation page.