Transition Graph

Displays an interactive directed graph where nodes are unique events and edges represent transitions between them. Edge weights can show transition probabilities, counts, or time-based metrics. Supports diff mode to compare two user segments side by side.

Usage

stream.transition_graph()
stream.transition_graph(edge_weight="count", diff=("plan", "pro", "free"))
stream.transition_graph(state_file="checkout_graph.json")
stream.transition_graph(
    views=[{"name": "Checkout", "focus": {"type": "node", "event": "cart"}}],
    view="Checkout",
)

Parameters

Data

Data parameters change the computed result. They are exactly the arguments of the widget's headless twin stream.transition_graph_data() — see headless mode below.

ParameterTypeDescription
edge_weight{"proba_out", "proba_in", "count", "unique_paths", "share_of_total", "avg_per_path", "time_median", "time_q95"}, default "proba_out"Value shown on edges. See the Edge Weights section for more details.
difftuple or list, optionalDraws a comparative chart for a pair of segments; see Diff mode. (segment_col, value1, value2) or (path_ids1, path_ids2); value2 may be <REST>, meaning "every other value of segment_col".
path_colstr, optionalPath ID column override; defaults to schema.path_col.

Display

Display parameters only affect how the widget is rendered.

ParameterTypeDescription
heightint, default 500Widget height in pixels.
sidebar_openbool, default TrueWhether the sidebar starts open.
viewslist of dict, optionalNamed visual presets rendered as pills above the graph. Each view is a dict with the keys name, focus, edgeFilter, eventCountFilter, hiddenEvents, viewport (all optional except name) and describes only how the graph is displayed — never the computed data. See the Views section for a detailed description of every key.
viewdict or str, optionalView applied once after the graph is built: a view dict (name not required), or the name of an entry in views. See the Views section.
state_filestr, optionalJSON file the widget state is bound to; see Saving widget state.

Edge weights

  • "proba_out" — probability of the transition among all transitions out of the source event.
  • "proba_in" — probability of the transition among all transitions into the target event.
  • "count" — number of times the transition occurred.
  • "unique_paths" — number of distinct paths containing the transition.
  • "share_of_total" — share of this transition among all transitions in the eventstream.
  • "avg_per_path" — average number of occurrences per path.
  • "time_median" / "time_q95" — median / 95th-percentile time between the two events (in seconds).

Views

