-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8fd37b6
commit aa733b4
Showing
11 changed files
with
3,558 additions
and
242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,4 +26,5 @@ cdk/cdk.context.json | |
**/.pytest_cache | ||
**/dist/ | ||
**/venv/ | ||
**/.ipynb_checkpoints | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
python_sources( | ||
name="notebook-utils", | ||
) | ||
|
||
resources( | ||
name="notebooks", | ||
sources=["*.ipynb"], | ||
) | ||
|
||
# To run: | ||
# pants run packages/roboto/examples:jupyter | ||
pex_binary( | ||
name="jupyter", | ||
dependencies=[ | ||
":notebooks", | ||
":notebook-utils", | ||
"//packages/roboto/src/roboto:roboto-src", | ||
|
||
# roboto[analytics] extras | ||
"//build-support:3rdparty#numpy", | ||
"//build-support:3rdparty#pandas", | ||
"//build-support:3rdparty#stumpy", | ||
|
||
# build-support[sdk_examples] extras | ||
"//build-support:3rdparty-dev-tools#ipython", | ||
"//build-support:3rdparty-dev-tools#jupyter", | ||
"//build-support:3rdparty-dev-tools#matplotlib", | ||
"//build-support:3rdparty-dev-tools#pillow", | ||
], | ||
script="jupyter", | ||
args=["lab", f"--notebook-dir='{build_file_dir()}'"], | ||
execution_mode="venv", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
SDK usage examples | ||
================== | ||
|
||
This directory contains Jupyter notebooks demonstrating the use and features of the Roboto Python SDK. | ||
|
||
## Setup | ||
|
||
1. Setup your environment for [programmatic access to the Roboto platform](http://docs.roboto.ai/getting-started/programmatic-access.html) | ||
|
||
2. Create a virtual environment using Python >= 3.10: | ||
```bash | ||
python -m venv .venv | ||
``` | ||
|
||
3. Install the SDK with relevant pip extras: | ||
|
||
_This assumes you're running this command from the root of the repository._ | ||
|
||
```bash | ||
.venv/bin/python -m pip install .[analytics,examples] | ||
``` | ||
|
||
## Running the examples | ||
|
||
Start the Jupyter server and run the cells in notebooks of interest: | ||
```bash | ||
.venv/bin/jupyter lab --notebook-dir=examples | ||
``` | ||
|
||
_If you're running the `jupyter lab` command from the `examples` directory itself, there's no need to specify the `--notebook-dir` argument. It's only necessary if you're running it from the root of the repository._ | ||
|
||
## Learn more | ||
|
||
For more information, check out: | ||
* [General Docs](https://docs.roboto.ai/) | ||
* [User Guides](https://docs.roboto.ai/user-guides/index.html) | ||
* [SDK Reference](https://docs.roboto.ai/reference/python-sdk/roboto/index.html) | ||
* [CLI Reference](https://docs.roboto.ai/reference/cli.html) | ||
* [About Roboto](https://www.roboto.ai/about) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# Copyright (c) 2024 Roboto Technologies, Inc. | ||
# | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
""" | ||
This is a collection of utilities used by the similarity search example notebook | ||
to format and display the results of a Roboto similarity search. | ||
""" | ||
|
||
import base64 | ||
import io | ||
import math | ||
|
||
from IPython.core.pylabtools import print_figure | ||
from IPython.display import HTML, display | ||
import PIL.Image | ||
import matplotlib.pyplot | ||
import matplotlib.ticker | ||
|
||
import roboto | ||
import roboto.analytics | ||
|
||
NANO_SEC_PER_SEC = 1e9 | ||
|
||
|
||
def images_frames_to_encoded_gif(image_frames, fps=10, loops=math.inf) -> str: | ||
images = [PIL.Image.open(io.BytesIO(frame)) for frame in image_frames] | ||
buffer = io.BytesIO() | ||
|
||
frame_duration_ms = (1 / fps) * 1000 | ||
|
||
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif-saving | ||
images[0].save( | ||
buffer, | ||
format="GIF", | ||
save_all=True, | ||
append_images=images[1:], | ||
duration=frame_duration_ms, | ||
loop=0 if loops == math.inf else loops, # 0 means loop forever | ||
) | ||
|
||
buffer.seek(0) | ||
|
||
return base64.b64encode(buffer.getvalue()).decode("utf-8") | ||
|
||
|
||
def format_log_time(log_time: int) -> str: | ||
sec, nano_sec = divmod(log_time, NANO_SEC_PER_SEC) | ||
return f"{int(sec)}.{int(nano_sec)}" | ||
|
||
|
||
def plot_match(match: roboto.analytics.Match) -> matplotlib.pyplot.Figure: | ||
fig, ax = matplotlib.pyplot.subplots() | ||
|
||
fig.set_size_inches(5, 3) | ||
ax.plot(match.subsequence) | ||
ax.set_xticks([match.start_time, match.end_time]) | ||
ax.xaxis.set_major_formatter( | ||
matplotlib.ticker.FuncFormatter(lambda val, _: format_log_time(val)) | ||
) | ||
matplotlib.pyplot.setp(ax.spines.values(), lw=0.5) | ||
|
||
return fig | ||
|
||
|
||
def format_match( | ||
match: roboto.analytics.Match, | ||
image_topic_name: str, | ||
additional_image_context_duration_seconds: float = 1.5, | ||
roboto_client: roboto.RobotoClient | None = None, | ||
) -> str: | ||
additional_image_context_duration_ns = int( | ||
additional_image_context_duration_seconds * NANO_SEC_PER_SEC | ||
) | ||
FALLBACK_GIF = "R0lGODlhAQABAIAAAAUEBA==" # 1x1 transparent GIF | ||
gif = FALLBACK_GIF | ||
if match.context.file_id is not None: | ||
try: | ||
file = roboto.File.from_id( | ||
match.context.file_id, roboto_client=roboto_client | ||
) | ||
image_topic = file.get_topic(image_topic_name) | ||
image_topic_data = image_topic.get_data( | ||
message_paths_include=["data"], | ||
start_time=match.start_time - additional_image_context_duration_ns, | ||
end_time=match.end_time + additional_image_context_duration_ns, | ||
) | ||
image_frames = [msg["data"] for msg in image_topic_data] | ||
gif = images_frames_to_encoded_gif(image_frames) | ||
except BaseException: | ||
pass | ||
|
||
fig = plot_match(match) | ||
plot_image = print_figure( | ||
fig, | ||
bbox_inches="tight", | ||
base64=True, | ||
dpi=600, | ||
) | ||
matplotlib.pyplot.close(fig) | ||
|
||
return f"""\ | ||
<div style="display: flex; align-items: center; margin-bottom: 20px; width: 100%;"> | ||
<div style="style="flex: 0 0 10%; margin-right: 10px; text-align: center;"> | ||
{match.distance} | ||
</div> | ||
<div style="flex: 1; margin-right: 10px; text-align: center;"> | ||
<img | ||
src="data:image/png;base64,{plot_image}" | ||
style="height: auto; max-width: 100%" | ||
/> | ||
</div> | ||
<div style="flex: 1; margin-right: 10px; text-align: center;"> | ||
<img | ||
src="data:image/gif;base64,{gif}" | ||
style="height: auto; max-width: 100%;" | ||
/> | ||
</div> | ||
<div style="flex: 0 0 10%; margin-right: 10px; text-align: center;"> | ||
<a | ||
href="https://app.roboto.ai/files/{match.context.file_id}" | ||
target="_blank" | ||
> | ||
View in Roboto | ||
</a> | ||
</div> | ||
</div> | ||
""" | ||
|
||
|
||
def print_match_results( | ||
matches: list[roboto.analytics.Match], | ||
image_topic: str, | ||
additional_image_context_duration_seconds: float = 1.5, | ||
roboto_client: roboto.RobotoClient | None = None, | ||
) -> None: | ||
HEADER_HTML = """\ | ||
<div style="display: flex; align-items: center; margin-bottom: 10px; width: 100%; font-weight: bold;"> | ||
<div style="flex: 0 0 10%; margin-right: 10px; text-align: center;">Distance</div> | ||
<div style="flex: 1; margin-right: 10px; text-align: center;">Matching sequence</div> | ||
<div style="flex: 1; text-align: center;">Camera topic</div> | ||
<div style="flex: 0 0 10%; margin-right: 10px; text-align: center;">Link</div> | ||
</div> | ||
""" | ||
display(HTML(HEADER_HTML)) | ||
|
||
for match in matches: | ||
display( | ||
HTML( | ||
format_match( | ||
match, | ||
image_topic, | ||
additional_image_context_duration_seconds, | ||
roboto_client, | ||
) | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"id": "cb4e0010-2301-48ba-acec-921f1a7911ee", | ||
"metadata": {}, | ||
"source": [ | ||
"### Initialization" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "de8b8546-fbd3-44a1-83ce-b5dcbc944748", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import roboto\n", | ||
"import roboto.query\n", | ||
"\n", | ||
"\n", | ||
"roboto_config = roboto.RobotoConfig.from_env(\"prod\")\n", | ||
"roboto_client = roboto.RobotoClient.from_config(roboto_config)\n", | ||
"query_client = roboto.query.QueryClient(\n", | ||
" roboto_client=roboto_client,\n", | ||
" owner_org_id=\"og_najtcyyee2qa\" # Drone Racing EU\n", | ||
")\n", | ||
"robotosearch = roboto.RobotoSearch(query_client=query_client)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "d2726851-7334-4091-a846-a73dd09f0b97", | ||
"metadata": {}, | ||
"source": [ | ||
"### Retrieve Event and Find Similar Signals" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "3aa216bd-e8fa-4997-abed-9a60c8bb16bb", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import roboto.analytics\n", | ||
"\n", | ||
"\n", | ||
"event = roboto.domain.events.Event.from_id(\n", | ||
" \"ev_6funfjngoznn17x3\", \n", | ||
" roboto_client=roboto_client\n", | ||
")\n", | ||
"\n", | ||
"# This is the topic on which the event was made.\n", | ||
"# In this example, it's the \"/snappy_imu\" topic.\n", | ||
"source_topic = roboto.Topic.from_id(\n", | ||
" event.topic_ids[0], \n", | ||
" roboto_client=roboto_client\n", | ||
")\n", | ||
"topics_to_match_against = robotosearch.find_topics(f\"topic.name = '{source_topic.name}'\")\n", | ||
"\n", | ||
"query_signal = event.get_data_as_df(\n", | ||
" message_paths_include=[\"linear_acceleration\", \"angular_velocity\"]\n", | ||
")\n", | ||
"\n", | ||
"matches = roboto.analytics.find_similar_signals(\n", | ||
" query_signal,\n", | ||
" topics_to_match_against,\n", | ||
" max_matches_per_topic=1,\n", | ||
" normalize=True\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "0413e6da-eeeb-4bb2-85a5-9b4898fd5a4e", | ||
"metadata": {}, | ||
"source": [ | ||
"### Inspect Results" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "72baea36-6364-4194-8f81-c60b0d600de0", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from match_visualization_utils import print_match_results\n", | ||
"\n", | ||
"\n", | ||
"print_match_results(\n", | ||
" matches[:5], \n", | ||
" image_topic=\"/snappy_cam/stereo_l\", \n", | ||
" roboto_client=roboto_client\n", | ||
")" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3 (ipykernel)", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.10.12" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.