Examples on interacting with Tracks with GraphQL¶
A track is a series of events that share a unique track identifier. An event may be equivalent to a machine learning detection; it general refers to a visual event that either a machine or a human identifies.
import requests
# This is the endpoint for the GraphQL API. On a production installation it might be http://<yourservername>/api .
API_URL = "http://localhost:4000/graphql"
# Put your auth token from login here
AUTH_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTY1NTkyMjI5NCwiZXhwIjoxNjU2NTI3MDk0fQ.6aEzi28x5s2jt7bvK2lURJD6Q-afKrf4DpYxofgJHjM"
Get a media id¶
All tracks are associated with a media, e.g. video file. Assuming you are starting with a media name in mind, you want to get the media identifier first. That is the database id for that media.
Fetching a media identifier can be done a couple of ways; the simplest way is by the video name.
Keep in mind that any video may return more than one id if it is associated with more than one job. Medias are uniquely referenced to their jobs, but they may be duplicated.
def get_media_id_by_name(video_name: str):
query = """ query
getMediaId($video_name: String!) {
media(where: { name: { equals: $video_name } } ) {
id
job_id
}
}
"""
variables = {"video_name": video_name}
reply = (requests.post(API_URL, json={'query': query, 'variables': variables}).json())
print(reply['data'])
return reply
video_name = "V4361_20211006T162056Z_h265.mp4"
data = get_media_id_by_name(video_name)
medias = data['data']['media']
media_id = medias[0]['id']
job_id = medias[0]['job_id']
print(f"Found {len(medias)} media object for video {video_name}. First media id {media_id} processed in job {job_id}")
{'media': [{'id': 21, 'job_id': 22}]} Found 1 media object for video V4361_20211006T162056Z_h265.mp4. First media id 21 processed in job 22
Get a media id using your M3 Media Asset Manager reference id¶
A media can also be fetched in the M3 Media Asset Manager using any given video reference name, e.g.
http://m3.shore.mbari.org/vam/v1/media/videoreference/filename/V4361_20211006T162056Z_h265.mp4
Media may be aligned with the video_reference_uuid key, e.g. aaa97fc1-f604-40c7-a52a-6faec11cbece if you have a M3 stack installed.
[
{
"video_sequence_uuid": "719c0f70-552e-4abd-8376-da58e2becc98",
"video_reference_uuid": "aaa97fc1-f604-40c7-a52a-6faec11cbece",
"video_uuid": "e2e7fa10-7fe4-4890-8a9b-8418837d04bd",
"video_sequence_name": "Ventana 4361",
"camera_id": "Ventana",
"video_name": "Ventana 4361 20211006T162056Z",
"uri": "http://m3.shore.mbari.org/videos/M3/mezzanine/Ventana/2021/10/4361/V4361_20211006T162056Z_h265.mp4",
"start_timestamp": "2021-10-06T16:20:56Z",
"duration_millis": 360026,
"container": "video/mp4",
"video_codec": "hevc",
"width": 1920,
"height": 1080,
"frame_rate": 59.94005994005994,
"size_bytes": 463214816,
"sha512": "35EB85BB1ADC7603BC6208324EABDE58247330ABB75463A8FB3CBEDCB1F7A8F132CF96093ED5D4E52583F69AB960EEA692BB04FA431849D25AEA09939F91D3AB"
}
]
def get_media_id_by_m3_uuid(video_reference_uuid: str):
query = """ query
getMediaId($video_reference_uuid: String!) {
media(where: { uuid: { equals: $video_reference_uuid } } ) {
id
}
}
"""
variables = {"video_reference_uuid": video_reference_uuid}
reply = (requests.post(API_URL, json={'query': query, 'variables': variables}).json())
print(reply['data'])
return reply
video_reference_uuid = "aaa97fc1-f604-40c7-a52a-6faec11cbece"
data = get_media_id_by_m3_uuid(video_reference_uuid)
medias = data['data']['media']
media_id = medias[0]['id']
print(f"Found {len(medias)} media object for video reference uuid {video_reference_uuid}. First media id {media_id}")
{'media': [{'id': 21}]} Found 1 media object for video reference uuid aaa97fc1-f604-40c7-a52a-6faec11cbece. First media id 21
Get tracks by the media id¶
Now that you have the id, fetch all the tracks uuids and their max_concept. The max_concept is the single most common concept over the track.
def get_tracks_by_id(media_id: int):
query = """ query
getTracksByMediaId($id: Int!) {
tracksByMediaId(media_id: $id) {
max_concept
track_uuid
}
}
"""
variables = {"id": media_id}
reply = (requests.post(API_URL, json={'query': query, 'variables': variables}).json())
print(reply['data'])
get_tracks_by_id(media_id)
{'tracksByMediaId': [{'max_concept': 'Akoya platinum', 'track_uuid': '2f4c19e5-36e3-403b-924f-b00f674e4901'}, {'max_concept': 'Asbestopluma monticola', 'track_uuid': '3eb2c329-1f85-4816-85c7-fa399ff22510'}, {'max_concept': 'Asbestopluma monticola', 'track_uuid': '523ac084-c02a-41e6-b573-6ea97acebb6e'}, {'max_concept': 'Asbestopluma monticola', 'track_uuid': '7f7821ae-c186-4f72-afcc-c4ca794d5839'}, {'max_concept': 'Asbestopluma monticola', 'track_uuid': 'b7ab5bca-02aa-474d-8870-b54417219fc8'}, {'max_concept': 'Asbestopluma monticola', 'track_uuid': 'ca8c55a9-b218-434d-a21b-d19b4c253be0'}, {'max_concept': 'Asteroidea', 'track_uuid': '23e13376-b709-45be-982c-4285b1e5f339'}, {'max_concept': 'Bathyraja trachura', 'track_uuid': '3ace5e31-0e9f-45c2-bdbf-92ac583c9087'}, {'max_concept': 'Chionoecetes tanneri', 'track_uuid': '5dfbc57b-2ede-4131-a389-36d27b4302ec'}, {'max_concept': 'Chionoecetes tanneri', 'track_uuid': 'e45129c7-9fd6-4c59-921f-ab4cee3198f0'}, {'max_concept': 'detritus', 'track_uuid': '305fb9f1-2ec8-4a88-a40e-580fe6d015b9'}, {'max_concept': 'detritus', 'track_uuid': 'd51ab08a-1d4f-4f98-8a20-cd5372364cb0'}, {'max_concept': 'Embassichthys bathybius', 'track_uuid': '09b03505-a50c-46c6-9c0c-202d143c4953'}, {'max_concept': 'Embassichthys bathybius', 'track_uuid': '1af6ce05-d0e3-494a-a7b4-3288e5cd4e4f'}, {'max_concept': 'Embassichthys bathybius', 'track_uuid': '1d3d731e-4fa6-430b-aba0-90ab2490657f'}, {'max_concept': 'Embassichthys bathybius', 'track_uuid': '95774db6-cb1b-4c47-b2a5-459f6d0d8113'}, {'max_concept': 'Embassichthys bathybius', 'track_uuid': 'b59640d3-2e20-40d1-babf-782ace06c6f6'}, {'max_concept': 'equipment', 'track_uuid': '28805d68-5648-42ec-8e85-895a4fdf4fa1'}, {'max_concept': 'equipment', 'track_uuid': '5637e81d-ea64-48e3-bdfc-54bf3b3a5fcb'}, {'max_concept': 'equipment', 'track_uuid': '9439baa5-139b-40da-a61c-5969936bef06'}, {'max_concept': 'equipment', 'track_uuid': '99d321f8-9f5e-48b9-a2da-eeaab2a35eea'}, {'max_concept': 'equipment', 'track_uuid': 'c78a5949-ab16-4e0b-8c41-fd80a1cf77fa'}, {'max_concept': 'equipment', 'track_uuid': 'd312b4c2-6f89-461a-9197-fd18dceba84a'}, {'max_concept': 'equipment', 'track_uuid': 'dae12daf-8c98-4c2f-9308-e554d18a615a'}, {'max_concept': 'equipment', 'track_uuid': 'de34792b-5b81-4cb4-a6a4-cd6d9c968858'}, {'max_concept': 'Gersemia juliepackardae', 'track_uuid': '191d0eac-979c-47c7-821c-31e4d817c90f'}, {'max_concept': 'Hippasteria', 'track_uuid': '00bb3f2e-0dba-45aa-b427-3344266948ff'}, {'max_concept': 'Hippasteria', 'track_uuid': '2b7c4d9b-ab70-4a5e-9df2-631737261fb5'}, {'max_concept': 'Merluccius productus', 'track_uuid': '8d085c60-e40b-4014-a303-afe6f6f68290'}, {'max_concept': 'Merluccius productus', 'track_uuid': 'a6da679b-e3a1-438b-b9bd-03fd4dab2ef2'}, {'max_concept': 'Octocorallia', 'track_uuid': '30be4071-a1e7-4728-9390-24f0759b1844'}, {'max_concept': 'Octocorallia', 'track_uuid': '3114635f-bc60-4782-a4c1-49a400995b5d'}, {'max_concept': 'Octocorallia', 'track_uuid': '34bb2f2c-eed4-47a6-b3b0-9dab97053151'}, {'max_concept': 'Octocorallia', 'track_uuid': '35a7f9c1-d702-440f-af0c-ca489ec34cce'}, {'max_concept': 'Octocorallia', 'track_uuid': '38ede27e-d6a3-47b4-8e0f-18af8bf5ea61'}, {'max_concept': 'Octocorallia', 'track_uuid': '5ca36c70-f984-4fce-af91-8e64845ea271'}, {'max_concept': 'Octocorallia', 'track_uuid': '91167a44-1346-4201-afb1-6fd903387908'}, {'max_concept': 'Octocorallia', 'track_uuid': '917d90a2-ee55-42a9-b864-207983f6e4e7'}, {'max_concept': 'Octocorallia', 'track_uuid': '9b93fe68-4046-45cf-8596-34d17d4e08fb'}, {'max_concept': 'Octocorallia', 'track_uuid': 'fdfaf857-e451-4e76-a744-5b39b8cdd87b'}, {'max_concept': 'Paragorgia', 'track_uuid': '0989d7fd-68e4-4f4e-a965-d13c69b2d758'}, {'max_concept': 'Paragorgia', 'track_uuid': '16299d5a-2309-49f9-a036-e9046f8bd4da'}, {'max_concept': 'Paragorgia', 'track_uuid': '17e10f0f-f3af-45d9-8345-55df167b05fb'}, {'max_concept': 'Paragorgia', 'track_uuid': '1c2b28bb-09d1-489a-a10e-133af8a1fe95'}, {'max_concept': 'Paragorgia', 'track_uuid': '42e93aeb-43c6-4364-beb6-abf3f2d15d2f'}, {'max_concept': 'Paragorgia', 'track_uuid': '450c17d8-ef07-41a6-9c47-2d33aec70120'}, {'max_concept': 'Paragorgia', 'track_uuid': '5afe833f-8b16-4efa-b137-8a25ac08a619'}, {'max_concept': 'Paragorgia', 'track_uuid': '730bd37e-e40d-4b65-931f-2bcab3a6c368'}, {'max_concept': 'Paragorgia', 'track_uuid': '7c968eed-e4d9-49d2-a152-76af15404de5'}, {'max_concept': 'Paragorgia', 'track_uuid': '84dd1489-b592-42a5-b2e2-190ec4b502c9'}, {'max_concept': 'Paragorgia', 'track_uuid': 'a0fc8cd6-8412-4828-946e-5ebef95b50e4'}, {'max_concept': 'Paragorgia', 'track_uuid': 'c0de7291-504c-419b-9104-90535b609c4b'}, {'max_concept': 'Paragorgia', 'track_uuid': 'f874505a-8406-47c2-a674-aafcfd146bf8'}, {'max_concept': 'Paragorgia', 'track_uuid': 'f9321a39-4787-491b-91c5-e56dab97dc75'}, {'max_concept': 'Paragorgia arborea', 'track_uuid': '90df3b41-0020-49eb-ae6b-f22be192caf9'}, {'max_concept': 'Peniagone', 'track_uuid': '6b466c38-8ad4-4c13-abed-b2536f8225f8'}, {'max_concept': 'Porifera', 'track_uuid': '60eb1a48-f722-4d2f-adda-21d2c70933ed'}, {'max_concept': 'Porifera', 'track_uuid': '64e41b0b-7384-4b5d-9c74-761bdcd6d00a'}, {'max_concept': 'Porifera', 'track_uuid': '7ecc1a9d-19e0-4eb4-b45c-9f238177772c'}, {'max_concept': 'Porifera', 'track_uuid': 'e3451cf5-4fa8-4edc-a4d6-e01e149d7596'}, {'max_concept': 'Porifera', 'track_uuid': 'ee964e56-0e4b-453c-8a2b-4969e72b39b3'}, {'max_concept': 'Pteraster', 'track_uuid': '37e18986-daac-405f-8579-3641e76dd80e'}, {'max_concept': 'Pteraster', 'track_uuid': '3bef9d18-4480-4c74-94c3-829c82a1f14e'}, {'max_concept': 'Rathbunaster californicus', 'track_uuid': '0f86a679-714b-4d86-a34e-691845f8039f'}, {'max_concept': 'Rathbunaster californicus', 'track_uuid': 'a61cff90-6244-4cb4-8130-0234cef7c9ba'}, {'max_concept': 'Sebastolobus', 'track_uuid': '4038c52a-7d24-43df-abd0-3e766df359a0'}, {'max_concept': 'Sebastolobus', 'track_uuid': '44e085b1-4401-443d-941c-383ba17f5bf4'}, {'max_concept': 'Sebastolobus', 'track_uuid': '5222e185-b500-460e-bd7c-c1f20319ff1b'}, {'max_concept': 'Sebastolobus', 'track_uuid': '66ec11d2-57ed-49d1-ae42-20890e7f6404'}, {'max_concept': 'Sebastolobus', 'track_uuid': '79f5a56e-2cc1-428c-9721-af3a7f60ed33'}, {'max_concept': 'Sebastolobus', 'track_uuid': '7b598859-c774-4388-b11e-39a64b643a41'}, {'max_concept': 'Sebastolobus', 'track_uuid': '82f70130-b593-47c4-8486-094525fa58f9'}, {'max_concept': 'Sebastolobus', 'track_uuid': '833c6a5c-b8fc-4497-8e6c-40066f8d9a35'}, {'max_concept': 'Sebastolobus', 'track_uuid': '84bd9435-9104-486a-a572-e76385cb47a3'}, {'max_concept': 'Sebastolobus', 'track_uuid': '883b1612-4305-4095-babc-85fa5681d761'}, {'max_concept': 'Sebastolobus', 'track_uuid': '9a37b6fe-e36d-499e-a1f1-7fa925100354'}, {'max_concept': 'Sebastolobus', 'track_uuid': 'a324866a-685f-4b76-a75d-6acef3519909'}, {'max_concept': 'Sebastolobus', 'track_uuid': 'a3b09b58-11e6-4490-8452-c54c8a7c3959'}, {'max_concept': 'Sebastolobus', 'track_uuid': 'b9655f32-505a-4f6a-a1d0-b9ab5acbee7a'}, {'max_concept': 'Sebastolobus', 'track_uuid': 'bb1e3c62-f01f-40e3-850e-2ba80222bd21'}, {'max_concept': 'Sebastolobus', 'track_uuid': 'c0f6d175-9dfe-4759-8473-38078620f556'}, {'max_concept': 'Sebastolobus', 'track_uuid': 'e3451cf5-4fa8-4edc-a4d6-e01e149d7596'}, {'max_concept': 'Swiftia', 'track_uuid': '9815bb70-7f54-4ff0-adf3-89ac26996a19'}, {'max_concept': 'Swiftia', 'track_uuid': 'db6a9f86-b87f-464b-8d68-d00c329b9eca'}, {'max_concept': 'Swiftia', 'track_uuid': 'f7316d37-e712-4541-abf3-42d89351aead'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '060007aa-df7d-4d41-98a3-0fa572d690c9'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '09b03505-a50c-46c6-9c0c-202d143c4953'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '11dc24fe-8549-4ff1-bace-137d3aee171a'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '133a3ea5-9441-4621-8db2-51f0132bf542'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '139857fe-6cde-4a1a-829b-b899471ecfc1'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '26545f9f-09fd-4373-904f-bf95961b0b3c'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '2d53af7e-9e7c-4063-8cf8-43952306872d'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '2e985ec9-c660-4805-830f-a74e700e905a'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '326759c0-7dbc-42e4-98ac-9c63e59fc23b'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '3a1bdbbc-afe9-42d2-bad1-3ab628ae11ed'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '495abcee-8a8f-492d-a4e7-67d710f0ab28'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '53492288-acc3-49fd-a138-9ddd0833be60'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '7b598859-c774-4388-b11e-39a64b643a41'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '83b518c2-7bf5-49ec-9d7c-8af926e2566b'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '957d89df-963d-43d5-bb55-7da4530327af'}, {'max_concept': 'Swiftia simplex', 'track_uuid': '9ee05da6-0b8a-4eb5-99ce-030d401f6785'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'b20bbb30-d20d-4965-b88e-3b0aa9212751'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'b51b947d-e855-497b-9b6c-a029e116b894'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'bcb9f820-6101-43bf-a989-b22cdd635026'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'c0fa0875-33ba-4633-81b4-b44048e8ae7a'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'c35a3bcc-0a73-4eca-807e-de2bbff71bbc'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'ce881556-9ff8-4c1b-8915-75095dd3fefd'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'db4f91e4-d65c-495f-b731-7af2ac78493e'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'dbdd9bed-3b37-4e88-996f-6d2a2a616612'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'e72129cf-c8da-4cc8-8501-d956d4012897'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'eb273eb2-5057-489f-8a2e-d8ecc4cc96f9'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'ee823acf-1388-40bb-971c-79d67063d3d1'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'ef7016f7-f370-436f-b478-92694afd9f97'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'f6b07d81-f06a-4bdb-883d-64f0d12db487'}, {'max_concept': 'Swiftia simplex', 'track_uuid': 'fe5cb55a-ce8e-4e24-810e-5182aae02cd1'}]}
Change a concept for a track¶
To change a concept for one or more tracks, pass in the unique identifiers and the concept name to change to. This will assign all Events that have that same unique track identifier to the concept.
def change_track_concept(track_uuids: [str], concept:str):
query = """ mutation
changeTrackConcept($track_uuids: [String!], $concept: String!) {
changeTracksByUuid(track_uuids: $track_uuids, concept: $concept) {
success
message
}
}
"""
variables = {"track_uuids": track_uuids, "concept": concept}
reply = (requests.post(API_URL, headers={'Authorization': f'Bearer {AUTH_TOKEN}'}, json={'query': query, 'variables': variables}).json())
print(reply)
change_track_concept(["d51ab08a-1d4f-4f98-8a20-cd5372364cb0", "305fb9f1-2ec8-4a88-a40e-580fe6d015b9"], "detritus")
{'data': {'changeTracksByUuid': {'success': True, 'message': 'Done modifying detritus in tracks d51ab08a-1d4f-4f98-8a20-cd5372364cb0,305fb9f1-2ec8-4a88-a40e-580fe6d015b9'}}}
Delete a track¶
To remove a track that was incorrect, e.g. to remove a track of something that was not a real concept/class, use the following mutation
def delete_track(track_uuids: [str]):
query = """ mutation
deleteTrack($track_uuids: [String!]) {
deleteTracksByUuid(track_uuids: $track_uuids) {
success
message
}
}
"""
variables = {"track_uuids": track_uuids}
reply = (requests.post(API_URL, headers={'Authorization': f'Bearer {AUTH_TOKEN}'},
json={'query': query, 'variables': variables}).json())
print(reply)
delete_track("442ad603-5a69-46b9-afb2-278005ffd7dd")
{'data': {'deleteTracksByUuid': {'success': False, 'message': 'One or more tracks 442ad603-5a69-46b9-afb2-278005ffd7dd not found '}}}
Change an track identifier¶
To change the unique identifier to another, use the changeEventsInTrack mutation. This can be useful in a sequence of operations to clean-up bad tracking results.
def change_events_in_track(source_track_uuid: str, target_track_uuid: str):
query = """ mutation
changeEvents($source_track_uuid: String!, $target_track_uuid: String!) {
changeEventsInTrack(source_track_uuid: $source_track_uuid, target_track_uuid: $target_track_uuid ) {
success
message
}
}
"""
variables = {"source_track_uuid": source_track_uuid, "target_track_uuid": target_track_uuid}
reply = (requests.post(API_URL, headers={'Authorization': f'Bearer {AUTH_TOKEN}'},
json={'query': query, 'variables': variables}).json())
print(reply)
change_events_in_track("597f7b93-b89b-476c-9c20-df91db96cbc2", "7b598859-c774-4388-b11e-39a64b643a41")
{'data': {'changeEventsInTrack': {'success': False, 'message': 'No matching events in track 597f7b93-b89b-476c-9c20-df91db96cbc2'}}}