Skip to content
Open Garphield

Binding grammar

A binding connects a source to a visual channel. The workbench writes bindings for you; this page is the wire format for authoring them directly - in a .gph document, over the embed protocol, or from the Python and R packages. The GPH schema constrains a binding’s shape, but not whether a channel accepts a source. Garphield resolves that against the catalog below, and the Python package raises BindingError at build time when a binding does not resolve.

Bindings live in config.bindings as an array. Each entry is:

{
"channel": "color",
"source": { "kind": "field", "id": "field:team" },
"resultType": "cat"
}
  • channel - the mark or layer the source drives (see Channels).
  • source - { "kind", "id", "params?", "target?" } (see Source kinds).
  • resultType - what the source produces: num, cat, or set. It must be a type the channel accepts, and for an algorithm source it must match what that algorithm produces.

Channels are camelCase on the wire. The result types a channel accepts and its target (node or edge) are fixed. The Python and R packages also accept the snake_case alias in the last column as a keyword argument; both resolve to the same camelCase channel on the wire.

Channel (wire) Target Accepts Python / R alias
size node num node_size
color node cat, num, set node_color
shape node cat, num, set -
image node cat -
nodeLabel node cat, num node_label
border node cat, set -
pieSlices node cat, num -
edgeColor edge cat, num edge_color
edgeWidth edge num edge_width
edgeStyle edge cat -
edgeLabel edge cat, num -
hull node cat, set -
contour node cat, set -
heatmap node num -

A source’s target must match the channel’s target: a node source cannot drive an edge channel, and the reverse. A source’s result type must be in the channel’s Accepts list - for example, size and edgeWidth take only num, so binding a category to either does not resolve.

  • num - a numeric value per node or edge. Drives size, edge width, heatmap, or any channel that lists num.
  • cat - a categorical value. Drives color, shape, labels, contours, and hulls.
  • set - a membership set. Drives color, shape, borders, hulls, and contours.
  • field - a value already on the graph. The id is field:<name> for a node attribute or efield:<name> for an edge attribute (see Field ids).
  • algorithm - a value computed in the browser, such as degree or louvain. The id is the bare algorithm id; optional params tune it (for example {"resolution": 1.2} for louvain). An algorithm’s own target and produced type are fixed - see Sources and algorithms for the catalog. Edge algorithms carry "target": "edge".
  • transform - a graph transformation. These live in config.filterStack, not in a visual channel, and produce trf.
  • set - a saved set. A set can anchor nodes or edges; its target is resolved from the channel it is dropped on.

A field id names an attribute by its internal, on-the-wire name:

  • Node attribute team becomes field:team.
  • Edge attribute weight becomes efield:weight.

Most attribute names pass through unchanged. A few names are reserved because the wire format uses them for structure: id on a node; source, target, and key on an edge; and any name beginning with _gph: or @gf:. When your data uses a reserved name, Garphield escapes it to @gf:attr:v1:<encoded> in the node or edge row and records the original name in config.interop.attributeNames, so the field id becomes field:@gf:attr:v1:<encoded>. You rarely write these by hand: discover the exact ids with project.sources() (Python) instead of guessing.

Project.from_networkx() and Project.from_pandas() take the snake_case channel keywords and write the bindings for you, so you do not hand-author the JSON:

import garphield as gph
project = gph.Project.from_networkx(
graph,
node_color="kind", # an existing attribute -> field:kind
node_size=gph.algorithm("degree"), # a computed source
layout="force",
)

from_networkx also accepts a mapping, a callable, or a partition (a list of node sets) for a channel; it materializes those into a node field and binds it. from_pandas binds by column name, an algorithm(...) spec, layout, or pos; for a per-row value, add a column to the frame and bind it by name.

Discover the bindable ids and their types without opening a browser:

for source in project.sources():
print(source.id, source.kind, source.target, source.result_type)
# field:kind field node cat
# efield:weight field edge num
# degree algorithm node num
# ...

Every binding is validated when the Project is built. An unknown channel, a missing field, an unknown algorithm, or a result type the channel does not accept raises BindingError in Python, instead of leaving a dead binding that renders nothing in a browser you cannot see.

See Visual channels for what each channel is for, Sources and algorithms for the algorithm catalog, and The .gph document for the surrounding project shape.