Skip to content

Commit

Permalink
Improve new time_ranges property python api & add snippet for time se…
Browse files Browse the repository at this point in the history
…ries view, explaining all its options (#6221)

<!--
Open the PR up as a draft until you feel it is ready for a proper
review.

Do not make PR:s from your own `main` branch, as that makes it difficult
for reviewers to add their own fixes.

Add any improvements to the branch as new commits to make it easier for
reviewers to follow the progress. All commits will be squashed to a
single commit once the PR is merged into `main`.

Make sure you mention any issues that this PR closes in the description,
as well as any other related issues.

To get an auto-generated PR description you can put "copilot:summary" or
"copilot:walkthrough" anywhere.
-->

### What

Improve `VisibleTimeRange` python api and add a snippet for time series
view which is the primary (but not sole!) user of this feature.

```
# Create a TimeSeries View
blueprint = rrb.Blueprint(
    rrb.TimeSeriesView(
        origin="/trig",
        # Set a custom Y axis.
        axis_y=rrb.ScalarAxis(range=(-1.0, 1.0), lock_range_during_zoom=True),
        # Configure the legend.
        plot_legend=rrb.PlotLegend(visible=False),
        # Set time different time ranges for different timelines.
        time_ranges=[
            # Sliding window depending on the time cursor for the first timeline.
            rrb.VisibleTimeRange(
                "timeline0",
                start=rrb.TimeRangeBoundary.cursor_relative(-100),
                end=rrb.TimeRangeBoundary.cursor_relative(),
            ),
            # Time range from some point to the end of the timeline for the second timeline.
            rrb.VisibleTimeRange(
                "timeline1",
                start=rrb.TimeRangeBoundary.absolute(300),
                end=rrb.TimeRangeBoundary.infinite(),
            ),
        ],
    )
)
```


TODO:
* [x] update usage on checklist test!
* [x] integrate with snippet reorg pr 
* [x] put the snippet on to timeseries view
* [x] check again whether we can't make `TimeRangeBoundary` a union and
if we can't or don't want note it down into the fbs file why

~* think about how to document time range on other places and how to
document usage of `VisibleTimeRange` type itself~
    * consider providing several snippets
~* update docs on visible time range in the manual with some code
examples while we're on it?~


### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested the web demo (if applicable):
* Using examples from latest `main` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/6221?manifest_url=https://app.rerun.io/version/main/examples_manifest.json)
* Using full set of examples from `nightly` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/6221?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG
* [x] If applicable, add a new check to the [release
checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)!

- [PR Build Summary](https://build.rerun.io/pr/6221)
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)

To run all checks from `main`, comment on the PR with `@rerun-bot
full-check`.
  • Loading branch information
Wumpf authored May 8, 2024
1 parent 1942b43 commit 8afcafa
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ namespace rerun.blueprint.archetypes;
/// - For any other view, the default is to apply latest-at semantics.
table VisibleTimeRanges (
"attr.rerun.scope": "blueprint",
"attr.rust.derive": "Default"
"attr.rust.derive": "Default",
"attr.python.aliases": "datatypes.VisibleTimeRangeLike, Sequence[datatypes.VisibleTimeRangeLike]"
) {
/// The time ranges to show for each timeline unless specified otherwise on a per-entity basis.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ include "rerun/attributes.fbs";
namespace rerun.blueprint.views;

/// A time series view.
///
/// \example timeseriesview title="Use a blueprint to customize a TimeSeriesView"
table TimeSeriesView (
"attr.rerun.view_identifier": "TimeSeries"
) {
Expand Down
6 changes: 6 additions & 0 deletions docs/content/reference/types/views/time_series_view.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions docs/snippets/all/timeseriesview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Use a blueprint to customize a TimeSeriesView."""

import math

import rerun as rr
import rerun.blueprint as rrb

rr.init("rerun_example_timeseries", spawn=True)

# Log some trigonometric functions
rr.log("trig/sin", rr.SeriesLine(color=[255, 0, 0], name="sin(0.01t)"), static=True)
rr.log("trig/cos", rr.SeriesLine(color=[0, 255, 0], name="cos(0.01t)"), static=True)
rr.log("trig/cos", rr.SeriesLine(color=[0, 0, 255], name="cos(0.01t) scaled"), static=True)
for t in range(0, int(math.pi * 4 * 100.0)):
rr.set_time_sequence("timeline0", t)
rr.set_time_sequence("timeline1", t)
rr.log("trig/sin", rr.Scalar(math.sin(float(t) / 100.0)))
rr.log("trig/cos", rr.Scalar(math.cos(float(t) / 100.0)))
rr.log("trig/cos_scaled", rr.Scalar(math.cos(float(t) / 100.0) * 2.0))

# Create a TimeSeries View
blueprint = rrb.Blueprint(
rrb.TimeSeriesView(
origin="/trig",
# Set a custom Y axis.
axis_y=rrb.ScalarAxis(range=(-1.0, 1.0), lock_range_during_zoom=True),
# Configure the legend.
plot_legend=rrb.PlotLegend(visible=False),
# Set time different time ranges for different timelines.
time_ranges=[
# Sliding window depending on the time cursor for the first timeline.
rrb.VisibleTimeRange(
"timeline0",
start=rrb.TimeRangeBoundary.cursor_relative(-100),
end=rrb.TimeRangeBoundary.cursor_relative(),
),
# Time range from some point to the end of the timeline for the second timeline.
rrb.VisibleTimeRange(
"timeline1",
start=rrb.TimeRangeBoundary.absolute(300),
end=rrb.TimeRangeBoundary.infinite(),
),
],
)
)

rr.send_blueprint(blueprint)
5 changes: 5 additions & 0 deletions rerun_py/rerun_sdk/rerun/blueprint/__init__.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion rerun_py/rerun_sdk/rerun/blueprint/views/spatial2d_view.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 62 additions & 2 deletions rerun_py/rerun_sdk/rerun/blueprint/views/time_series_view.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion rerun_py/rerun_sdk/rerun/datatypes/time_range_boundary.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 62 additions & 0 deletions rerun_py/rerun_sdk/rerun/datatypes/time_range_boundary_ext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from . import TimeInt, TimeIntLike

if TYPE_CHECKING:
from .time_range_boundary import TimeRangeBoundary


class TimeRangeBoundaryExt:
"""Extension for [TimeRangeBoundary][rerun.datatypes.TimeRangeBoundary]."""

@staticmethod
def cursor_relative(time: TimeIntLike = 0) -> TimeRangeBoundary:
"""
Boundary that is relative to the timeline cursor.
Parameters
----------
time:
Offset from the cursor time, can be positive or negative.
"""

from .time_range_boundary import TimeRangeBoundary

if not isinstance(time, TimeInt):
time = TimeInt(time)

return TimeRangeBoundary(inner=time, kind="cursor_relative")

@staticmethod
def infinite() -> TimeRangeBoundary:
"""
Boundary that extends to infinity.
Depending on the context, this can mean the beginning or the end of the timeline.
"""

from .time_range_boundary import TimeRangeBoundary

return TimeRangeBoundary(inner=None, kind="infinite")

@staticmethod
def absolute(time: TimeIntLike) -> TimeRangeBoundary:
"""
Boundary that is at an absolute time.
Parameters
----------
time:
Absolute time value.
"""

from .time_range_boundary import TimeRangeBoundary

if not isinstance(time, TimeInt):
time = TimeInt(time)

return TimeRangeBoundary(inner=time, kind="absolute")
21 changes: 4 additions & 17 deletions rerun_py/rerun_sdk/rerun/datatypes/visible_time_range.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions rerun_py/rerun_sdk/rerun/datatypes/visible_time_range_ext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations

from typing import Any

from .. import datatypes


class VisibleTimeRangeExt:
"""Extension for [VisibleTimeRange][rerun.datatypes.VisibleTimeRange]."""

def __init__(
self: Any,
timeline: datatypes.Utf8Like,
range: datatypes.TimeRangeLike | None = None,
*,
start: datatypes.TimeRangeBoundary | None = None,
end: datatypes.TimeRangeBoundary | None = None,
):
"""
Create a new instance of the VisibleTimeRange datatype.
Parameters
----------
timeline:
Name of the timeline this applies to.
range:
Time range to use for this timeline.
start:
Low time boundary for sequence timeline. Specify this instead of `range`.
end:
High time boundary for sequence timeline. Specify this instead of `range`.
"""
from . import TimeRange

if range is None:
if start is None or end is None:
raise ValueError("Specify either start_and_end or both start & end")
range = TimeRange(start=start, end=end)
else:
if start is not None or end is not None:
raise ValueError("Specify either start_and_end or both start & end, not both")

self.__attrs_init__(timeline=timeline, range=range)
Loading

0 comments on commit 8afcafa

Please sign in to comment.