---
title: "Fishbone Layout"
description: "Fishbone Layout"
language: "en"
canonical: "https://g6.antv.antgroup.com/en/manual/layout/Fishbone/"
version: "5.1.1"
---

## Overview

Fishbone layout is a graphical layout specifically designed for representing hierarchical data. By simulating the shape of a fishbone, it arranges data nodes according to their hierarchy, making the hierarchical relationships of the data clearer and more intuitive. Fishbone layout is especially suitable for datasets that need to show causality, hierarchy, or classification information.

## Use Cases

- Displaying hierarchical data, such as organizational structures or classification systems
- Showing problem analysis processes, such as fault analysis or quality analysis
- Displaying decision processes, such as decision trees or factor analysis

## Online Demo



```ts
import { createGraph } from '/demo-runtime.ts';

createGraph(
  {
    data: {
      nodes: [
        {
          id: 'Quality',
          depth: 0,
          children: ['Machine', 'Method', 'Material', 'Man Power', 'Measurement', 'Milieu'],
        },
        {
          id: 'Machine',
          depth: 1,
          children: ['Mill', 'Mixer', 'Metal Lathe'],
        },
        {
          id: 'Mill',
          depth: 2,
        },
        {
          id: 'Mixer',
          depth: 2,
        },
        {
          id: 'Metal Lathe',
          depth: 2,
          children: ['Milling'],
        },
        {
          id: 'Milling',
          depth: 3,
        },
        {
          id: 'Method',
          depth: 1,
        },
        {
          id: 'Material',
          depth: 1,
          children: ['Masonite', 'Marscapone', 'Meat'],
        },
        {
          id: 'Masonite',
          depth: 2,
          children: ['spearMint', 'pepperMint', 'test1'],
        },
        {
          id: 'spearMint',
          depth: 3,
        },
        {
          id: 'pepperMint',
          depth: 3,
          children: ['test3'],
        },
        {
          id: 'test3',
          depth: 4,
        },
        {
          id: 'test1',
          depth: 3,
          children: ['test4'],
        },
        {
          id: 'test4',
          depth: 4,
        },
        {
          id: 'Marscapone',
          depth: 2,
          children: ['Malty', 'Minty'],
        },
        {
          id: 'Malty',
          depth: 3,
        },
        {
          id: 'Minty',
          depth: 3,
        },
        {
          id: 'Meat',
          depth: 2,
          children: ['Mutton'],
        },
        {
          id: 'Mutton',
          depth: 3,
        },
        {
          id: 'Man Power',
          depth: 1,
          children: ['Manager', "Master's Student", 'Magician', 'Miner', 'Magister', 'Massage Artist'],
        },
        {
          id: 'Manager',
          depth: 2,
        },
        {
          id: "Master's Student",
          depth: 2,
        },
        {
          id: 'Magician',
          depth: 2,
        },
        {
          id: 'Miner',
          depth: 2,
        },
        {
          id: 'Magister',
          depth: 2,
          children: ['Malpractice'],
        },
        {
          id: 'Malpractice',
          depth: 3,
        },
        {
          id: 'Massage Artist',
          depth: 2,
          children: ['Masseur', 'Masseuse'],
        },
        {
          id: 'Masseur',
          depth: 3,
        },
        {
          id: 'Masseuse',
          depth: 3,
        },
        {
          id: 'Measurement',
          depth: 1,
          children: ['Malleability'],
        },
        {
          id: 'Malleability',
          depth: 2,
        },
        {
          id: 'Milieu',
          depth: 1,
          children: ['Marine'],
        },
        {
          id: 'Marine',
          depth: 2,
        },
      ],
      edges: [
        {
          source: 'Quality',
          target: 'Machine',
        },
        {
          source: 'Quality',
          target: 'Method',
        },
        {
          source: 'Quality',
          target: 'Material',
        },
        {
          source: 'Quality',
          target: 'Man Power',
        },
        {
          source: 'Quality',
          target: 'Measurement',
        },
        {
          source: 'Quality',
          target: 'Milieu',
        },
        {
          source: 'Machine',
          target: 'Mill',
        },
        {
          source: 'Machine',
          target: 'Mixer',
        },
        {
          source: 'Machine',
          target: 'Metal Lathe',
        },
        {
          source: 'Metal Lathe',
          target: 'Milling',
        },
        {
          source: 'Material',
          target: 'Masonite',
        },
        {
          source: 'Material',
          target: 'Marscapone',
        },
        {
          source: 'Material',
          target: 'Meat',
        },
        {
          source: 'Masonite',
          target: 'spearMint',
        },
        {
          source: 'Masonite',
          target: 'pepperMint',
        },
        {
          source: 'Masonite',
          target: 'test1',
        },
        {
          source: 'pepperMint',
          target: 'test3',
        },
        {
          source: 'test1',
          target: 'test4',
        },
        {
          source: 'Marscapone',
          target: 'Malty',
        },
        {
          source: 'Marscapone',
          target: 'Minty',
        },
        {
          source: 'Meat',
          target: 'Mutton',
        },
        {
          source: 'Man Power',
          target: 'Manager',
        },
        {
          source: 'Man Power',
          target: "Master's Student",
        },
        {
          source: 'Man Power',
          target: 'Magician',
        },
        {
          source: 'Man Power',
          target: 'Miner',
        },
        {
          source: 'Man Power',
          target: 'Magister',
        },
        {
          source: 'Man Power',
          target: 'Massage Artist',
        },
        {
          source: 'Magister',
          target: 'Malpractice',
        },
        {
          source: 'Massage Artist',
          target: 'Masseur',
        },
        {
          source: 'Massage Artist',
          target: 'Masseuse',
        },
        {
          source: 'Measurement',
          target: 'Malleability',
        },
        {
          source: 'Milieu',
          target: 'Marine',
        },
      ],
    },
    node: {
      type: 'rect',
      style: {
        size: [32, 32],
        // fill: () => randomColor(),
        label: false,
        labelFill: '#262626',
        labelFontFamily: 'Gill Sans',
        labelMaxLines: 2,
        labelMaxWidth: '100%',
        labelPlacement: 'center',
        labelText: (d) => d.id,
        labelWordWrap: true,
      },
    },
    edge: {
      type: 'polyline',
      style: {
        lineWidth: 3,
      },
    },
    behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element'],
    autoFit: 'view',
    layout: {
      type: 'fishbone',
      direction: 'RL',
      hGap: 50,
      vGap: 50,
      getRibSep: () => 60,
    },
  },
  { width: 600, height: 400 },
  (gui, graph) => {
    const options = {
      type: 'fishbone',
      direction: 'RL',
      hGap: 50,
      vGap: 50,
      getRibSep: 60,
    };

    const optionFolder = gui.addFolder('Fishbone Layout Options');
    optionFolder.add(options, 'type').disable(true);
    optionFolder.add(options, 'direction', ['RL', 'LR']);
    optionFolder.add(options, 'hGap', 20, 100, 10);
    optionFolder.add(options, 'vGap', 20, 100, 10);
    optionFolder.add(options, 'getRibSep', 30, 100, 10);

    optionFolder.onChange(async ({ property, value }) => {
      graph.setLayout(
        Object.assign({}, graph.getLayout(), {
          [property]: property === 'getRibSep' ? () => value : value,
        }),
      );
      await graph.layout();
      // 调整 direction 后部分node可能会溢出屏幕，重新执行下fitView
      if (property === 'direction') {
        graph.fitView();
      }
    });
  },
);
```



