Events, exports, and positions¶
On this page¶
- Custom event listeners
- Event validation
- Export formats
- Position payloads
- Movement metadata
- Choosing browser or Python export
Custom event listeners¶
Use Event(name, event_type, selector) for lower-level Cytoscape interactions
not already represented by selection, CRUD, analysis, or other built-in tools:
events = [
Event("vehicle_click", "click tap", "node[label = 'VEHICLE']"),
Event("location_double_click", "dblclick dbltap", "node[label = 'LOCATION']"),
]
The returned event uses the custom name as action and includes event type,
target ID, target group, target data, and timestamp. Changing events updates
listeners on the existing component without requiring a new key.
Event validation¶
Names and event types must be non-empty strings. Selectors must be strings.
Custom names cannot be reserved values such as selection, search,
analysis, crud, edit, viewport, positions, or export.
Export formats¶
The browser toolbar provides:
- Visible graph JSON.
- Full graph JSON, including currently hidden elements.
- Selected subgraph JSON.
- PNG image.
- JPG image.
- Node positions JSON.
JSON exports preserve graph element data. Image exports capture the current canvas appearance and viewport; they are evidence illustrations rather than a replacement for source records.
Position payloads¶
Set return_positions=True to receive position events. Each record contains a
node id and model position with x and y. Apply those positions to
Python-owned nodes and render with layout="preset" to restore manual layouts.
import copy
import streamlit as st
from st_graph_workbench import graph_workbench
def apply_positions(elements: dict, position_records: list[dict]) -> dict:
positions = {
str(item["id"]): item["position"]
for item in position_records
if "id" in item and "position" in item
}
updated = copy.deepcopy(elements)
for node in updated["nodes"]:
node_id = str(node["data"]["id"])
if node_id in positions:
node["position"] = positions[node_id]
return updated
event = graph_workbench(
st.session_state.elements,
layout={"name": "preset", "fit": True, "padding": 40},
return_positions=True,
connected_drag={"enabled": False, "depth": 1, "max_nodes": 100},
key="persisted-layout",
)
if isinstance(event, dict) and event.get("action") == "positions":
st.session_state.elements = apply_positions(
st.session_state.elements,
event.get("data", {}).get("positions", []),
)
Movement metadata¶
Position events produced by a node drag include a movement dictionary:
{
"operation": "connected_drag",
"status": "applied",
"anchor_node_id": "location-1",
"moved_node_ids": ["location-1", "vehicle-1", "vehicle-2"],
"connected_node_ids": ["vehicle-1", "vehicle-2"],
"depth": 1,
"candidate_count": 2,
"max_nodes": 100
}
moved_node_ids includes native anchor/selected-group movement plus automatic
followers. connected_node_ids contains followers only. Status is applied,
disabled, limit_exceeded, or layout_running; operation is drag for
ordinary dragging and connected_drag for configured connected gestures.
Layout-generated position events remain unchanged and omit movement.
Choosing browser or Python export¶
Use browser exports for analyst-driven snapshots. Use returned records and
records_to_dataframe() when the application must add metadata, enforce access
control, create a repeatable report, or write to a controlled destination.
Conclusion¶
Custom events expose Cytoscape without weakening the higher-level API. Keep event names application-specific and retain structured records beside images.