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.
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
divwithwidth: 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: falseon 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.