## Basic Usage

```js
const graph = new Graph({
  layout: {
    type: 'fishbone',
    direction: 'LR',
    hGap: 50,
    vGap: 50,
    getRibSep: () => 60,
  },
});
```

## Options

| Property               | Description                                                                                      | Type                                                                                                                                   | Default  | Required |
| ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------- |
| type                   | Layout type                                                                                      | `fishbone`                                                                                                                             | -        | ✓        |
| direction              | Layout direction, `RL` (right to left, head on right), `LR` (left to right, head on left)        | `RL` \| `LR`                                                                                                                           | `RL`     |          |
| hGap                   | Horizontal gap                                                                                   | number                                                                                                                                 | -        |          |
| vGap                   | Vertical gap                                                                                     | number                                                                                                                                 | -        |          |
| getRibSep              | Function to get rib gap                                                                          | (node: NodeData) => number                                                                                                             | () => 60 |          |
| width                  | Layout width                                                                                     | number                                                                                                                                 | -        |          |
| height                 | Layout height                                                                                    | number                                                                                                                                 | -        |          |
| nodeSize               | Node size                                                                                        | number \| [number, number] \| [number, number, number] \| ((node: NodeData) => number \| [number, number] \| [number, number, number]) | -        |          |
| isLayoutInvisibleNodes | Whether invisible nodes participate in layout (effective when preLayout is true)                 | boolean                                                                                                                                | -        |          |
| nodeFilter             | Nodes to participate in this layout                                                              | (node: NodeData) => boolean                                                                                                            | -        |          |
| preLayout              | Use pre-layout, calculate layout before initializing elements (not suitable for pipeline layout) | boolean                                                                                                                                | -        |          |

## Code Example

### Basic Usage

The simplest configuration:

