render_ipycytoscape

render_ipycytoscape class

Reactively render an ipycytoscape network graph.

Usage Source

render_ipycytoscape(
    _fn: Optional[ValueFn[ValueT]] = None,
    *,
    width: Optional[str] = None,
    height: Optional[str] = None,
    fill: Optional[bool] = None,
    fillable: Optional[bool] = None,
    rate_policy: Optional[RatePolicy] = None,
    rate_delay: Optional[float] = None,
)

@render_ipycytoscape is a decorator that creates a render function – a function that returns the graph to display and re-runs when the reactive values it reads change:

import networkx as nx

from shinywidgets import render_ipycytoscape


@render_ipycytoscape
def graph():
    return nx.karate_club_graph()

The render function may return either a networkx.Graph (which is coerced to an ipycytoscape.CytoscapeWidget; requires pip install 'shinywidgets[ipycytoscape]') or an ipycytoscape.CytoscapeWidget widget.

Note

Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered CytoscapeWidget instance.

Responding to user interaction: the output has methods that read what the user does in the graph, much like input.my_slider() reads an input. Call them in a reactive function (a @render.* function, @reactive.calc, or @reactive.effect), which then re-runs whenever the interaction changes:

  • clicked_node(): the JSON data of the most recently clicked node.
  • clicked_edge(): the JSON data of the most recently clicked edge.
  • selected_nodes(): the data dicts of the currently selected nodes.
  • selected_edges(): the data dicts of the currently selected edges.

clicked_node() and clicked_edge() return None until the interaction happens (a normal state, not an error, so check for it, or use req(graph.clicked_node())), and keep their value across re-renders (the last interaction still happened, though its payload refers to the previous render’s graph). For other event types, register callbacks with CytoscapeWidget.on() inside the render function, before returning the widget, and have them set a value (registering there also means an interaction right at display isn’t missed).

ipycytoscape makes nodes unselectable by default, so selected_nodes() stays [] unless you create the widget with auto_unselectify=False and set selectable = True on each node (plus box_selection_enabled=True for shift-drag selection). Each node’s selection is also synced to its selected trait, readable with reactive_read() (e.g., reactive_read(node, "selected") on a node in .widget.graph.nodes).

Mutating the widget: use .widget to update the graph in place (e.g., .widget.set_style(), .widget.set_layout(), or setting classes on the nodes in .widget.graph.nodes) without re-rendering.

Parameters

width : Optional[str] = None

A CSS length unit (e.g., "400px" or "100%") for the output’s width.

height : Optional[str] = None

A CSS length unit for the output’s height. When None (the default), the output is designed to fill the height of its parent container (see fill and fillable).

fill : Optional[bool] = None

Whether the output should grow or shrink to fit its parent container. When None (the default), this is True if height is not specified.

fillable : Optional[bool] = None

Whether the output container should fill available space (scrolling its contents on overflow). When None (the default), this is True if height is not specified.

rate_policy : Optional[RatePolicy] = None

How to rate-limit reactive_read() on the widget and on its graph’s child Node/Edge widgets, which own the traits worth reading (selected on both, grabbed on nodes): "debounce" or "throttle". None (the default) debounces reactive_read() only if rate_delay is given, and keeps the selected_nodes()/selected_edges() accessors’ own debounce default (0.25s), which these kwargs override. Nodes or edges added to the graph after the render aren’t covered (re-render to cover them).

rate_delay : Optional[float] = None

The rate-limit window in seconds (default 0.25). 0 disables rate limiting.

Each :
which :

See also

output_widget(): in Shiny Core, the UI needs this to hold the output (Shiny Express displays it where the render function is defined).

Methods

clicked_edge() The most recently clicked edge, as its cytoscape ele.json() dict (its "data" key holds the edge’s data, including "id", "source", and "target").
clicked_node() The most recently clicked node, as its cytoscape ele.json() dict (its "data" key holds the node’s data, including "id").
selected_edges() The currently selected edges, as their data dicts (each including its "id", "source", and "target"), in graph order; [] when nothing is selected.
selected_nodes() The currently selected nodes, as their data dicts (each including its "id"), in graph order; [] when nothing is selected.

clicked_edge()

render_ipycytoscape.clicked_edge()

The most recently clicked edge, as its cytoscape ele.json() dict (its "data" key holds the edge’s data, including "id", "source", and "target").

Returns None until the user clicks an edge, and keeps its value across re-renders, so use req(graph.clicked_edge()) to wait for a click. Edge ids generated from networkx graphs are fresh UUIDs each render, so a retained payload’s id won’t exist in the new graph. Clicking the same edge twice doesn’t fire twice. Not rate-limited.

clicked_node()

render_ipycytoscape.clicked_node()

The most recently clicked node, as its cytoscape ele.json() dict (its "data" key holds the node’s data, including "id").

Returns None until the user clicks a node, and keeps its value across re-renders (the payload then refers to the previous render’s graph – node ids may not exist in the new one), so use req(graph.clicked_node()) to wait for a click. Node ids are strings, even for integer networkx nodes. Clicking the same node twice doesn’t fire twice. Not rate-limited.

selected_edges()

render_ipycytoscape.selected_edges()

The currently selected edges, as their data dicts (each including its "id", "source", and "target"), in graph order; [] when nothing is selected.

See selected_nodes() for selection setup and rate limiting.

selected_nodes()

render_ipycytoscape.selected_nodes()

The currently selected nodes, as their data dicts (each including its "id"), in graph order; [] when nothing is selected.

Unlike clicked_node(), this covers box/multi-select, and it doesn’t reset on re-render. ipycytoscape makes nodes unselectable by default: create the widget with auto_unselectify=False and set selectable = True on each node (plus box_selection_enabled=True for shift-drag selection). Debounced by default (0.25s; see the renderer’s rate_policy/rate_delay parameters).