Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement complete Graph View example #8421

Merged
merged 13 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/store/re_chunk/src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl ChunkComponents {
}

/// Returns all list arrays for the given component name.
///
///
/// I.e semantically equivalent to `get("MyComponent:*.*")`
#[inline]
pub fn get_by_component_name<'a>(
Expand Down
2 changes: 1 addition & 1 deletion crates/viewer/re_view_graph/src/layout/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.);
Expand Down
5 changes: 3 additions & 2 deletions examples/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ examples = [
"notebook",
"clock",
"dna",
"graphs",
"log_file",
"openstreetmap_data",
"minimal",
Expand All @@ -150,8 +151,6 @@ examples = [
"plots",
"live_scrolling_plot",
"raw_mesh",
"graph_lattice",
"graph_binary_tree",
"air_traffic_data",
]

Expand All @@ -169,6 +168,8 @@ examples = [
"drone_lidar",
"extend_viewer_ui",
"external_data_loader",
"graph_binary_tree",
"graph_lattice",
"incremental_logging",
"minimal_serve",
"shared_recording",
Expand Down
72 changes: 0 additions & 72 deletions examples/python/graph_lattice/graph_lattice.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<!--[metadata]
title = "Graph lattice"
title = "Graphs"
tags = ["Graph", "Layout"]
thumbnail = "https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/480w.png"
thumbnail_dimensions = [480, 269]
thumbnail = "https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/480w.png"
thumbnail_dimensions = [480, 399]
channel = "main"
-->

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.

<picture>
<img src="https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/1200w.png">
<img src="https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/1200w.png">
</picture>

## Used Rerun types
Expand All @@ -24,6 +24,6 @@ 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
pip install -e examples/python/graphs
python -m graphs
```
206 changes: 206 additions & 0 deletions examples/python/graphs/graphs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#!/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) -> 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)
grtlr marked this conversation as resolved.
Show resolved Hide resolved


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
]

# 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]

print(colors)

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()
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[project]
name = "graph_lattice"
name = "graphs"
version = "0.1.0"
readme = "README.md"
dependencies = ["rerun-sdk"]

[project.scripts]
graph_lattice = "graph_lattice:main"
graphs = "graphs:main"

[build-system]
requires = ["hatchling"]
Expand Down
Loading
Loading