```js
import { Graph, treeToGraphData } from '@antv/g6';

const graph = new Graph({
  layout: {
    type: 'fishbone',
  },
  autoFit: 'view',
  data: treeToGraphData({
    nodes: [
      { id: 'root', data: { label: 'Root' } },
      { id: 'child1', data: { label: 'Child 1' } },
      { id: 'child2', data: { label: 'Child 2' } },
      { id: 'child3', data: { label: 'Child 3' } },
    ],
    edges: [
      { id: 'e1', source: 'root', target: 'child1' },
      { id: 'e2', source: 'root', target: 'child2' },
      { id: 'e3', source: 'root', target: 'child3' },
    ],
  }),
  edge: {
    type: 'polyline',
    style: {
      lineWidth: 3,
    },
  },
  behaviors: ['drag-canvas'],
});
```

Result:



```ts

import { Graph } from '@antv/g6';

const graph = new Graph({
  container: 'container',
  width: 600,
  height: 400,
  layout: {
    type: 'fishbone',
  },
  autoFit: 'view',
  data: {
    nodes: [
      {
        id: 'Quality',
        depth: 0,
        children: ['Machine', 'Method', 'Material', 'Man Power', 'Measurement', 'Milieu'],
      },
      {
        id: 'Machine',
        depth: 1,
        children: ['Mill', 'Mixer', 'Metal Lathe'],
      },
      {
        id: 'Mill',
        depth: 2,
      },
      {
        id: 'Mixer',
        depth: 2,
      },
      {
        id: 'Metal Lathe',
        depth: 2,
        children: ['Milling'],
      },
      {
        id: 'Milling',
        depth: 3,
      },
      {
        id: 'Method',
        depth: 1,
      },
      {
        id: 'Material',
        depth: 1,
        children: ['Masonite', 'Marscapone', 'Meat'],
      },
      {
        id: 'Masonite',
        depth: 2,
        children: ['spearMint', 'pepperMint', 'test1'],
      },
      {
        id: 'spearMint',
        depth: 3,
      },
      {
        id: 'pepperMint',
        depth: 3,
        children: ['test3'],
      },
      {
        id: 'test3',
        depth: 4,
      },
      {
        id: 'test1',
        depth: 3,
        children: ['test4'],
      },
      {
        id: 'test4',
        depth: 4,
      },
      {
        id: 'Marscapone',
        depth: 2,
        children: ['Malty', 'Minty'],
      },
      {
        id: 'Malty',
        depth: 3,
      },
      {
        id: 'Minty',
        depth: 3,
      },
      {
        id: 'Meat',
        depth: 2,
        children: ['Mutton'],
      },
      {
        id: 'Mutton',
        depth: 3,
      },
      {
        id: 'Man Power',
        depth: 1,
        children: ['Manager', "Master's Student", 'Magician', 'Miner', 'Magister', 'Massage Artist'],
      },
      {
        id: 'Manager',
        depth: 2,
      },
      {
        id: "Master's Student",
        depth: 2,
      },
      {
        id: 'Magician',
        depth: 2,
      },
      {
        id: 'Miner',
        depth: 2,
      },
      {
        id: 'Magister',
        depth: 2,
        children: ['Malpractice'],
      },
      {
        id: 'Malpractice',
        depth: 3,
      },
      {
        id: 'Massage Artist',
        depth: 2,
        children: ['Masseur', 'Masseuse'],
      },
      {
        id: 'Masseur',
        depth: 3,
      },
      {
        id: 'Masseuse',
        depth: 3,
      },
      {
        id: 'Measurement',
        depth: 1,
        children: ['Malleability'],
      },
      {
        id: 'Malleability',
        depth: 2,
      },
      {
        id: 'Milieu',
        depth: 1,
        children: ['Marine'],
      },
      {
        id: 'Marine',
        depth: 2,
      },
    ],
    edges: [
      {
        source: 'Quality',
        target: 'Machine',
      },
      {
        source: 'Quality',
        target: 'Method',
      },
      {
        source: 'Quality',
        target: 'Material',
      },
      {
        source: 'Quality',
        target: 'Man Power',
      },
      {
        source: 'Quality',
        target: 'Measurement',
      },
      {
        source: 'Quality',
        target: 'Milieu',
      },
      {
        source: 'Machine',
        target: 'Mill',
      },
      {
        source: 'Machine',
        target: 'Mixer',
      },
      {
        source: 'Machine',
        target: 'Metal Lathe',
      },
      {
        source: 'Metal Lathe',
        target: 'Milling',
      },
      {
        source: 'Material',
        target: 'Masonite',
      },
      {
        source: 'Material',
        target: 'Marscapone',
      },
      {
        source: 'Material',
        target: 'Meat',
      },
      {
        source: 'Masonite',
        target: 'spearMint',
      },
      {
        source: 'Masonite',
        target: 'pepperMint',
      },
      {
        source: 'Masonite',
        target: 'test1',
      },
      {
        source: 'pepperMint',
        target: 'test3',
      },
      {
        source: 'test1',
        target: 'test4',
      },
      {
        source: 'Marscapone',
        target: 'Malty',
      },
      {
        source: 'Marscapone',
        target: 'Minty',
      },
      {
        source: 'Meat',
        target: 'Mutton',
      },
      {
        source: 'Man Power',
        target: 'Manager',
      },
      {
        source: 'Man Power',
        target: "Master's Student",
      },
      {
        source: 'Man Power',
        target: 'Magician',
      },
      {
        source: 'Man Power',
        target: 'Miner',
      },
      {
        source: 'Man Power',
        target: 'Magister',
      },
      {
        source: 'Man Power',
        target: 'Massage Artist',
      },
      {
        source: 'Magister',
        target: 'Malpractice',
      },
      {
        source: 'Massage Artist',
        target: 'Masseur',
      },
      {
        source: 'Massage Artist',
        target: 'Masseuse',
      },
      {
        source: 'Measurement',
        target: 'Malleability',
      },
      {
        source: 'Milieu',
        target: 'Marine',
      },
    ],
  },
  edge: {
    type: 'polyline',
    style: {
      lineWidth: 3,
    },
  },
  behaviors: ['drag-canvas'],
});

graph.render();
```


