Cytoscape JS Examples

Cytoscape JS examples are node-link graphs, not bar charts. Here are four I actually paste: force, hierarchy, circle, and tap to highlight.

Cytoscape Examples Networks
← All posts
Cytoscape JS Examples

Search Cytoscape JS examples and you'll get biology papers next to a three-node hello-world and not much in between. Cytoscape.js is a graph theory library — nodes, edges, a layout name, interaction events. It doesn't draw bar charts. If that's what you're after, I wrote bar charts explained.

Below are four examples I actually reach for: a cose force layout, a directed breadthfirst pipeline, a circle layout, and tap-to-highlight neighbors. The Cytoscape.js page has a tighter demo with force, circle, and grid side by side. For D3's take on networks, see D3 graph examples.

What these Cytoscape JS examples are

Every example is the same object: a container, an elements list, a stylesheet, a layout. Change the layout name and the picture changes. That's the API.

  • cose. Force-directed. The default when you don't know the shape yet.
  • breadthfirst. A tree or a pipeline. Needs directed edges.
  • circle. Small graphs where you want every node on the ring.
  • Tap. Not a layout. The interaction that makes a graph feel like a tool.

I pick Cytoscape when the product is the graph: pan, tap, filter, a few hundred nodes. I would not wrap D3 force just to ship that. vis.js is the other name I shortlist.

Force layout (cose)

Six services, some edges, cose spreads them out. Drag a node. This is the Cytoscape JS example I start from, then I swap in real ids. Animate is off so the page doesn't wriggle while it settles.

Preview

Code

const cy = cytoscape({
  container: document.getElementById("chart"),
  elements: [
    { data: { id: "App", label: "App" } },
    { data: { id: "API", label: "API" } },
    { data: { id: "DB", label: "DB" } },
    { data: { id: "e1", source: "App", target: "API" } },
    { data: { id: "e2", source: "API", target: "DB" } },
  ],
  style: [
    { selector: "node", style: { "background-color": "#e8b84a", label: "data(label)" } },
    { selector: "edge", style: { width: 2, "line-color": "#5b9fd4" } },
  ],
  layout: { name: "cose", animate: false, padding: 28 },
});

Breadthfirst

A deploy pipeline. Directed edges, directed: true, and breadthfirst puts Git at the top and Prod at the bottom. Use this when the graph has a root and a direction. Force would just make a blob. If the tree is people reporting to people, that's an organization chart in JavaScript, not a deploy pipeline.

Preview

Code

cy.layout({
  name: "breadthfirst",
  directed: true,
  padding: 28,
  spacingFactor: 1.25,
  animate: false,
}).run();

// edges need a direction for this to mean anything
// { data: { id: "e1", source: "Git", target: "Build" } }

Circle

Eight nodes on a ring, a couple of chords so it isn't just a cycle. Circle is honest when the graph is small and you don't want cose to hide a node behind another one. Past ~20 nodes I stop using it.

Preview

Tap to highlight neighbors

Tap a person. Their neighborhood stays, everyone else fades. Tap the background to reset. closedNeighborhood() is the node plus its edges plus its neighbors. That's the selection I want 90% of the time.

Preview

Tap a node. Tap the empty space to clear.

Code

cy.on("tap", "node", (event) => {
  const node = event.target;
  cy.elements().removeClass("highlighted faded");
  node.addClass("highlighted");
  node.neighborhood().addClass("highlighted");
  cy.elements().difference(node.closedNeighborhood()).addClass("faded");
});

cy.on("tap", (event) => {
  if (event.target === cy) cy.elements().removeClass("highlighted faded");
});

Gotchas

  • Height. The container needs a pixel height in CSS. A div with width: 100% and no explicit height is effectively invisible — Cytoscape measures it and draws nothing. This is always the first thing to check when the graph is blank.
  • Edge ids. Give every edge its own id. If you skip it and later try to add a second edge between the same pair of nodes, you'll get confusing behavior that's hard to debug.
  • Layout vs style. Layout determines where nodes sit on screen. Style determines how they look. You can't put a fill color on the layout object and expect it to do anything.
  • Scroll vs zoom. By default the scroll wheel zooms the graph, which makes the page feel broken when embedded in an article. I set userZoomingEnabled: false on embedded examples so the wheel scrolls normally. Turn it back on for an actual app.

Grid layout is on the library page if you just need a table of nodes. Compound nodes (parents that wrap children) are the next step when a flat graph isn't enough. And if the “graph” is really a flow of amounts, that's a sankey, not Cytoscape.

Questions I get

What are Cytoscape JS examples usually showing?

Node-link graphs. Nodes are things — people, servers, concepts — and edges are the relationships between them. You pick a layout (cose, circle, breadthfirst) and Cytoscape places everything. This is not a bar chart or line chart library; if that's what you're after, you want Chart.js or Recharts.

How do I start a Cytoscape.js graph?

The minimal setup is a container element that has a real CSS height, an elements array with your nodes and edges, a style block, and a layout name. Something like cytoscape({ container, elements, style, layout: { name: 'cose' } }) and you'll have a working graph. The tricky part is usually the style — Cytoscape uses its own selector syntax, not CSS.

Why is my Cytoscape graph blank?

The container has no height. This is almost always the answer. Cytoscape measures the container and draws into that space — if the div has height: 0, you get nothing. Set a real height in CSS or inline. The second most common cause is the script running before the container div exists in the DOM.

Should I use Cytoscape.js or D3 for a network?

Cytoscape when the graph is the product — when users need to pan around, tap nodes, filter, and the graph might have a few hundred elements. D3 force is a better fit when you're doing a one-off visualization in SVG and you're already deep in D3 for other things. I wouldn't build a proper graph UI by wrapping D3 force myself when Cytoscape handles all that interaction out of the box.

Do I need cytoscape-cose-bilkent?

Not for these examples — cose ships in the core build and works well for moderate-sized graphs. cose-bilkent is a separate extension that tends to produce cleaner layouts on larger, messier graphs. My advice: start with cose. If the result looks like a tangled knot and nodes are piling up on each other, that's the time to swap in the extension.

Latest posts

All posts