ChatGPT: Render a sankey diagram using SVG

Note: I tried testing ChatGPT to produce more complex code! But this one failed miserably. Read on.


Rendering a Sankey diagram in React using SVG can be a complex task as it involves creating paths and managing node positions. There are libraries available that simplify the process, such as react-sankey or d3-sankey. However, if you prefer to implement it manually, here’s an example code snippet to get you started:

import React from 'react';

const SankeyDiagram = ({ data, width, height }) => {
  const { nodes, links } = data;

  const nodeWidth = 20;
  const nodePadding = 8;

  const maxLinkValue = Math.max(...links.map(link => link.value));
  const linkScale = width / maxLinkValue;

  const getNodeX = node => {
    return node.index * (nodeWidth + nodePadding);
  };

  const getNodeY = node => {
    return height / 2 - node.value / 2;
  };

  const renderNode = node => {
    const x = getNodeX(node);
    const y = getNodeY(node);

    return (
      <rect
        key={node.id}
        x={x}
        y={y}
        width={nodeWidth}
        height={node.value}
        fill={node.color}
      />
    );
  };

  const renderLink = link => {
    const x1 = getNodeX(link.source) + nodeWidth;
    const y1 = getNodeY(link.source) + link.sy + link.dy / 2;
    const x2 = getNodeX(link.target);
    const y2 = getNodeY(link.target) + link.ty + link.dy / 2;

    return (
      <path
        key={`${link.source.id}-${link.target.id}`}
        d={`M ${x1},${y1} L ${x2},${y2}`}
        stroke={link.color}
        strokeWidth={link.value * linkScale}
        fill="none"
      />
    );
  };

  return (
    <svg width={width} height={height}>
      {nodes.map(renderNode)}
      {links.map(renderLink)}
    </svg>
  );
};

export default SankeyDiagram;

In this code, the SankeyDiagram component receives the following props:

  • data: An object containing an array of nodes and an array of links. Each node has an id, value, and color. Each link has source, target, value, and color.
  • width: The width of the chart in pixels.
  • height: The height of the chart in pixels.

The component calculates the necessary dimensions for each node and link based on the provided props. It then maps over the nodes array to generate SVG rect elements for each node. The renderNode function calculates the position and dimensions of each node based on the index and value.

The component also maps over the links array to generate SVG path elements for each link. The renderLink function calculates the positions of the source and target nodes and sets the stroke width of the path based on the link value.

Finally, the component renders an SVG element with the specified width and height. It renders the nodes and links using the nodes.map and links.map functions respectively.

To use the SankeyDiagram component, provide the appropriate data, width, and height as props. For example:

import React from 'react';
import SankeyDiagram from './SankeyDiagram';

const App = () => {
  const data = {
    nodes: [
      { id: 'A', value: 100, color: 'steelblue' },
      { id: 'B', value: 200, color: 'orange' },
      { id: 'C', value: 150, color: 'green' },
    ],
    links: [
      { source: 'A', target: 'B', value: 50, color: 'gray' },
      { source: 'B', target: 'C', value: 100, color: 'gray' },
      { source: 'A', target: 'C', value: 75, color: 'gray' },
    ],
  };

  return (
    <div>
      <h1>Sankey Diagram Example</h1>
      <SankeyDiagram data={data} width={500} height={300} />
    </div>
  );
};

export default App;

In this example, we provide an object with an array of nodes and an array of links to the data prop of the SankeyDiagram component. Adjust the values and colors to match your specific data.


On running this code in CodeSandbox, I get this image!

Clearly, this image is wrong. So, where is the code wrong?

In the below code, node does not have an index

const getNodeX = node => {
    return node.index * (nodeWidth + nodePadding);
  };

In the renderLink fn, there is no “sy”, “dy”, “ty”. link.source, link.target does not refer to a node.

const renderLink = link => {
    const x1 = getNodeX(link.source) + nodeWidth;
    const y1 = getNodeY(link.source) + link.sy + link.dy / 2;
    const x2 = getNodeX(link.target);
    const y2 = getNodeY(link.target) + link.ty + link.dy / 2;

    return (
      <path
        key={`${link.source.id}-${link.target.id}`}
        d={`M ${x1},${y1} L ${x2},${y2}`}
        stroke={link.color}
        strokeWidth={link.value * linkScale}
        fill="none"
      />
    );
  };

Even after correcting those errors in CodeSandbox, I still get a bad sankey diagram

Sankey diagrams are difficult to do in React because of lack of library options. Here is an example of a good sankey diagram, if you have not seen one.



After finding the mistakes in ChatGPT generated code, I am happy that my job is safe from GPT code for the next 10 years.

Related Posts

Leave a Reply

Your email address will not be published.