diff --git a/rerun_py/rerun_sdk/rerun/blueprint/api.py b/rerun_py/rerun_sdk/rerun/blueprint/api.py index 6bea25e2a582..ae031e3ded94 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/api.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/api.py @@ -134,6 +134,7 @@ def __init__( column_shares: Optional[ColumnShareArrayLike] = None, row_shares: Optional[RowShareArrayLike] = None, grid_columns: Optional[int] = None, + active_tab: Optional[int | str] = None, ): """ Construct a new container. @@ -155,6 +156,8 @@ def __init__( This is only applicable to `Vertical` or `Grid` containers. grid_columns The number of columns in the grid. This is only applicable to `Grid` containers. + active_tab + The active tab in the container. This is only applicable to `Tabs` containers. """ self.id = uuid.uuid4() @@ -163,6 +166,7 @@ def __init__( self.column_shares = column_shares self.row_shares = row_shares self.grid_columns = grid_columns + self.active_tab = active_tab def blueprint_path(self) -> str: """ @@ -183,8 +187,15 @@ def to_blueprint(self) -> Blueprint: def _log_to_stream(self, stream: RecordingStream) -> None: """Internal method to convert to an archetype and log to the stream.""" - for sub in self.contents: + active_tab_path = None + + for i, sub in enumerate(self.contents): sub._log_to_stream(stream) + if i == self.active_tab or (isinstance(sub, SpaceView) and sub.name == self.active_tab): + active_tab_path = sub.blueprint_path() + + if self.active_tab is not None and active_tab_path is None: + raise ValueError(f"Active tab '{self.active_tab}' not found in the container contents.") arch = ContainerBlueprint( container_kind=self.kind, @@ -193,6 +204,7 @@ def _log_to_stream(self, stream: RecordingStream) -> None: row_shares=self.row_shares, visible=True, grid_columns=self.grid_columns, + active_tab=active_tab_path, ) stream.log(self.blueprint_path(), arch) # type: ignore[attr-defined] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/containers.py b/rerun_py/rerun_sdk/rerun/blueprint/containers.py index db47f5a1fdba..243201151c37 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/containers.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/containers.py @@ -84,7 +84,7 @@ def __init__( class Tabs(Container): """A tab container.""" - def __init__(self, *contents: Container | SpaceView): + def __init__(self, *contents: Container | SpaceView, active_tab: Optional[int | str] = None): """ Construct a new tab container. @@ -92,6 +92,8 @@ def __init__(self, *contents: Container | SpaceView): ---------- *contents: All positional arguments are the contents of the container, which may be either other containers or space views. + active_tab: + The index or name of the active tab. """ - super().__init__(*contents, kind=ContainerKind.Tabs) + super().__init__(*contents, kind=ContainerKind.Tabs, active_tab=active_tab) diff --git a/rerun_py/rerun_sdk/rerun/script_helpers.py b/rerun_py/rerun_sdk/rerun/script_helpers.py index d4542a7e9362..86d48e01338d 100644 --- a/rerun_py/rerun_sdk/rerun/script_helpers.py +++ b/rerun_py/rerun_sdk/rerun/script_helpers.py @@ -65,6 +65,7 @@ def script_setup( args: Namespace, application_id: str, recording_id: str | UUID | None = None, + blueprint: rr.blueprint.Blueprint | None = None, ) -> RecordingStream: """ Run common Rerun script setup actions. Connect to the viewer if necessary. @@ -86,6 +87,8 @@ def script_setup( processes to log to the same Rerun instance (and be part of the same recording), you will need to manually assign them all the same recording_id. Any random UUIDv4 will work, or copy the recording id for the parent process. + blueprint : Optional[rr.blueprint.Blueprint] + An optional blueprint to use for the viewer. """ rr.init( @@ -106,11 +109,11 @@ def script_setup( # Send logging data to separate `rerun` process. # You can omit the argument to connect to the default address, # which is `127.0.0.1:9876`. - rec.connect(args.addr) # type: ignore[attr-defined] + rec.connect(args.addr, blueprint=blueprint) # type: ignore[attr-defined] elif args.save is not None: rec.save(args.save) # type: ignore[attr-defined] elif not args.headless: - rec.spawn() # type: ignore[attr-defined] + rec.spawn(blueprint=blueprint) # type: ignore[attr-defined] return rec