chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
<!--[metadata]
|
||||
title = "Live scrolling plot"
|
||||
tags = ["Plots", "Live"]
|
||||
thumbnail = "https://static.rerun.io/live_scrolling_plot_thumbnail/73c6b11bd074af258b8d30092e15361e358d8069/480w.png"
|
||||
thumbnail_dimensions = [480, 384]
|
||||
-->
|
||||
|
||||
Visualize a live stream of several plots, scrolling horizontally to keep a fixed window of data.
|
||||
|
||||
<picture>
|
||||
<img src="https://static.rerun.io/live_scrolling_plot/9c9a9b3a4dd1d5e858ba58489f686b5d481cfb2e/full.png" alt="">
|
||||
<source media="(max-width: 480px)" srcset="https://static.rerun.io/live_scrolling_plot/9c9a9b3a4dd1d5e858ba58489f686b5d481cfb2e/480w.png">
|
||||
<source media="(max-width: 768px)" srcset="https://static.rerun.io/live_scrolling_plot/9c9a9b3a4dd1d5e858ba58489f686b5d481cfb2e/768w.png">
|
||||
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/live_scrolling_plot/9c9a9b3a4dd1d5e858ba58489f686b5d481cfb2e/1024w.png">
|
||||
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/live_scrolling_plot/9c9a9b3a4dd1d5e858ba58489f686b5d481cfb2e/1200w.png">
|
||||
</picture>
|
||||
|
||||
## Used Rerun types
|
||||
[`Scalars`](https://www.rerun.io/docs/reference/types/archetypes/scalars)
|
||||
|
||||
## Setting up the blueprint
|
||||
|
||||
In order to only show a fixed window of data, this example creates a blueprint that uses
|
||||
the `time_ranges` parameter of the `TimeSeriesView` blueprint type.
|
||||
|
||||
We dynamically create a `TimeSeriesView` for each plot we want to show, so that we can
|
||||
set the `time_ranges`. The start of the visible time range is set to the current time
|
||||
minus the window size, and the end is set to the current time.
|
||||
|
||||
```python
|
||||
rr.send_blueprint(
|
||||
rrb.Grid(
|
||||
contents=[
|
||||
rrb.TimeSeriesView(
|
||||
origin=plot_path,
|
||||
time_ranges=[
|
||||
rrb.VisibleTimeRange(
|
||||
"time",
|
||||
start=rrb.TimeRangeBoundary.cursor_relative(seconds=-args.window_size),
|
||||
end=rrb.TimeRangeBoundary.cursor_relative(),
|
||||
)
|
||||
],
|
||||
plot_legend=rrb.PlotLegend(visible=False),
|
||||
)
|
||||
for plot_path in plot_paths
|
||||
]
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
## Run the code
|
||||
To run this example, make sure you have the Rerun repository checked out and the latest SDK installed:
|
||||
```bash
|
||||
# Setup
|
||||
pip install --upgrade rerun-sdk # install the latest Rerun SDK
|
||||
git clone git@github.com:rerun-io/rerun.git # Clone the repository
|
||||
cd rerun
|
||||
git checkout latest # Check out the commit matching the latest SDK release
|
||||
```
|
||||
Install the necessary libraries specified in the requirements file:
|
||||
```bash
|
||||
pip install -e examples/python/live_scrolling_plot
|
||||
```
|
||||
|
||||
Then, simply execute the main Python script:
|
||||
```bash
|
||||
python -m live_scrolling_plot
|
||||
```
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Show several live plots of random walk data using a scrolling fixed window size."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import numpy as np
|
||||
|
||||
import rerun as rr # pip install rerun-sdk
|
||||
import rerun.blueprint as rrb
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterator
|
||||
|
||||
|
||||
def random_walk_generator() -> Iterator[float]:
|
||||
value = 0.0
|
||||
while True:
|
||||
value += np.random.normal()
|
||||
yield value
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Plot dashboard stress test")
|
||||
rr.script_add_args(parser)
|
||||
|
||||
parser.add_argument("--num-plots", type=int, default=6, help="How many different plots?")
|
||||
parser.add_argument("--num-series-per-plot", type=int, default=5, help="How many series in each single plot?")
|
||||
parser.add_argument("--freq", type=float, default=100, help="Frequency of logging (applies to all series)")
|
||||
parser.add_argument("--window-size", type=float, default=5.0, help="Size of the window in seconds")
|
||||
parser.add_argument("--duration", type=float, default=60, help="How long to log for in seconds")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
plot_paths = [f"plot_{i}" for i in range(args.num_plots)]
|
||||
series_paths = [f"series_{i}" for i in range(args.num_series_per_plot)]
|
||||
|
||||
rr.script_setup(args, "rerun_example_live_scrolling_plot")
|
||||
|
||||
# Always send the blueprint since it is a function of the data.
|
||||
rr.send_blueprint(
|
||||
rrb.Grid(
|
||||
contents=[
|
||||
rrb.TimeSeriesView(
|
||||
origin=plot_path,
|
||||
time_ranges=[
|
||||
rrb.VisibleTimeRange(
|
||||
"time",
|
||||
start=rrb.TimeRangeBoundary.cursor_relative(seconds=-args.window_size),
|
||||
end=rrb.TimeRangeBoundary.cursor_relative(),
|
||||
),
|
||||
],
|
||||
plot_legend=rrb.PlotLegend(visible=False),
|
||||
)
|
||||
for plot_path in plot_paths
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
# Generate a list of generators for each series in each plot
|
||||
values = [[random_walk_generator() for _ in range(args.num_series_per_plot)] for _ in range(args.num_plots)]
|
||||
|
||||
cur_time = time.time()
|
||||
end_time = cur_time + args.duration
|
||||
time_per_tick = 1.0 / args.freq
|
||||
|
||||
while cur_time < end_time:
|
||||
# Advance time and sleep if necessary
|
||||
cur_time += time_per_tick
|
||||
sleep_for = cur_time - time.time()
|
||||
if sleep_for > 0:
|
||||
time.sleep(sleep_for)
|
||||
|
||||
if sleep_for < -0.1:
|
||||
print(f"Warning: missed logging window by {-sleep_for:.2f} seconds")
|
||||
|
||||
rr.set_time("time", timestamp=cur_time)
|
||||
|
||||
# Output each series based on its generator
|
||||
for plot_idx, plot_path in enumerate(plot_paths):
|
||||
for series_idx, series_path in enumerate(series_paths):
|
||||
rr.log(f"{plot_path}/{series_path}", rr.Scalars(next(values[plot_idx][series_idx])))
|
||||
|
||||
rr.script_teardown(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,12 @@
|
||||
[project]
|
||||
name = "live_scrolling_plot"
|
||||
version = "0.1.0"
|
||||
readme = "README.md"
|
||||
dependencies = ["numpy", "rerun-sdk"]
|
||||
|
||||
[project.scripts]
|
||||
live_scrolling_plot = "live_scrolling_plot:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
Reference in New Issue
Block a user