## Real Case



```ts

import { Graph, treeToGraphData } from '@antv/g6';

const data = {
  id: 'Quality',
  children: [
    {
      id: 'Machine',
      children: [{ id: 'Mill' }, { id: 'Mixer' }, { id: 'Metal Lathe', children: [{ id: 'Milling' }] }],
    },
    { id: 'Method' },
    {
      id: 'Material',
      children: [
        {
          id: 'Masonite',
          children: [
            { id: 'spearMint' },
            { id: 'pepperMint', children: [{ id: 'test3' }] },
            { id: 'test1', children: [{ id: 'test4' }] },
          ],
        },
        {
          id: 'Marscapone',
          children: [{ id: 'Malty' }, { id: 'Minty' }],
        },
        { id: 'Meat', children: [{ id: 'Mutton' }] },
      ],
    },
    {
      id: 'Man Power',
      children: [
        { id: 'Manager' },
        { id: "Master's Student" },
        { id: 'Magician' },
        { id: 'Miner' },
        { id: 'Magister', children: [{ id: 'Malpractice' }] },
        {
          id: 'Massage Artist',
          children: [{ id: 'Masseur' }, { id: 'Masseuse' }],
        },
      ],
    },
    {
      id: 'Measurement',
      children: [{ id: 'Malleability' }],
    },
    {
      id: 'Milieu',
      children: [{ id: 'Marine' }],
    },
  ],
};

export const layoutFishbone = async (context) => {
  const graph = new Graph({
    ...context,
    container: 'container',
    autoFit: 'view',
    data: treeToGraphData(data),
    node: {
      type: 'rect',
      style: {
        size: [32, 32],
        // fill: () => randomColor(),
        label: false,
        labelFill: '#262626',
        labelFontFamily: 'Gill Sans',
        labelMaxLines: 2,
        labelMaxWidth: '100%',
        labelPlacement: 'center',
        labelText: (d) => d.id,
        labelWordWrap: true,
      },
    },
    edge: {
      type: 'polyline',
      style: {
        lineWidth: 3,
      },
    },
    layout: {
      type: 'fishbone',
      vGap: 48,
      hGap: 48,
      direction: 'RL',
    },
    behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element'],
    animation: false,
  });

  await graph.render();

  layoutFishbone.form = (panel) => {
    const config = {
      type: 'fishbone',
      direction: 'RL',
    };

    return [
      panel
        .add(config, 'direction', ['LR', 'RL'])
        .name('Direction')
        .onChange((value) => {
          graph.setLayout((prev) => ({ ...prev, direction: value }));
          graph.render();
        }),
    ];
  };

  return graph;
};

layoutFishbone();
```


- [Fishbone Layout](/en/examples/layout/fishbone/basic/)
### demo-runtime.ts

```ts
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';

export function addPanel(renderPanel: (gui: GUI) => void) {
  const gui = new GUI({ container: document.body });
  gui.title('Control');
  Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
  renderPanel(gui);
  addEventListener('pagehide', () => gui.destroy(), { once: true });
}

export async function createGraph(
  options: ConstructorParameters<typeof Graph>[0],
  size: { width?: number; height?: number } = {},
  renderPanel?: (gui: GUI, graph: Graph) => void,
) {
  const container = document.createElement('div');
  Object.assign(container.style, {
    width: '100%',
    maxWidth: `${size.width || 600}px`,
    height: `${size.height || 400}px`,
  });
  document.getElementById('container')!.append(container);
  const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
  addEventListener('pagehide', () => graph.destroy(), { once: true });
  await graph.render();
  if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
  return container;
}
```
