Meta / Script / Callback

Handle events from external Javascript libraries.

import json
import random
import math
from h2o_wave import main, app, Q, ui
# Create some data for a random graph
node_count = 100
edge_count = 500
nodes = [
dict(id=f'n{i}', label=f'Node {i}', x=random.random(), y=random.random(), size=random.random(), color='#ff0000')
for i in range(node_count)]
edges = [dict(id=f'e{i}', source=f'n{math.floor(random.random() * node_count)}',
target=f'n{math.floor(random.random() * node_count)}', size=random.random(), color='#666') for i in
graph_data = dict(nodes=nodes, edges=edges)
# Serialize graph data to Javascript / JSON.
graph_data_js = f'const graph = {json.dumps(graph_data)};'
# Define a script that uses Sigma.js to render our graph.
render_graph = graph_data_js + '''
const s = new sigma({ graph: graph, container: 'graph' });
s.bind('clickNode', (e) => {
// Emit an event when a node is clicked.
// All three arguments are arbitrary.
// Here, we use:
// - 'graph' to indicate the source of the event.
// - 'node_clicked' to indicate the type of event.
// - the third argument can be a string, number, boolean or any complex structure, like { foo: 'bar', qux: 42 }
// In Python, will be set to the ID of the clicked node.
wave.emit('graph', 'node_clicked',;
async def serve(q: Q):
if not q.client.initialized:['meta'] = ui.meta_card(
# Load Sigma.js
# Call Javascript to render our graph using Sigma.js.
# Ensure that Sigma.js is available before running our script.
# Ensure that the 'graph' element is available before running our script.
# Add a placeholder named 'graph' to house our rendered graph.['vis'] = ui.markup_card(
box='1 1 6 8',
title='Select a node',
content='<div id="graph" style="width: 800px; height: 500px;"/>'
# Add another card to display which node was selected.['details'] = ui.markdown_card(
box='1 9 6 1',
content='The selected node will be displayed here.',
q.client.initialized = True
selected_node =
if selected_node:['details'].content = f'You clicked on node {selected_node}'