views is a list of named visual presets rendered as pills above the graph; view applies one of them (or an inline preset) right after the graph is built. A view describes only how the graph is displayed — focus, filters, hidden events, viewport — never the computed data, so the same view works identically in the live widget, in exported HTML (including the #view=<base64url> URL fragment) and in MCP report tabs ([Tab:view=Name] links in the analysis text).

Applying a pill always starts from the Default state — views do not inherit each other's settings — and the Default pill returns exactly the state the widget had before the first view was applied. Any manual interaction (clicking a node, moving a filter) deselects the active pill.

KeyTypeDescription
namestrPill label; also the handle for view="Name" and [Tab:view=Name] links. Required for pills, optional for inline view= presets.
focusdict, optionalDim everything except the focused element(s): a node, an edge, or a path. See focus.
edgeFilterdict, optionalEdge filter override — the Auto/Manual control at the bottom right. See edgeFilter.
eventCountFilter[min, max], optionalEvent-count (node) filter in absolute occurrence counts — the sidebar's Event Count slider.
hiddenEventslist of str, optionalEvents hidden in this view.
viewportstr or dict, optionalCamera control. See viewport.
nodePositionsdict, optionalExact node coordinates ({"event": {"x": …, "y": …}}) the view pins on apply. Rarely needed by hand: manual arrangements persist on their own (per-dataset) and travel with exports.
egoNodestr, optionalOpens the Ego view modal for this event on apply. Independent of focus — a view can set both, or just this. Not captured by the Copy view link button (the modal covers the toolbar while it's open) — write it by hand.

focus

  • {"type": "node", "event": "cart"} — focus one event: everything else dims and the viewport fits the node together with its neighborhood. One direction is shown at a time by default: outgoing transitions, "direction": "in" for incoming, "direction": "both" for both at once (no color code — direction is read off the existing arrowheads). In the widget, clicking a node shows its outgoing transitions; clicking that same node again cycles to incoming, then to both, then back to outgoing. Diff mode always shows both directions (red/blue).
  • {"type": "edge", "source": "cart", "target": "checkout"} — focus one transition: the edge and its two nodes stay bright (the edge is shown even when the edge filter would hide it), the weight label is forced on, and the viewport fits the pair.
  • {"type": "path", "nodes": ["main", "catalog", "cart"]} — highlight a route of two or more events: consecutive transitions are drawn as an amber dashed overlay (visible through the edge filter), weight labels appear along the route, and everything outside the route dims. Segments with no direct transition in the data are skipped.

Omitting focus means "no focus" — the view only applies filters and the viewport.

edgeFilter

  • {"mode": "topk", "k": 3} — the Auto mode: keep each node's k strongest outgoing edges (plus every node's single strongest incoming edge, so no node is left unconnected).
  • {"mode": "range", "range": [0.05, 1]} — the Manual mode: a weight range normalized to 0..1. For probability weights the bounds are the probabilities themselves; for other weight types they are fractions of the largest weight on the graph.

viewport

  • "fit" — fit the whole graph.
  • "fit-focus" — fit the focused node/edge/path; this is the default whenever focus is present.
  • {"zoom": 1.4, "pan": {"x": 350, "y": 220}} — an exact camera position.

The easiest way to author a view is the Copy view link toolbar button: arrange the graph by hand and click it — the current state (including the exact viewport) is copied as a JSON snippet for views=[...] in the live widget, or as a shareable #view= URL in exported HTML. To author a path view by mouse: click the route's first event, then Cmd/Ctrl+click the following events in route order — after every click, the outgoing edges of the route's last event stay lit, so the candidates for the next click are always visible. Every Cmd/Ctrl+click appends, so repeated events build loops and cycles (A→B→B, A→B→A→C); Cmd/Ctrl+double-click on the route's last event removes it — a backspace-like undo. Then Copy view link serializes the selection as {"type": "path", ...}. Note that transitions are directed: the route follows the click order, and segments with no direct transition in the data are skipped when the view is applied.

Route statistics

While a path of two or more events is selected in the live widget, a badge at the top shows statistics for that exact route — how many paths contain the sequence A→B→…→N as strict consecutive transitions (no other events in between). The badge's metric selector offers: unique paths (and their share of all paths), traversals (total occurrences; a path may traverse a route several times), avg per path, median / p95 route time (from the route's first to last event within one traversal), and P(route) — the product of the route's P(next | source) transition probabilities. The default metric follows the current edge weight.

Ego view

With a node focused, the Ego view toolbar button expands its neighborhood into a modal mini-sankey: the event in the center, incoming transitions on the left, outgoing on the right, sorted with ribbon thickness proportional to the value. The sides answer the two ego questions directly, independent of the edge weight selected on the graph: the left side shows each source's share of the arrivals at the event (proba_in), the right side each target's share of the exits from it (proba_out) — both sides sum to 100%, and the tooltip carries the raw transition counts. Unlike the graph, the same event can appear on both sides, and a self-loop shows up on each (marked ↻). The view is not limited by the edge filter — it always shows the strongest transitions of the focused event (up to 12 per side). Clicking a neighbor re-centers the view on it, so you can walk the graph one neighborhood at a time; Esc or clicking outside closes the modal. In diff mode the ribbons instead show the displayed diff values with the red/blue color code, and hovering one shows the same per-group breakdown tooltip as a graph edge — both group values and the diff between them.

Headless mode

stream.transition_graph_data()

Compute the transition matrix between events (headless): an events x events DataFrame where cell [source, target] holds the selected edge_weight for the source -> target transition. This is the data behind the transition_graph widget.

Examples

Basic

stream.transition_graph()

Edge weight

stream.transition_graph(edge_weight="unique_paths")

Diff mode

stream.transition_graph(diff=["platform", "mobile", "desktop"])

Views

stream.transition_graph(
  views=[
      {
          "name": "Cart",
          "focus": {"type": "node", "event": "cart"},
          "edgeFilter": {"mode": "topk", "k": 2}
      },
      {
          "name": "Checkout path",
          "focus": {
              "type": "path",
              "nodes": ["cart", "shipping_details", "payment_details", "purchase"]
          }
      },
      {
          "name": "Big picture",
          "edgeFilter": {"mode": "range", "range": [0.10, 1]},
          "eventCountFilter": [500, 7000]
      },
  ],
  view="Checkout path",
  sidebar_open=False
)

Ego view

stream.transition_graph(
  views=[
      {
          "name": "Cart",
          "focus": {"type": "node", "event": "cart"},
          "egoNode": "cart"
      },
  ],
  view="Cart"
)