From 776aa4f2024e83bd0778ae5d07a1d220dd458e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Thu, 12 Dec 2024 12:58:57 +0100 Subject: [PATCH] Create a more convincing example of the graph view (#8421) ### What This PR tries to create a more convincing example for the graph view. It consists of 4 views: * A tree that randomly grows over time * A bubble chart with new bubbles coming in over time * The lattice, which is logged statically but without positions * And finally a Markov-Chain with fixed positions There are still some minor things to fix: * [x] That one weird edge in the Markov-Chain * [x] It would be nice if the viewer would fit the resulting graphs to the view. image --------- Co-authored-by: Clement Rey --- Cargo.lock | 9 - .../re_view_graph/src/layout/provider.rs | 2 +- crates/viewer/re_view_graph/src/view.rs | 3 +- examples/manifest.toml | 5 +- examples/python/graph_binary_tree/README.md | 28 --- .../graph_binary_tree/graph_binary_tree.py | 108 --------- examples/python/graph_lattice/README.md | 8 +- examples/python/graphs/README.md | 29 +++ examples/python/graphs/graphs.py | 205 ++++++++++++++++++ .../pyproject.toml | 4 +- examples/rust/graph_binary_tree/Cargo.toml | 13 -- examples/rust/graph_binary_tree/README.md | 3 - examples/rust/graph_binary_tree/src/main.rs | 155 ------------- pixi.lock | 44 ++-- pixi.toml | 2 +- .../check_graph_time_layout.py | 111 ---------- 16 files changed, 268 insertions(+), 461 deletions(-) delete mode 100644 examples/python/graph_binary_tree/README.md delete mode 100644 examples/python/graph_binary_tree/graph_binary_tree.py create mode 100644 examples/python/graphs/README.md create mode 100644 examples/python/graphs/graphs.py rename examples/python/{graph_binary_tree => graphs}/pyproject.toml (70%) delete mode 100644 examples/rust/graph_binary_tree/Cargo.toml delete mode 100644 examples/rust/graph_binary_tree/README.md delete mode 100644 examples/rust/graph_binary_tree/src/main.rs delete mode 100644 tests/python/release_checklist/check_graph_time_layout.py diff --git a/Cargo.lock b/Cargo.lock index bd21dfd45a73..98a0e10c66c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2915,15 +2915,6 @@ dependencies = [ "bitflags 2.6.0", ] -[[package]] -name = "graph_binary_tree" -version = "0.21.0-alpha.1+dev" -dependencies = [ - "anyhow", - "clap", - "rerun", -] - [[package]] name = "graph_lattice" version = "0.21.0-alpha.1+dev" diff --git a/crates/viewer/re_view_graph/src/layout/provider.rs b/crates/viewer/re_view_graph/src/layout/provider.rs index 6f84d1ff3f67..b49f3f6669a0 100644 --- a/crates/viewer/re_view_graph/src/layout/provider.rs +++ b/crates/viewer/re_view_graph/src/layout/provider.rs @@ -236,7 +236,7 @@ impl ForceLayoutProvider { let c1_base = source_pos + delta * 0.25; let c2_base = source_pos + delta * 0.75; - let base_n = Vec2::new(-c1_base.y, c1_base.x).normalized(); + let base_n = Vec2::new(-delta.y, delta.x).normalized(); let c1_left = c1_base + base_n * (fan_amount / 2.); let c2_left = c2_base + base_n * (fan_amount / 2.); diff --git a/crates/viewer/re_view_graph/src/view.rs b/crates/viewer/re_view_graph/src/view.rs index eaf2068663ee..8948a343c423 100644 --- a/crates/viewer/re_view_graph/src/view.rs +++ b/crates/viewer/re_view_graph/src/view.rs @@ -180,7 +180,6 @@ Display a graph of nodes and edges. // Perform all layout-related tasks. let request = LayoutRequest::from_graphs(graphs.iter()); - let layout_was_empty = state.layout_state.is_none(); let layout = state.layout_state.get(request, params); // Prepare the view and the transformations. @@ -216,7 +215,7 @@ Display a graph of nodes and edges. // Update blueprint if changed let updated_rect_in_scene = blueprint::components::VisualBounds2D::from(ui_from_world.inverse() * rect_in_ui); - if resp.double_clicked() || layout_was_empty { + if resp.double_clicked() { bounds_property.reset_blueprint_component::(ctx); state.ui_from_world = None; } else if rect_in_scene != updated_rect_in_scene { diff --git a/examples/manifest.toml b/examples/manifest.toml index 915fc0509dcf..b229b765acd5 100644 --- a/examples/manifest.toml +++ b/examples/manifest.toml @@ -142,6 +142,7 @@ examples = [ "notebook", "clock", "dna", + "graphs", "log_file", "openstreetmap_data", "minimal", @@ -150,8 +151,6 @@ examples = [ "plots", "live_scrolling_plot", "raw_mesh", - "graph_lattice", - "graph_binary_tree", "air_traffic_data", ] @@ -169,6 +168,8 @@ examples = [ "drone_lidar", "extend_viewer_ui", "external_data_loader", + "graph_binary_tree", + "graph_lattice", "incremental_logging", "minimal_serve", "shared_recording", diff --git a/examples/python/graph_binary_tree/README.md b/examples/python/graph_binary_tree/README.md deleted file mode 100644 index 1165823aa39f..000000000000 --- a/examples/python/graph_binary_tree/README.md +++ /dev/null @@ -1,28 +0,0 @@ - - -This example shows a binary tree that uses `GraphNodes` and `GraphEdges` together with fixed node positions. - - - - - - - - - -## Used Rerun types -[`GraphNodes`](https://www.rerun.io/docs/reference/types/archetypes/graph_nodes?speculative-link), -[`GraphEdges`](https://www.rerun.io/docs/reference/types/archetypes/graph_edges?speculative-link) - -## Run the code - -```bash -pip install -e examples/python/graph_binary_tree -python -m graph_binary_tree -``` diff --git a/examples/python/graph_binary_tree/graph_binary_tree.py b/examples/python/graph_binary_tree/graph_binary_tree.py deleted file mode 100644 index 96f9a2c869a1..000000000000 --- a/examples/python/graph_binary_tree/graph_binary_tree.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python3 -"""Examples of logging graph data to Rerun.""" - -from __future__ import annotations - -import argparse - -import rerun as rr - -DESCRIPTION = """ -# Binary tree -This is a minimal example that logs a time-varying binary tree to Rerun. - -The full source code for this example is available -[on GitHub](https://github.com/rerun-io/rerun/blob/latest/examples/python/graph_binary_tree?speculative-link). -""".strip() - -s = 3 # scaling factor for the positions - -# Potentially unbalanced and not sorted binary tree. :nerd_face:. -# :warning: The nodes have to be unique, which is why we use `5_0`… - -NodeId = str - - -class NodeInfo: - def __init__(self, label: str, pos: tuple[float, float]) -> None: - self.label = label - self.pos = pos - - -all_nodes: dict[NodeId, NodeInfo] = { - "1": NodeInfo(label="1", pos=(0 * s, 0 * s)), - "7": NodeInfo(label="7", pos=(-20 * s, 30 * s)), - "2": NodeInfo(label="2", pos=(-30 * s, 60 * s)), - "6": NodeInfo(label="6", pos=(-10 * s, 60 * s)), - "5_0": NodeInfo(label="5", pos=(-20 * s, 90 * s)), - "11": NodeInfo(label="11", pos=(0 * s, 90 * s)), - "9_0": NodeInfo(label="9", pos=(20 * s, 30 * s)), - "9_1": NodeInfo(label="9", pos=(30 * s, 60 * s)), - "5_1": NodeInfo(label="5", pos=(20 * s, 90 * s)), -} - - -class Level: - def __init__(self, nodes: list[NodeId], edges: list[tuple[NodeId, NodeId]]): - self.nodes = nodes - self.edges = edges - - -levels: list[Level] = [ - Level(nodes=["1"], edges=[]), - Level(nodes=["1", "7", "9_0"], edges=[("1", "7"), ("1", "9_0")]), - Level( - nodes=["1", "7", "9_0", "2", "6", "9_1"], - edges=[("1", "7"), ("1", "9_0"), ("7", "2"), ("7", "6"), ("9_0", "9_1")], - ), - Level( - nodes=["1", "7", "9_0", "2", "6", "9_1", "5_0", "11", "5_1"], - edges=[ - ("1", "7"), - ("1", "9_0"), - ("7", "2"), - ("7", "6"), - ("9_0", "9_1"), - ("6", "5_0"), - ("6", "11"), - ("9_1", "5_1"), - ], - ), -] - - -def log_data() -> None: - rr.log("description", rr.TextDocument(DESCRIPTION, media_type=rr.MediaType.MARKDOWN), static=True) - - t = 0 - for level in levels: - if len(level.nodes) > 0: - t = t + 1 - rr.set_time_seconds("stable_time", t) - rr.log( - "binary_tree", - rr.GraphNodes( - level.nodes, - labels=list(map(lambda n: all_nodes[n].label, level.nodes)), - positions=list(map(lambda n: all_nodes[n].pos, level.nodes)), - ), - ) - - if len(level.edges) > 0: - t = t + 1 - rr.set_time_seconds("stable_time", t) - rr.log("binary_tree", rr.GraphEdges(level.edges)) - - -def main() -> None: - parser = argparse.ArgumentParser(description="Logs a binary tree with associated positions using the Rerun SDK.") - rr.script_add_args(parser) - args = parser.parse_args() - - rr.script_setup(args, "rerun_example_graph_binary_tree") - log_data() - rr.script_teardown(args) - - -if __name__ == "__main__": - main() diff --git a/examples/python/graph_lattice/README.md b/examples/python/graph_lattice/README.md index ed764409c37c..8ffe2530634f 100644 --- a/examples/python/graph_lattice/README.md +++ b/examples/python/graph_lattice/README.md @@ -23,7 +23,7 @@ Since no explicit positions are passed for the nodes, Rerun will layout the grap ## Run the code -```bash -pip install -e examples/python/graph_lattice -python -m graph_lattice -``` + ```bash + pip install -e examples/python/graph_lattice + python -m graph_lattice + ``` diff --git a/examples/python/graphs/README.md b/examples/python/graphs/README.md new file mode 100644 index 000000000000..245143a18cc0 --- /dev/null +++ b/examples/python/graphs/README.md @@ -0,0 +1,29 @@ + + +This example shows different attributes that you can associate with nodes in a graph. +Since no explicit positions are passed for the nodes, Rerun will layout the graph automatically. + + + + + + + + + +## Used Rerun types +[`GraphNodes`](https://www.rerun.io/docs/reference/types/archetypes/graph_nodes?speculative-link), +[`GraphEdges`](https://www.rerun.io/docs/reference/types/archetypes/graph_edges?speculative-link) + +## Run the code + +```bash +pip install -e examples/python/graphs +python -m graphs +``` diff --git a/examples/python/graphs/graphs.py b/examples/python/graphs/graphs.py new file mode 100644 index 000000000000..3bf490c625d9 --- /dev/null +++ b/examples/python/graphs/graphs.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python3 +"""Examples of logging graph data to Rerun and performing force-based layouts.""" + +from __future__ import annotations + +import argparse +import itertools +import random + +import numpy as np +import rerun as rr +import rerun.blueprint as rrb +from rerun.blueprint.archetypes.force_collision_radius import ForceCollisionRadius +from rerun.blueprint.archetypes.force_link import ForceLink +from rerun.blueprint.archetypes.force_many_body import ForceManyBody +from rerun.components.color import Color +from rerun.components.radius import Radius +from rerun.components.show_labels import ShowLabels + +color_scheme = [ + Color([228, 26, 28]), # Red + Color([55, 126, 184]), # Blue + Color([77, 175, 74]), # Green + Color([152, 78, 163]), # Purple + Color([255, 127, 0]), # Orange + Color([255, 255, 51]), # Yellow + Color([166, 86, 40]), # Brown + Color([247, 129, 191]), # Pink + Color([153, 153, 153]), # Gray +] + +DESCRIPTION = """ +# Graphs +This example shows various graph visualizations that you can create using Rerun. +In this example, the node positions—and therefore the graph layout—are computed by Rerun internally using a force-based layout algorithm. + +You can modify how these graphs look by changing the parameters of the force-based layout algorithm in the selection panel. + +The full source code for this example is available +[on GitHub](https://github.com/rerun-io/rerun/blob/latest/examples/python/graphs?speculative-link). +""".strip() + + +# We want reproducible results +random.seed(42) + + +def log_lattice(num_nodes: int) -> None: + coordinates = itertools.product(range(num_nodes), range(num_nodes)) + + nodes, colors = zip(*[ + ( + str(i), + rr.components.Color([round((x / (num_nodes - 1)) * 255), round((y / (num_nodes - 1)) * 255), 0]), + ) + for i, (x, y) in enumerate(coordinates) + ]) + + rr.log( + "lattice", + rr.GraphNodes( + nodes, + colors=colors, + labels=[f"({x}, {y})" for x, y in itertools.product(range(num_nodes), range(num_nodes))], + ), + static=True, + ) + + edges = [] + for x, y in itertools.product(range(num_nodes), range(num_nodes)): + if y > 0: + source = (y - 1) * num_nodes + x + target = y * num_nodes + x + edges.append((str(source), str(target))) + if x > 0: + source = y * num_nodes + (x - 1) + target = y * num_nodes + x + edges.append((str(source), str(target))) + + rr.log("lattice", rr.GraphEdges(edges, graph_type="directed"), static=True) + + +def log_trees() -> None: + nodes = ["root"] + radii = [42] + colors = [Color([81, 81, 81])] + edges = [] + + # Randomly add nodes and edges to the graph + for i in range(50): + existing = random.choice(nodes) + new_node = str(i) + nodes.append(new_node) + radii.append(random.randint(10, 50)) + colors.append(random.choice(color_scheme)) + edges.append((existing, new_node)) + + rr.set_time_sequence("frame", i) + rr.log( + "node_link", + rr.GraphNodes(nodes, labels=nodes, radii=radii, colors=colors), + rr.GraphEdges(edges, graph_type=rr.GraphType.Directed), + ) + rr.log( + "bubble_chart", + rr.GraphNodes(nodes, labels=nodes, radii=radii, colors=colors), + ) + + +def log_markov_chain() -> None: + transition_matrix = np.array([ + [0.8, 0.1, 0.1], # Transitions from sunny + [0.3, 0.4, 0.3], # Transitions from rainy + [0.2, 0.3, 0.5], # Transitions from cloudy + ]) + state_names = ["sunny", "rainy", "cloudy"] + # For this example, we use hardcoded positions. + positions = [[0, 0], [150, 150], [300, 0]] + inactive_color = Color([153, 153, 153]) # Gray + active_colors = [ + Color([255, 127, 0]), # Orange + Color([55, 126, 184]), # Blue + Color([152, 78, 163]), # Purple + ] + + edges = [ + (state_names[i], state_names[j]) + for i in range(len(state_names)) + for j in range(len(state_names)) + if transition_matrix[i][j] > 0 + ] + edges.append(("start", "sunny")) + + # We start in state "sunny" + state = "sunny" + + for i in range(50): + current_state_index = state_names.index(state) + next_state_index = np.random.choice(range(len(state_names)), p=transition_matrix[current_state_index]) + state = state_names[next_state_index] + colors = [inactive_color] * len(state_names) + colors[next_state_index] = active_colors[next_state_index] + + rr.set_time_sequence("frame", i) + rr.log( + "markov_chain", + rr.GraphNodes(state_names, labels=state_names, colors=colors, positions=positions), + rr.GraphEdges(edges, graph_type="directed"), + ) + + +def log_blueprint() -> None: + rr.send_blueprint( + rrb.Blueprint( + rrb.Grid( + rrb.GraphView( + origin="node_link", + name="Node-link diagram", + force_link=ForceLink(distance=60), + force_many_body=ForceManyBody(strength=-60), + ), + rrb.GraphView( + origin="bubble_chart", + name="Bubble chart", + force_link=ForceLink(enabled=False), + force_many_body=ForceManyBody(enabled=False), + force_collision_radius=ForceCollisionRadius(enabled=True), + defaults=[ShowLabels(False)], + ), + rrb.GraphView( + origin="lattice", + name="Lattice", + force_link=ForceLink(distance=60), + force_many_body=ForceManyBody(strength=-60), + defaults=[ShowLabels(False), Radius(10)], + ), + rrb.Horizontal( + rrb.GraphView( + origin="markov_chain", + name="Markov Chain", + # We don't need any forces for this graph, because the nodes have fixed positions. + ), + rrb.TextDocumentView(origin="description", name="Description"), + ), + ) + ) + ) + + +def main() -> None: + parser = argparse.ArgumentParser(description="Logs various graphs using the Rerun SDK.") + rr.script_add_args(parser) + args = parser.parse_args() + + rr.script_setup(args, "rerun_example_graphs") + rr.log("description", rr.TextDocument(DESCRIPTION, media_type=rr.MediaType.MARKDOWN), static=True) + log_trees() + log_lattice(10) + log_markov_chain() + log_blueprint() + rr.script_teardown(args) + + +if __name__ == "__main__": + main() diff --git a/examples/python/graph_binary_tree/pyproject.toml b/examples/python/graphs/pyproject.toml similarity index 70% rename from examples/python/graph_binary_tree/pyproject.toml rename to examples/python/graphs/pyproject.toml index a10385ee722a..107c5d05bba6 100644 --- a/examples/python/graph_binary_tree/pyproject.toml +++ b/examples/python/graphs/pyproject.toml @@ -1,11 +1,11 @@ [project] -name = "graph_binary_tree" +name = "graphs" version = "0.1.0" readme = "README.md" dependencies = ["rerun-sdk"] [project.scripts] -graph_binary_tree = "graph_binary_tree:main" +graphs = "graphs:main" [build-system] requires = ["hatchling"] diff --git a/examples/rust/graph_binary_tree/Cargo.toml b/examples/rust/graph_binary_tree/Cargo.toml deleted file mode 100644 index 34af848c8320..000000000000 --- a/examples/rust/graph_binary_tree/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "graph_binary_tree" -version = "0.21.0-alpha.1+dev" -edition = "2021" -rust-version = "1.80" -license = "MIT OR Apache-2.0" -publish = false - -[dependencies] -rerun = { path = "../../../crates/top/rerun", features = ["clap"] } - -anyhow = "1.0" -clap = { version = "4.0", features = ["derive"] } diff --git a/examples/rust/graph_binary_tree/README.md b/examples/rust/graph_binary_tree/README.md deleted file mode 100644 index 110ff4de97b1..000000000000 --- a/examples/rust/graph_binary_tree/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# graph_binary_tree - -Demonstrates visualization of a graph that varies over time. diff --git a/examples/rust/graph_binary_tree/src/main.rs b/examples/rust/graph_binary_tree/src/main.rs deleted file mode 100644 index 1f820fa28f0a..000000000000 --- a/examples/rust/graph_binary_tree/src/main.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Shows how to draw a graph that varies over time. -//! Please not that this example makes use of fixed positions. -//! -//! Usage: -//! ``` -//! cargo run -p graph_binary_tree -- --connect -//! ``` - -use rerun::{external::re_log, GraphEdges, GraphNodes}; -use std::collections::HashMap; - -#[derive(Debug, clap::Parser)] -#[clap(author, version, about)] -pub struct Args { - #[command(flatten)] - rerun: rerun::clap::RerunArgs, -} - -fn main() -> anyhow::Result<()> { - re_log::setup_logging(); - - use clap::Parser as _; - let args = Args::parse(); - - let (rec, _serve_guard) = args.rerun.init("rerun_example_graph_binary_tree")?; - - let s = 3.0; // scaling factor for the positions - - // Potentially unbalanced and not sorted binary tree. :nerd_face:. - // :warning: The nodes have to be unique, which is why we use `5_0`… - - // (label, position) - type NodeInfo = (&'static str, (f32, f32)); - - struct Level<'a> { - nodes: &'a [&'a str], - edges: &'a [(&'a str, &'a str)], - } - - let nodes_unsorted: HashMap<&str, NodeInfo> = [ - ("1", ("1", (0.0 * s, 0.0 * s))), - ("7", ("7", (-20.0 * s, 30.0 * s))), - ("2", ("2", (-30.0 * s, 60.0 * s))), - ("6", ("6", (-10.0 * s, 60.0 * s))), - ("5_0", ("5", (-20.0 * s, 90.0 * s))), - ("11", ("11", (0.0 * s, 90.0 * s))), - ("9_0", ("9", (20.0 * s, 30.0 * s))), - ("9_1", ("9", (30.0 * s, 60.0 * s))), - ("5_1", ("5", (20.0 * s, 90.0 * s))), - ] - .into_iter() - .collect(); - - let levels_unsorted: Vec = vec![ - Level { - nodes: &["1"], - edges: &[], - }, - Level { - nodes: &["1", "7", "9_0"], - edges: &[("1", "7"), ("1", "9_0")], - }, - Level { - nodes: &["1", "7", "9_0", "2", "6", "9_1"], - edges: &[ - ("1", "7"), - ("1", "9_0"), - ("7", "2"), - ("7", "6"), - ("9_0", "9_1"), - ], - }, - Level { - nodes: &["1", "7", "9_0", "2", "6", "9_1", "5_0", "11", "5_1"], - edges: &[ - ("1", "7"), - ("1", "9_0"), - ("7", "2"), - ("7", "6"), - ("9_0", "9_1"), - ("6", "5_0"), - ("6", "11"), - ("9_1", "5_1"), - ], - }, - ]; - - let nodes_sorted: HashMap<&str, NodeInfo> = [ - ("6", ("6", (0.0 * s, 0.0 * s))), - ("5_0", ("5", (-20.0 * s, 30.0 * s))), - ("9_0", ("9", (20.0 * s, 30.0 * s))), - ] - .into_iter() - .collect(); - - let levels_sorted: Vec = vec![ - Level { - nodes: &["6"], - edges: &[], - }, - Level { - nodes: &["6", "5_0", "9_0"], - edges: &[("6", "5_0"), ("6", "9_0"), ("1", "6"), ("1", "42")], - }, - ]; - - let mut t = 0; - for level in levels_unsorted { - if !level.nodes.is_empty() { - t += 1; - rec.set_time_seconds("stable_time", t as f64); - let _ = rec.log( - "unsorted", - &GraphNodes::new(level.nodes.iter().copied()) - .with_labels(level.nodes.iter().map(|n| nodes_unsorted[n].0)) - .with_positions(level.nodes.iter().map(|n| nodes_unsorted[n].1)), - ); - } - - if !level.edges.is_empty() { - t += 1; - rec.set_time_seconds("stable_time", t as f64); - let _ = rec.log("unsorted", &GraphEdges::new(level.edges)); - } - } - - let entity_offset_x = 200.0; - - for level in levels_sorted { - if !level.nodes.is_empty() { - t += 1; - rec.set_time_seconds("stable_time", t as f64); - let _ = rec.log( - "sorted", - &GraphNodes::new(level.nodes.iter().copied()) - .with_labels(level.nodes.iter().map(|n| nodes_sorted[n].0)) - .with_positions(level.nodes.iter().map(|n| { - let (x, y) = nodes_sorted[n].1; - [x + entity_offset_x, y] - })), - ); - } - - if !level.edges.is_empty() { - t += 1; - rec.set_time_seconds("stable_time", t as f64); - let _ = rec.log( - "sorted", - &GraphEdges::new(level.edges).with_directed_edges(), - ); - } - } - - Ok(()) -} diff --git a/pixi.lock b/pixi.lock index cec6b0f84bfb..704ab17f98a4 100644 --- a/pixi.lock +++ b/pixi.lock @@ -2549,8 +2549,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -2953,8 +2953,8 @@ environments: - pypi: examples/python/dicom_mri - pypi: examples/python/dna - pypi: examples/python/drone_lidar - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/incremental_logging - pypi: examples/python/lidar - pypi: examples/python/live_camera_edge_detection @@ -3338,8 +3338,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -3725,8 +3725,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -4111,8 +4111,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -4541,8 +4541,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -4897,8 +4897,8 @@ environments: - pypi: examples/python/dicom_mri - pypi: examples/python/dna - pypi: examples/python/drone_lidar - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/incremental_logging - pypi: examples/python/lidar - pypi: examples/python/live_camera_edge_detection @@ -5235,8 +5235,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -5575,8 +5575,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -5915,8 +5915,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -9158,8 +9158,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -9656,8 +9656,8 @@ environments: - pypi: examples/python/dicom_mri - pypi: examples/python/dna - pypi: examples/python/drone_lidar - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/incremental_logging - pypi: examples/python/lidar - pypi: examples/python/live_camera_edge_detection @@ -10134,8 +10134,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -10614,8 +10614,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -11073,8 +11073,8 @@ environments: - pypi: examples/python/drone_lidar - pypi: examples/python/face_tracking - pypi: examples/python/gesture_detection - - pypi: examples/python/graph_binary_tree - pypi: examples/python/graph_lattice + - pypi: examples/python/graphs - pypi: examples/python/human_pose_tracking - pypi: examples/python/incremental_logging - pypi: examples/python/lidar @@ -18045,13 +18045,6 @@ packages: - protobuf!=3.20.0,!=3.20.1,>=3.20.2,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0.dev0 - grpcio>=1.44.0,<2.0.0.dev0 ; extra == 'grpc' requires_python: '>=3.7' -- pypi: examples/python/graph_binary_tree - name: graph-binary-tree - version: 0.1.0 - sha256: 8ceb8c2d1102f2f2476eb5fb9c79e717e520f92220709449f48138a3c84c6609 - requires_dist: - - rerun-sdk - editable: true - pypi: examples/python/graph_lattice name: graph-lattice version: 0.1.0 @@ -18113,6 +18106,13 @@ packages: purls: [] size: 95406 timestamp: 1711634622644 +- pypi: examples/python/graphs + name: graphs + version: 0.1.0 + sha256: 4e848c8bfec82cd0d79a4080a37ea03ee24c33d3c64019af981b76ba0bd8d10c + requires_dist: + - rerun-sdk + editable: true - pypi: https://files.pythonhosted.org/packages/eb/fc/570a1e503e19be24c5642ea8b93f23e3eef1dfa930e761cab72dedc2c2db/griffe-1.4.1-py3-none-any.whl name: griffe version: 1.4.1 diff --git a/pixi.toml b/pixi.toml index 4448ca0b884a..72217e1239c9 100644 --- a/pixi.toml +++ b/pixi.toml @@ -638,8 +638,8 @@ minimal = { path = "examples/python/minimal", editable = true } minimal_options = { path = "examples/python/minimal_options", editable = true } multiprocess_logging = { path = "examples/python/multiprocess_logging", editable = true } multithreading = { path = "examples/python/multithreading", editable = true } -graph_binary_tree = { path = "examples/python/graph_binary_tree", editable = true } graph_lattice = { path = "examples/python/graph_lattice", editable = true } +graphs = { path = "examples/python/graphs", editable = true } nuscenes_dataset = { path = "examples/python/nuscenes_dataset", editable = true } nv12 = { path = "examples/python/nv12", editable = true } objectron = { path = "examples/python/objectron", editable = true } diff --git a/tests/python/release_checklist/check_graph_time_layout.py b/tests/python/release_checklist/check_graph_time_layout.py deleted file mode 100644 index e10bde1053a5..000000000000 --- a/tests/python/release_checklist/check_graph_time_layout.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import annotations - -# TODO(grtlr): Promote to example -import os -import random -from argparse import Namespace -from uuid import uuid4 - -import rerun as rr -import rerun.blueprint as rrb - -# TODO(grtlr): Clean up the exports -from rerun.blueprint.archetypes.force_collision_radius import ForceCollisionRadius -from rerun.blueprint.archetypes.force_link import ForceLink -from rerun.blueprint.archetypes.force_many_body import ForceManyBody -from rerun.components.color import Color -from rerun.components.show_labels import ShowLabels - -README = """\ -# Time-varying graph view - -Please watch out for any twitching, jumping, or other wise unexpected changes to -the layout when navigating the timeline. - -Please check the following: -* Scrub the timeline to see how the graph layout changes over time. -""" - -color_scheme = [ - Color([228, 26, 28]), # Red - Color([55, 126, 184]), # Blue - Color([77, 175, 74]), # Green - Color([152, 78, 163]), # Purple - Color([255, 127, 0]), # Orange - Color([255, 255, 51]), # Yellow - Color([166, 86, 40]), # Brown - Color([247, 129, 191]), # Pink - Color([153, 153, 153]), # Gray -] - - -def log_readme() -> None: - rr.log("readme", rr.TextDocument(README, media_type=rr.MediaType.MARKDOWN), static=True) - - -def log_graphs() -> None: - nodes = ["root"] - radii = [42] - colors = [Color([81, 81, 81])] - edges = [] - - # We want reproducible results - random.seed(42) - - # Randomly add nodes and edges to the graph - for i in range(50): - existing = random.choice(nodes) - new_node = str(i) - nodes.append(new_node) - radii.append(random.randint(10, 50)) - colors.append(random.choice(color_scheme)) - edges.append((existing, new_node)) - - rr.set_time_sequence("frame", i) - rr.log( - "node_link", - rr.GraphNodes(nodes, labels=nodes, radii=radii, colors=colors), - rr.GraphEdges(edges, graph_type=rr.GraphType.Directed), - ) - rr.log( - "bubble_chart", - rr.GraphNodes(nodes, labels=nodes, radii=radii, colors=colors), - ) - - rr.send_blueprint( - rrb.Blueprint( - rrb.Grid( - rrb.GraphView( - origin="node_link", - name="Node-link diagram", - force_link=ForceLink(distance=60), - force_many_body=ForceManyBody(strength=-60), - ), - rrb.GraphView( - origin="bubble_chart", - name="Bubble chart", - force_link=ForceLink(enabled=False), - force_many_body=ForceManyBody(enabled=False), - force_collision_radius=ForceCollisionRadius(enabled=True), - defaults=[ShowLabels(False)], - ), - rrb.TextDocumentView(origin="readme", name="Instructions"), - ) - ) - ) - - -def run(args: Namespace) -> None: - rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4()) - - log_readme() - log_graphs() - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser(description="Interactive release checklist") - rr.script_add_args(parser) - args = parser.parse_args() - run(args)