Skip to content

Commit bd71bf0

Browse files
committed
Promote time-varying layout to full example
1 parent 388c8aa commit bd71bf0

File tree

8 files changed

+243
-220
lines changed

8 files changed

+243
-220
lines changed

examples/manifest.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ examples = [
142142
"notebook",
143143
"clock",
144144
"dna",
145+
"graphs",
145146
"log_file",
146147
"openstreetmap_data",
147148
"minimal",
@@ -150,8 +151,6 @@ examples = [
150151
"plots",
151152
"live_scrolling_plot",
152153
"raw_mesh",
153-
"graph_lattice",
154-
"graph_binary_tree",
155154
"air_traffic_data",
156155
]
157156

@@ -169,6 +168,7 @@ examples = [
169168
"drone_lidar",
170169
"extend_viewer_ui",
171170
"external_data_loader",
171+
"graph_binary_tree",
172172
"incremental_logging",
173173
"minimal_serve",
174174
"shared_recording",

examples/python/graph_lattice/graph_lattice.py

-72
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
<!--[metadata]
2-
title = "Graph lattice"
2+
title = "Graphs"
33
tags = ["Graph", "Layout"]
4-
thumbnail = "https://static.rerun.io/graph_lattice/f9169da9c3f35b7260c9d74cd5be5fe710aec6a8/480w.png"
5-
thumbnail_dimensions = [480, 269]
4+
thumbnail = "https://static.rerun.io/graphs/19e6ca2e0752cdc7107c10b0cb79a4b7192d9e0b/480w.png"
5+
thumbnail_dimensions = [480, 399]
66
channel = "main"
77
-->
88

99
This example shows different attributes that you can associate with nodes in a graph.
1010
Since no explicit positions are passed for the nodes, Rerun will layout the graph automatically.
1111

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

2020
## Used Rerun types
@@ -24,6 +24,6 @@ Since no explicit positions are passed for the nodes, Rerun will layout the grap
2424
## Run the code
2525

2626
```bash
27-
pip install -e examples/python/graph_lattice
28-
python -m graph_lattice
27+
pip install -e examples/python/graphs
28+
python -m graphs
2929
```

examples/python/graphs/graphs.py

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
#!/usr/bin/env python3
2+
"""Examples of logging graph data to Rerun and performing force-based layouts."""
3+
4+
from __future__ import annotations
5+
6+
import argparse
7+
import random
8+
import itertools
9+
import numpy as np
10+
11+
import rerun as rr
12+
import rerun.blueprint as rrb
13+
14+
from rerun.blueprint.archetypes.force_collision_radius import ForceCollisionRadius
15+
from rerun.blueprint.archetypes.force_link import ForceLink
16+
from rerun.blueprint.archetypes.force_many_body import ForceManyBody
17+
from rerun.components.color import Color
18+
from rerun.components.radius import Radius
19+
from rerun.components.show_labels import ShowLabels
20+
21+
22+
color_scheme = [
23+
Color([228, 26, 28]), # Red
24+
Color([55, 126, 184]), # Blue
25+
Color([77, 175, 74]), # Green
26+
Color([152, 78, 163]), # Purple
27+
Color([255, 127, 0]), # Orange
28+
Color([255, 255, 51]), # Yellow
29+
Color([166, 86, 40]), # Brown
30+
Color([247, 129, 191]), # Pink
31+
Color([153, 153, 153]), # Gray
32+
]
33+
34+
DESCRIPTION = """
35+
# Graphs
36+
This example shows various graph visualizations that you can create using Rerun.
37+
In this example, the node positions—and therefore the graph layout—are computed by Rerun internally using a force-based layout algorithm.
38+
39+
You can modify how these graphs look by changing the parameters of the force-based layout algorithm in the selection panel.
40+
41+
The full source code for this example is available
42+
[on GitHub](https://github.com/rerun-io/rerun/blob/latest/examples/python/graphs?speculative-link).
43+
""".strip()
44+
45+
46+
# We want reproducible results
47+
random.seed(42)
48+
49+
50+
def log_lattice(num_nodes) -> None:
51+
coordinates = itertools.product(range(num_nodes), range(num_nodes))
52+
53+
nodes, colors = zip(*[
54+
(
55+
str(i),
56+
rr.components.Color([round((x / (num_nodes - 1)) * 255), round((y / (num_nodes - 1)) * 255), 0]),
57+
)
58+
for i, (x, y) in enumerate(coordinates)
59+
])
60+
61+
rr.log(
62+
"lattice",
63+
rr.GraphNodes(
64+
nodes,
65+
colors=colors,
66+
labels=[f"({x}, {y})" for x, y in itertools.product(range(num_nodes), range(num_nodes))],
67+
),
68+
static=True,
69+
)
70+
71+
edges = []
72+
for x, y in itertools.product(range(num_nodes), range(num_nodes)):
73+
if y > 0:
74+
source = (y - 1) * num_nodes + x
75+
target = y * num_nodes + x
76+
edges.append((str(source), str(target)))
77+
if x > 0:
78+
source = y * num_nodes + (x - 1)
79+
target = y * num_nodes + x
80+
edges.append((str(source), str(target)))
81+
82+
rr.log("/lattice", rr.GraphEdges(edges, graph_type="directed"), static=True)
83+
84+
85+
def log_trees() -> None:
86+
nodes = ["root"]
87+
radii = [42]
88+
colors = [Color([81, 81, 81])]
89+
edges = []
90+
91+
# Randomly add nodes and edges to the graph
92+
for i in range(50):
93+
existing = random.choice(nodes)
94+
new_node = str(i)
95+
nodes.append(new_node)
96+
radii.append(random.randint(10, 50))
97+
colors.append(random.choice(color_scheme))
98+
edges.append((existing, new_node))
99+
100+
rr.set_time_sequence("frame", i)
101+
rr.log(
102+
"node_link",
103+
rr.GraphNodes(nodes, labels=nodes, radii=radii, colors=colors),
104+
rr.GraphEdges(edges, graph_type=rr.GraphType.Directed),
105+
)
106+
rr.log(
107+
"bubble_chart",
108+
rr.GraphNodes(nodes, labels=nodes, radii=radii, colors=colors),
109+
)
110+
111+
112+
def log_markov_chain() -> None:
113+
transition_matrix = np.array([
114+
[0.8, 0.1, 0.1], # Transitions from sunny
115+
[0.3, 0.4, 0.3], # Transitions from rainy
116+
[0.2, 0.3, 0.5], # Transitions from cloudy
117+
])
118+
state_names = ["sunny", "rainy", "cloudy"]
119+
# For this example, we use hardcoded positions.
120+
positions = [[0, 0], [150, 150], [300, 0]]
121+
inactive_color = Color([153, 153, 153]) # Gray
122+
active_colors = [
123+
Color([255, 127, 0]), # Orange
124+
Color([55, 126, 184]), # Blue
125+
Color([152, 78, 163]), # Purple
126+
]
127+
128+
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]
129+
130+
# We start in state "sunny"
131+
state = "sunny"
132+
133+
for i in range(50):
134+
current_state_index = state_names.index(state)
135+
next_state_index = np.random.choice(
136+
range(len(state_names)), p=transition_matrix[current_state_index]
137+
)
138+
state = state_names[next_state_index]
139+
colors = [inactive_color] * len(state_names)
140+
colors[next_state_index] = active_colors[next_state_index]
141+
142+
print(colors)
143+
144+
rr.set_time_sequence("frame", i)
145+
rr.log(
146+
"markov_chain",
147+
rr.GraphNodes(state_names, labels=state_names, colors=colors, positions=positions),
148+
rr.GraphEdges(edges, graph_type="directed")
149+
)
150+
151+
152+
153+
def log_blueprint() -> None:
154+
rr.send_blueprint(
155+
rrb.Blueprint(
156+
rrb.Grid(
157+
rrb.GraphView(
158+
origin="node_link",
159+
name="Node-link diagram",
160+
force_link=ForceLink(distance=60),
161+
force_many_body=ForceManyBody(strength=-60),
162+
),
163+
rrb.GraphView(
164+
origin="bubble_chart",
165+
name="Bubble chart",
166+
force_link=ForceLink(enabled=False),
167+
force_many_body=ForceManyBody(enabled=False),
168+
force_collision_radius=ForceCollisionRadius(enabled=True),
169+
defaults=[ShowLabels(False)],
170+
),
171+
rrb.GraphView(
172+
origin="lattice",
173+
name="Lattice",
174+
force_link=ForceLink(distance=60),
175+
force_many_body=ForceManyBody(strength=-60),
176+
defaults=[ShowLabels(False), Radius(10)],
177+
),
178+
rrb.Horizontal(
179+
rrb.GraphView(
180+
origin="markov_chain",
181+
name="Markov Chain",
182+
# We don't need any forces for this graph, because the nodes have fixed positions.
183+
),
184+
rrb.TextDocumentView(origin="description", name="Description"),
185+
)
186+
)
187+
)
188+
)
189+
190+
191+
def main() -> None:
192+
parser = argparse.ArgumentParser(description="Logs various graphs using the Rerun SDK.")
193+
rr.script_add_args(parser)
194+
args = parser.parse_args()
195+
196+
rr.script_setup(args, "rerun_example_graphs")
197+
rr.log("description", rr.TextDocument(DESCRIPTION, media_type=rr.MediaType.MARKDOWN), static=True)
198+
log_trees()
199+
log_lattice(10)
200+
log_markov_chain()
201+
log_blueprint()
202+
rr.script_teardown(args)
203+
204+
205+
if __name__ == "__main__":
206+
main()

examples/python/graph_lattice/pyproject.toml renamed to examples/python/graphs/pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[project]
2-
name = "graph_lattice"
2+
name = "graphs"
33
version = "0.1.0"
44
readme = "README.md"
55
dependencies = ["rerun-sdk"]
66

77
[project.scripts]
8-
graph_lattice = "graph_lattice:main"
8+
graphs = "graphs:main"
99

1010
[build-system]
1111
requires = ["hatchling"]

0 commit comments

Comments
 (0)