diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 334af92eb3f8..1257c67eebad 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -38,10 +38,11 @@ jobs: # * skip changelog PR links (so many) # * skip speculative links # * Stackoverflow links are no longer accessible from CI. + # * Tuxfamily.org links are down intermittently. # * Nyud links are down every now and then. # * TODO(#4085): https://rerun-io.github.io/rerun/dev/bench/ often 404:s for unknown reasons # * TODO(#4556): remove the `static.rerun.io` and `github.com` skips - linksToSkip: "https://stackoverflow.com/.*, https://cs.nyu.edu/~silberman/datasets/nyu_depth_v2.html, https://static.rerun.io/.*, https://github.com/.*, https://crates.io/crates/.*, https://github.com/rerun-io/rerun/pull/.*, .*?speculative-link, https://rerun-io.github.io/rerun/dev/bench/" + linksToSkip: "https://stackoverflow.com/.*, https://eigen.tuxfamily.org/, https://cs.nyu.edu/~silberman/datasets/nyu_depth_v2.html, https://static.rerun.io/.*, https://github.com/.*, https://crates.io/crates/.*, https://github.com/rerun-io/rerun/pull/.*, .*?speculative-link, https://rerun-io.github.io/rerun/dev/bench/" retry: true retryErrors: true retryErrorsCount: 5 diff --git a/docs/content/getting-started/visualize/blueprint.md b/docs/content/getting-started/visualize/blueprint.md deleted file mode 100644 index f4afdc697dfc..000000000000 --- a/docs/content/getting-started/visualize/blueprint.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Configure from code -order: 1 ---- - -TODO(#5466): diff --git a/docs/content/howto/configure-the-viewer.md b/docs/content/howto/configure-the-viewer.md new file mode 100644 index 000000000000..d345a881ef1d --- /dev/null +++ b/docs/content/howto/configure-the-viewer.md @@ -0,0 +1,25 @@ +--- +title: Configure the Viewer +order: 10 +--- + +Although the Rerun Viewer tries to do a reasonable job of using heuristics to automatically determine +an appropriate layout given the data that you provide, there will always be situations where the heuristic +results don't match the needs of a particular use-case. + +Fortunately, almost all aspects of the viewer can be configured via the [Blueprint](../reference/viewer/blueprint.md). + +The viewer Blueprint completely determines: + +- What contents are included in each view +- The type of view used to visualize the data +- The organizational layout and names of the different view panels and containers +- Configuration and styling properties of the individual data visualizers + +There are a few different ways to work with Blueprints: + +- [Blueprints can be modified interactively](./configure-the-viewer/interactively.md) +- [Blueprint files (.rbl) can be saved and loaded from disk](./configure-the-viewer/save-and-load.md) +- [Blueprints can be controlled directly from code](./configure-the-viewer/through-code.md) + +For a hands on example, you can also follow the [Blueprint API Tutorial](./configure-the-viewer/blueprint-api-tutorial.md). diff --git a/docs/content/howto/configure-the-viewer/blueprint-api-tutorial.md b/docs/content/howto/configure-the-viewer/blueprint-api-tutorial.md new file mode 100644 index 000000000000..bbc9ec4c52cc --- /dev/null +++ b/docs/content/howto/configure-the-viewer/blueprint-api-tutorial.md @@ -0,0 +1,389 @@ +--- +title: Blueprint API Tutorial +order: 4 +--- + +This tutorial will walk you through using the Blueprint APIs to better control the +layout and appearance of your data in the Rerun Viewer in Python. + +This walkthrough is based on the [stock charts](https://github.com/rerun-io/rerun/tree/main/examples/python/blueprint_stocks?speculative-link) example. +The main differences between this tutorial and the linked example are related to additional processing of +command-line flags, which are omitted here for simplicity. + +## Create an environment for you example + +We start by creating a new virtual environment and installing the Rerun SDK along with the dependencies +we will use in this example. + +On linux or mac: + +```bash +mkdir stocks_example +cd stocks_example +python -m venv venv +source venv/bin/activate +pip install rerun-sdk humanize yfinance +``` + +On windows: + +```bash +mkdir stocks_example +cd stocks_example +python -m venv venv +.\venv\Scripts\activate +pip install rerun-sdk humanize yfinance +``` + +## Create your script + +In your project folder, add a new file, `stocks.py`. + +First, we import the necessary libraries: + +```python +#!/usr/bin/env python3 +import datetime as dt +import humanize +import pytz +import yfinance as yf +from typing import Any + +import rerun as rr +import rerun.blueprint as rrb +``` + +Next, we create some helper functions for style data and a template for an info card: + +```python +brand_colors = { + "AAPL": 0xA2AAADFF, + "AMZN": 0xFF9900FF, + "GOOGL": 0x34A853FF, + "META": 0x0081FBFF, + "MSFT": 0xF14F21FF, +} + + +def style_plot(symbol: str) -> rr.SeriesLine: + return rr.SeriesLine( + color=brand_colors[symbol], + name=symbol, + ) + + +def style_peak(symbol: str) -> rr.SeriesPoint: + return rr.SeriesPoint( + color=0xFF0000FF, + name=f"{symbol} (peak)", + marker="Up", + ) + + +def info_card( + shortName: str, + industry: str, + marketCap: int, + totalRevenue: int, + **args: dict[str, Any], +) -> rr.TextDocument: + markdown = f""" +- **Name**: {shortName} +- **Industry**: {industry} +- **Market cap**: ${humanize.intword(marketCap)} +- **Total Revenue**: ${humanize.intword(totalRevenue)} +""" + + return rr.TextDocument(markdown, media_type=rr.MediaType.MARKDOWN) +``` + +And finally, we create our main function that queries and logs the data: + +```python +def main() -> None: + symbols = ["AAPL", "AMZN", "GOOGL", "META", "MSFT"] + + # Use eastern time for market hours + et_timezone = pytz.timezone("America/New_York") + start_date = dt.date(2024, 3, 18) + dates = [start_date + dt.timedelta(days=i) for i in range(5)] + + # Initialize Rerun and spawn a new viewer + rr.init("rerun_example_blueprint_stocks", spawn=True) + + # This is where we will edit the blueprint + blueprint = None + #rr.send_blueprint(blueprint) + + # Log the stock data for each symbol and date + for symbol in symbols: + stock = yf.Ticker(symbol) + + # Log the stock info document as timeless + rr.log(f"stocks/{symbol}/info", info_card(**stock.info), timeless=True) + + for day in dates: + # Log the styling data as timeless + rr.log(f"stocks/{symbol}/{day}", style_plot(symbol), timeless=True) + rr.log(f"stocks/{symbol}/peaks/{day}", style_peak(symbol), timeless=True) + + # Query the stock data during market hours + open_time = dt.datetime.combine(day, dt.time(9, 30), et_timezone) + close_time = dt.datetime.combine(day, dt.time(16, 00), et_timezone) + + hist = stock.history(start=open_time, end=close_time, interval="5m") + + # Offset the index to be in seconds since the market open + hist.index = hist.index - open_time + peak = hist.High.idxmax() + + # Log the stock state over the course of the day + for row in hist.itertuples(): + rr.set_time_seconds("time", row.Index.total_seconds()) + rr.log(f"stocks/{symbol}/{day}", rr.Scalar(row.High)) + if row.Index == peak: + rr.log(f"stocks/{symbol}/peaks/{day}", rr.Scalar(row.High)) + + +if __name__ == "__main__": + main() +``` + +## Run your script + +You can now run the script and view the results in the Rerun Viewer: + +```bash +python stocks.py +``` + +You should see the application launch and display the stock data, but you will also notice the +layout is far from ideal: + + + + + + + + + +## Create a Blueprint + +To improve the layout, we will now use the blueprint APIs to create some custom layouts. + +All we need to do is modify the section of the code that currently reads: + +```python + # This is where we will edit the blueprint + blueprint = None + #rr.send_blueprint(blueprint) +``` + +### Create a view for an origin + +Replace these lines with the following: + +```python + # Create a single chart for all the AAPL data: + blueprint = rrb.Blueprint( + rrb.TimeSeriesView(name="AAPL", origin="/stocks/AAPL"), + ) + rr.send_blueprint(blueprint) +``` + +This blueprint uses the `origin` parameter to scope the view to just a portion of the entity tree. + +If you run the script again, you should see a single chart for the AAPL data: + + + + + + + + + +### Control the default panel state + +In addition to controlling the data, you can also control the default state of the blueprint, selection, +and time panels. + +Let's modify the code again to include additional blueprint specifications for these: + +```python + # Create a single chart for all the AAPL data, and collapse the selection and time panels: + blueprint = rrb.Blueprint( + rrb.TimeSeriesView(name="AAPL", origin="/stocks/AAPL"), + rrb.BlueprintPanel(expanded=True), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False), + ) + rr.send_blueprint(blueprint) +``` + +This time when you run the script, you will now see the panels start off collapsed, giving you a +more focused view of your data: + + + + + + + + + +### Combining multiple views + +When using blueprints, you don't have to limit yourself to a single view. You can create multiple views +and use containers to combine them. + +Let's modify the code to include the info card as well. We will use the `Vertical` container and the +`row_shares` parameter to control the relative size of the views: + +```python + # Create a vertical layout of an info document and a time series chart + blueprint = rrb.Blueprint( + rrb.Vertical( + rrb.TextDocumentView(name="Info", origin="/stocks/AAPL/info"), + rrb.TimeSeriesView(name="Chart", origin="/stocks/AAPL"), + row_shares=[1, 4], + ), + rrb.BlueprintPanel(expanded=True), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False), + ) + rr.send_blueprint(blueprint) +``` + +Running the script now produces two views stacked vertically: + + + + + + + + + +### Including specific contents + +Specifying the `origin` of a view is convenient, but sometimes you need more control. In this case, you can +specify the `contents` of a view by providing multiple content expressions. + +For example, we can create a stock that includes data from both META and MSFT for a single day on +the same chart. Using `origin` alone there is no way we could have expressed this: + +```python + # Create a view with two stock time series + blueprint = rrb.Blueprint( + rrb.TimeSeriesView( + name="META vs MSFT", + contents=[ + "+ /stocks/META/2024-03-19", + "+ /stocks/MSFT/2024-03-19", + ], + ), + rrb.BlueprintPanel(expanded=True), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False), + ) + rr.send_blueprint(blueprint) +``` + +Running the script now produces a chart that combines data from multiple sources: + + + + + + + + + +### More complex filtering + +Just specifying single path inclusions can also be challenging when dealing datasets that +include large subtrees. + +Filter expressions can be used to include or exclude data based on a path pattern. This pattern can optionally +start with `$origin` to refer to the origin of the given space, and can end with the wildcard `/**` to include +or exclude an entire subtree, + +Going back to our single stock example, we can filter out the peaks data by excluding the `peaks` subtree: + +```python + # Create a single chart for all the AAPL data and filter out the peaks: + blueprint = rrb.Blueprint( + rrb.TimeSeriesView( + name="AAPL", + origin="/stocks/AAPL", + contents=[ + "+ $origin/**", + "- $origin/peaks/**", + ], + ), + rrb.BlueprintPanel(expanded=True), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False), + ) + rr.send_blueprint(blueprint) +``` + +When you run the script you will see that the data from the peaks subtree is no longer part of the view: + + + + + + + + + +### Programmatic layouts + +Since these layouts are created by executing python code, they can also be generated programmatically. + +For example, we can create a create a separate view for every piece of data we were interested in. +Setting this up by hand would be extremely tedious. + +```python + # Iterate over all the symbols and days to log the stock data in a grid + blueprint = rrb.Blueprint( + rrb.Vertical( + contents=[ + rrb.Horizontal( + contents=[ + rrb.TextDocumentView( + name=f"{symbol}", + origin=f"/stocks/{symbol}/info", + ), + ] + + [ + rrb.TimeSeriesView( + name=f"{day}", + origin=f"/stocks/{symbol}/{day}", + ) + for day in dates + ], + name=symbol, + ) + for symbol in symbols + ] + ), + rrb.BlueprintPanel(expanded=True), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False), + ) + rr.send_blueprint(blueprint) +``` + +Running the script again this final chart is a significant improvement over the original heuristic-based layout: + + + + + + + + diff --git a/docs/content/howto/configure-the-viewer/interactively.md b/docs/content/howto/configure-the-viewer/interactively.md new file mode 100644 index 000000000000..5f7d885ace81 --- /dev/null +++ b/docs/content/howto/configure-the-viewer/interactively.md @@ -0,0 +1,85 @@ +--- +title: Interactively setup up viewer +order: 1 +--- + +The Rerun Viewer is configurable directly through the UI itself. + +## Viewer overview + +TODO(#5636): Screenshot of the viewer, with the blueprint and selection panels highlighted. + +The left panel of the viewer is the "Blueprint Panel" this shows a visual tree view representing +the contents of the current blueprint. + +The right panel of the viewer is the "Selection Panel" this panel allows you to configure +specific blueprint properties of the currently selected element. + +After editing the viewer you may want to [save or share the blueprint](./save-and-load.md). + +## Configuring Layout and Contents + +### Show or hide parts of the blueprint + +Click the "eye" icon next to the container, view, or entity in the blueprint panel. +TODO(#5636): show_hide + +### Add new Containers or Views + +Clicking the "+" at the top of the blueprint panel. +TODO(#5636): add_1 + +Selecting a Container and clicking the "+" in the selection panel. +TODO(#5636): add_2 + +### Remove a View or Container + +Click the "-" button next to the container or view in the blueprint panel. +TODO(#5636): remove + +### Re-arrange existing Containers or Views + +Drag and drop the container or view in the blueprint panel. +TODO(#5636): drag_1 + +Drag and drop containers or views directly in the viewport +TODO(#5636): drag_2 + +### Change the size of Containers or Views + +Click and drag the edge of a view or container to resize it +TODO(#5636): resize + +### Rename a View or Container + +Select the Container or View and enter a name at the top of the selection panel +TODO(#5636): rename + +### Change the type of a Container + +Select the Container and choose a new type from the dropdown in the selection panel +TODO(#5636): change_type + +### Add a new Data to a View + +Select the view and click "edit" to bring up the entity editor +TODO(#5636): add_data_1 + +Select the view and directly edit the entity query +See [Entity Queries](../../reference/entity-queries.md) for more information on how to write queries. + +TODO(#5636): add_data_2 + +### Remove Data from a View + +Click the "-" next to the entity in the blueprint panel +TODO(#5636): remove_data_1 + +### Change the origin of a View + +Select the view, then click the "Space Origin" field and type or select a new origin +TODO(#5636): change_origin + +## Overriding Properties + +TODO(jleibs): do we include this now or wait for generalized component overrides? diff --git a/docs/content/howto/configure-the-viewer/save-and-load.md b/docs/content/howto/configure-the-viewer/save-and-load.md new file mode 100644 index 000000000000..ab8aa010b1a5 --- /dev/null +++ b/docs/content/howto/configure-the-viewer/save-and-load.md @@ -0,0 +1,24 @@ +--- +title: Save and load viewer configuration files +order: 1 +--- + +If you have made changes to your blueprint and you would like to save or share these changes, +you can do so by saving your blueprint to an `.rbl` file. + +## Saving a blueprint + +To save your blueprint, go to the file-menu and choose "Save blueprint…" +TODO(#5636): save + +## Loading a blueprint + +Once you have saved a blueprint, you can load it again. + +When loading a blueprint, it must match the "application_id" used by the recording. + +To load a blueprint, go to the file-menu and choose "Open…" and select the `.rbl` file you would like to load. +TODO(#5636): open_1 + +You can also drag and drop an `.rbl` file directly into the viewer +TODO(#5636): open_2 diff --git a/docs/content/howto/configure-the-viewer/through-code.md b/docs/content/howto/configure-the-viewer/through-code.md new file mode 100644 index 000000000000..76339ced0db4 --- /dev/null +++ b/docs/content/howto/configure-the-viewer/through-code.md @@ -0,0 +1,290 @@ +--- +title: Control the viewer through code +order: 2 +--- + +As of Rerun 0.15, the state of the [blueprint](../../reference/viewer/blueprint.md) can be directly manipulated using the +Rerun SDK. + +In the initial 0.15 release, the APIs are still somewhat limited and only available in the Python SDK. +Future releases will add support for the full scope of blueprint. See issues: [#5519](https://github.com/rerun-io/rerun/issues/5519), [#5520](https://github.com/rerun-io/rerun/issues/5520), [#5521](https://github.com/rerun-io/rerun/issues/5521). + +## Blueprint API overview + +All blueprint APIs are in the [`rerun.blueprint`](https://ref.rerun.io/docs/python/stable/common/blueprint_apis/?speculative-link) namespace. In our python examples, we typically import this using the `rrb` alias: + +```python +import rerun.blueprint as rrb +``` + +The python blueprint API is declarative and object-centric. There are 3 main types of blueprint objects you will +encounter: + +- `Blueprint`: The root object that represents the entire viewer layout. +- `Container`: A layout object that contains other containers or views. +- `SpaceView`: A view object that represents a single view of the data. + +Both containers and spaceviews should be used via typed subclasses instead.: + +- `Container` has subclasses: `Horizontal`, `Vertical`, `Grid`, and `Tabs`. +- `SpaceView` has subclasses: `BarChartView`, `Spatial2DView`, `Spatial3DView`, `TensorView`, + `TextDocumentView`, `TextLogView`, and `TimeSeriesView`. + +These paths can be combined hierarchically to create a complex viewer layout. + +For example: + +```python +my_blueprint = rrb.Blueprint( + rrb.Horizontal( + rrb.SpaceView(rrb.BarChartView()), + rrb.Vertical( + rrb.SpaceView(rrb.Spatial2DView()), + rrb.SpaceView(rrb.Spatial3DView()), + ), + ), +) +``` + +## Sending the blueprint to the viewer + +To provide a blueprint, simply pass it to either `init` or `connect` using the `default_blueprint` +parameter. + +Using `init` with `spawn=True`: + +```python +my_blueprint = rrb.Blueprint(...) + +rr.init("rerun_example_my_blueprint", spawn=True, default_blueprint=my_blueprint) +``` + +Or if you use `connect` separate from `init`: + +```python +my_blueprint = rrb.Blueprint(...) + +rr.init("rerun_example_my_blueprint") + +... + +rr.connect(default_blueprint=my_blueprint) +``` + +## Activating the default blueprint + +Just like the viewer can store many different recordings internally, it can also +store many different blueprints. For each `application_id` in the viewer, are two +particularly important blueprints: the "default blueprint" and the "active blueprint". + +When a recording is selected, the active blueprint for the corresponding +`application_id` will completely determine what is displayed by the viewer. + +When you send a blueprint to the viewer, it will not necessarily be +activated immediately. The standard behavior is to only update the "default +blueprint" in the viewer. This minimizes the chance that you accidentally +overwrite blueprint edits you may have made locally. + +If you want to start using the new blueprint, after sending it, you will need to +click the reset button in the blueprint panel. This resets the active blueprint to the +current default: + +TODO(#5636): reset_blueprint + +## Always activating the blueprint + +If you want to always activate the blueprint as soon as it is received, you can instead use the `send_blueprint` +API. This API has two flags `make_active` and `make_default`, both of which default to `True`. + +If `make_active` is set, the blueprint will be activated immediately. Exercise care in using this API, as it can be +surprising for users to have their blueprint changed without warning. + +```python +my_blueprint = rrb.Blueprint(...) + +rr.init("rerun_example_my_blueprint", spawn=True) + +rr.send_blueprint(my_blueprint, make_active=True) + +``` + +## Customizing Space Views + +Any of the space views (`BarChartView`, `Spatial2DView`, `Spatial3DView`, `TensorView`, +`TextDocumentView`, `TextLogView`, or `TimeSeriesView`) can be instantiated with no arguments. +By default these views try to include all compatible entities. + +For example, the following blueprint creates a single 3D view that includes all the 3D content +you have logged to the entity tree: + +```python +rrb.Blueprint( + rrb.Spatial3DView() +) +``` + +Beyond, instantiating the space views, there are 3 parameters you may want to specify: `name`, `origin`, and `contents`. + +`name` is simply the name of the view used as a label in the viewer. + +However, both `origin` and `contents` play an important role in determining what data is included in the view. + +### `origin` + +The `origin` of a space-view is a generalized "frame of reference" for the view. We think of showing all data +in the space view as relative to the `origin`. + +By default, only data that is under the `origin` will be included in the view. As such this is one of the most +convenient ways of restricting a space-view to a particular subtree. + +Because the data in the space-view is relative to the `origin`, the `origin` will be the first entity displayed +in the blueprint tree, with all entities under the origin shown using relative paths. + +For Spatial views such as `Spatial2DView` and `Spatial3DView`, the `origin` plays an additional role with respect +to data transforms. All data in the view will be transformed to the `origin` space before being displayed. See [Spaces and Transforms](../../concepts/spaces-and-transforms.md) for more information. +TODO(jleibs): Re-review spaces-and-transforms for correctness + +For example: + +```python +rrb.Blueprint( + rrb.Horizontal( + rrb.Spatial3DView(origin="/world"), + rrb.Spatial2DView(origin="/world/robot/camera"), + ) +) +``` + +### `contents` + +If you need to further modify the contents of a space view, you can use the `contents` parameter. This parameter is +a list of [entity query expressions](../../reference/) that are either included or excluded from the +view. + +Each entity expressions starts with "+" for inclusion or "-" for an exclusion. The expressions can either be specific entity paths, or may end in a wildcard `/**` to include all entities under a specific subtree. + +When combining multiple expressions, the "most specific" rule wins. + +Additionally, these expressions can reference `$origin` to refer to the origin of the space view. + +For example: + +```python +rrb.Blueprint( + rrb.Horizontal( + rrb.Spatial3DView( + origin="/world", + contents=[ + "+ $origin/robot/**", + ], + ), + rrb.Spatial2DView( + origin="/world/robot/camera", + contents=[ + "+ $origin/**", + "+ /world/robot/actuator/**", + ], + ), + ) +) +``` + +## Implicit conversion + +For convenience all of the blueprint APIs take a `BlueprintLike` rather than requiring a `Blueprint` object. +Both `SpaceView`s and `Containers` are considered `BlueprintLike`. Similarly, the `Blueprint` object can +take a `SpaceView` or `Container` as an argument. + +All of the following are equivalent: + +```python +rr.send_blueprint(rrb.Spatial3DView()) +``` + +```python +rr.send_blueprint( + rrb.Grid( + Spatial3DView(), + ) +) +``` + +```python +rr.send_blueprint( + rrb.Blueprint( + Spatial3DView(), + ), +) + +``` + +```python +rr.send_blueprint( + rrb.Blueprint( + rrb.Grid( + Spatial3DView(), + ) + ), +) +``` + +## Customizing the top-level blueprint + +The top-level `Blueprint` object can also be customized. + +### Controlling the panel state + +The `Blueprint` controls the default panel-state of the 3 panels: the `BlueprintPanel`, the `SelectionPanel`, and the `TimePanel`. These can be controlled by passing them as additional arguments to the `Blueprint` constructor. + +```python +rrb.Blueprint( + rrb.TimePanel(expanded=False) +) +``` + +As an convenience, you can also use the blueprint argument: `collapse_panels=True` as a short-hand for: + +```python +rrb.Blueprint( + rrb.TimePanel(expanded=False), + rrb.SelectionPanel(expanded=False), + rrb.BlueprintPanel(expanded=False), +) +``` + +### Controlling the auto behaviors + +The blueprint has two additional parameters that influence the behavior of the viewer: + +- `auto_space_views` controls whether the viewer will automatically create space views for entities that are not explicitly included in the blueprint. +- `auto_layout` controls whether the viewer should automatically layout the containers when introducing new space-views. + +If you pass in your own `SpaceView` or `Container` objects, these will both default to `False` so that the Blueprint +you get is exactly what you specify. Otherwise they will default to `True` so that you will still get content (this +matches the default behavior of the viewer if no blueprint is provided). + +This means that: + +```python +rrb.Blueprint() +``` + +and + +```python +rrb.Blueprint( + auto_space_views=True, + auto_layout=True +) +``` + +are both equivalent to the viewer's default behavior. + +If you truly want to create an empty blueprint, you must set both values to `False`: + +```python +rrb.Blueprint( + auto_space_views=False, + auto_layout=False +), +``` diff --git a/docs/content/reference/entity-queries.md b/docs/content/reference/entity-queries.md new file mode 100644 index 000000000000..9f9300144321 --- /dev/null +++ b/docs/content/reference/entity-queries.md @@ -0,0 +1,92 @@ +--- +title: Entity Queries +order: 4 +--- + +Many space views are made up of visualizations that include more than one +entity. + +Rather that requiring you to specify each entity individually, Rerun supports +this through "entity queries" that allow you to use "query expressions" to +include or exclude entire subtrees. + +## Query expression syntax + +An entity query is made up of a set of "query expressions." Each query expression +is either an "inclusion," which starts with an optional `+` or an "exclusion," +which always starts with a `-`. + +Query expressions are also allowed to end with an optional `/**`. The`/**` +suffix matches the whole subtree, i.e. self and any child, recursively. For +example, `/world/**`matches both`/world`and`/world/car/driver`. Other uses of +`*` are not yet supported. + +When combining multiple query expressions, the rules are sorted by entity-path, +from least to most specific: + +- If there are multiple matching rules, the most specific rule wins. +- If there are multiple rules of the same specificity, the last one wins. +- If no rules match, the path is excluded. + +Consider the following example: + +```diff ++ /world/** +- /world +- /world/car/** ++ /world/car/driver +``` + +- The last rule matching `/world/car/driver` is `+ /world/car/driver`, so it + is included. +- The last rule matching `/world/car/hood` is `- /world/car/**`, so it is + excluded. +- The last rule matching `/world` is `- /world`, so it is excluded. +- The last rule matching `/world/house` is `+ /world/**`, so it is included. + +## In the viewer + +In the viewer, an entity query is typically displayed as a multi-line +edit box, with each query expression shown on its own line. You can find the +query editor in the right-hand selection panel when selecting a space view. + + + + + + + + + + +## In the SDK + +In the SDK, query expressions are represented as a list or iterable, with each +expression written as a separate string. The query expression from above would +be written as: + +```python +rrb.Spatial3DView( + contents=[ + "+ helix/**, + "- helix/structure/scaffolding", + ], +), +``` + +## 'origin` substitution + +Query expressions also allow you to use the variable `$origin` to refer to the +origin of the space-view that the query belongs to. + +For example, the above query could be rewritten as: + +```python +rrb.Spatial3DView( + origin="helix", + contents=[ + "+ $origin/**, + "- $origin/structure/scaffolding", + ], +), +``` diff --git a/docs/content/reference/types.md b/docs/content/reference/types.md index ea9fd7fa17a1..c5711e2bf5e6 100644 --- a/docs/content/reference/types.md +++ b/docs/content/reference/types.md @@ -1,6 +1,6 @@ --- title: Types -order: 2 +order: 3 --- Rerun comes with built-in support for a number of different types that can be logged via the Python and Rust Logging diff --git a/docs/content/reference/viewer.md b/docs/content/reference/viewer.md index 00414c7f2739..379792ff12b4 100644 --- a/docs/content/reference/viewer.md +++ b/docs/content/reference/viewer.md @@ -1,5 +1,5 @@ --- title: Viewer -order: 1 +order: 2 redirect: reference/viewer/overview --- diff --git a/docs/cspell.json b/docs/cspell.json index ca7ba3b7552d..b9a42adfc4d6 100644 --- a/docs/cspell.json +++ b/docs/cspell.json @@ -148,14 +148,17 @@ "hstack", "Huggingface", "icosphere", + "idxmax", "imgmsg", "impls", "inproceedings", "interner", "intrinsics", + "intword", "ipynb", "ipython", "itertools", + "itertuples", "Jitendra", "jleibs", "Joao", @@ -271,6 +274,7 @@ "pypi", "pyright", "pytest", + "pytz", "Pythonic", "quickstart", "randn", @@ -346,6 +350,7 @@ "Texcoord", "thiserror", "Tian", + "timedelta", "timepanel", "timepoint", "timepoints", @@ -408,6 +413,7 @@ "XYWH", "XYXY", "xyzw", + "yfinance", "Yifan", "Yilun", "Yiqin", diff --git a/rerun_py/rerun_sdk/rerun/datatypes/tensor_data_ext.py b/rerun_py/rerun_sdk/rerun/datatypes/tensor_data_ext.py index 859904151c02..43b717d2231c 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/tensor_data_ext.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/tensor_data_ext.py @@ -68,7 +68,7 @@ def __init__( self: TensorData The TensorData object to construct. shape: Sequence[TensorDimensionLike] | None - The shape of the tensor. If None, and an array is proviced, the shape will be inferred + The shape of the tensor. If None, and an array is provided, the shape will be inferred from the shape of the array. buffer: TensorBufferLike | None The buffer of the tensor. If None, and an array is provided, the buffer will be generated