Custom JavaScript Controls#
The Python and R bindings cover the common options, but every figure
they produce is a live LightGraph instance with a full JavaScript
API — you can wire your own buttons, dashboards, or page logic to it.
This page shows how to reach the instance from each host and what you
can do with it.
The instance API#
Whichever way a graph was created, its container element carries the
instance as container.lightgraph (in hand-written JavaScript you
also get it back from new lightGraph.LightGraph(...)). The instance
offers:
Methods —
setData({nodes, edges}),updateConfig(partial),zoomToFit(padding?),getSelection(),selectNodes(ids),egoFilter(nodeId, depth?)/clearEgoFilter()/getVisibleNodes(),settle(ticks?),resize(),destroy().Events —
on(event, cb)/off(event, cb)fornodeClick({node}),selectionChange(array of selected nodes),dataLoad,egoFilter, anddestroy.
Live example#
The toolbar above this graph is plain HTML — three buttons and a status label — talking to the instance. Click a node or use the buttons:
The wiring is just event handlers calling instance methods:
var graph = new lightGraph.LightGraph(document.getElementById('graph'), {
nodes: nodes, edges: edges, config: config
});
var status = document.getElementById('status');
document.getElementById('btn-starks').onclick = function () {
graph.clearEgoFilter();
graph.selectNodes(['Eddard', 'Catelyn', 'Robb', 'Sansa',
'Arya', 'Bran', 'Rickon', 'Jon']);
};
document.getElementById('btn-tyrion').onclick = function () {
graph.egoFilter('Tyrion', 2);
};
document.getElementById('btn-reset').onclick = function () {
graph.clearEgoFilter();
graph.selectNodes([]);
graph.zoomToFit();
};
graph.on('nodeClick', function (e) {
status.textContent = 'Clicked ' + e.node.id;
});
graph.on('selectionChange', function (selected) {
if (selected.length) status.textContent = selected.length + ' selected';
});
graph.on('egoFilter', function () {
status.textContent = graph.getVisibleNodes().length + ' nodes visible';
});
(The full page is generated by docs/tools/gen_example_embeds.py if
you want to copy it as a starting point.)
From R: htmlwidgets::onRender#
R’s htmlwidgets framework has a standard hook for attaching JavaScript to a rendered widget. The hook receives the widget’s DOM element, so the instance is one property away:
library(lightgraph)
library(htmlwidgets)
data(got)
w <- lightgraph(edges = got, node_metric = lg_pagerank(got),
edge_weight_to_width = TRUE)
onRender(w, "
function(el, x) {
var graph = el.lightgraph;
graph.on('nodeClick', function (e) {
console.log('clicked', e.node.id);
});
graph.egoFilter('Tyrion', 2);
}
")
This works in the RStudio viewer, in R Markdown documents, and in Shiny
(wrap the widget in renderLightgraph() as usual — the onRender
hook travels with it, and nodeClick handlers can call
Shiny.setInputValue() to send selections back to the server).
From Python: extend the generated page#
net_vis() returns a NetworkVisualization whose
.html property is a complete, self-contained page. Append your own
script before saving it. One detail: the page initializes the graph
asynchronously, so poll until the instance appears on the container
(id lightGraph):
from lightgraph import net_vis, datasets, pagerank
edges = datasets.got()
vis = net_vis(edges=edges, node_metric=pagerank(edges))
controls = """
<script>
(function poll() {
var el = document.getElementById('lightGraph');
if (!(el && el.lightgraph)) return setTimeout(poll, 50);
var graph = el.lightgraph;
graph.on('nodeClick', function (e) {
console.log('clicked', e.node.id);
});
graph.egoFilter('Tyrion', 2);
})();
</script>
"""
html = vis.html.replace('</body>', controls + '</body>')
with open('got_custom.html', 'w') as f:
f.write(html)
Inside Jupyter, vis renders in a sandboxed iframe for isolation, so
scripts on the notebook page cannot reach it — the pattern above
(augment the HTML, then save or serve it) is the supported route for
custom controls.
Going further#
updateConfig(partial) accepts any fragment of the JS
DEFAULT_CONFIG (see API Reference), so a slider wired to
graph.updateConfig({edges: {widthScale: v}}) gives you live styling
controls; setData({nodes, edges}) swaps the whole graph and reuses
the instance. Everything the built-in toolbar and sidebar do goes
through this same public API.