1

How can I toggle visible the Sankey link (together with the node and label)? I want users to expand nodes step by step by clicking on the node. The diagram would have ca 5 levels and ca 10 columns when fully expanded. Default view on the first load is showing about 6 columns and 4 levels.

  1. I could manipulate the data and set the weight to 0 to hide all 3 of them (node,link,label).
  2. I could add a className to the node and use 'display:none' (Would it work for all 3 of them?)
  3. Here is a similar question about organization chart. Can I adapt the solution to Sankey?

I've tried out the 1st option. It works well - hiding all 3 of them(node,link,label). Though, to make it to work, I need to query the database every time and redraw (reload) the chart. I'm doing API call and manipulating the json. Isn't it too many API calls or there is a better way to do it?

The 2nd option looks more clear compared to the 3rd, because I know more CSS than highcharts.js. (Though I tend to avoid the cascading styles:)

The 3rd option seems tedious, because I need to find out how these libraries are working. But maybe it's a good solution, then I have no doubts about investing time. Though, the given example was not very well working.

What would be the best solution to avoid problems with dev and customisation, functionalities, export.js, responsive design, etc?

Here is the fiddle of the desired view : link

var nodes = [{
    id: 'Col_1-Row_1',
    column: 1
  }, ],
  data0 = [
    // default - data is set to 0 - link is hidden
    ['Col_0-Row_0', 'Col_1-Row_0', 0],
    ['Col_0-Row_1', 'Col_1-Row_0', 0],
    // data to display
    ['Col_1-Row_0', 'Col_2-Row_0', 153],
    ['Col_1-Row_1', 'Col_2-Row_0', 91],
    ['Col_1-Row_1', 'Col_2-Row_0', 221],
    ['Col_1-Row_1', 'Col_2-Row_0', 200],
    //  circulra link
    ['Col_2-Row_0', 'Col_1-Row_1', 10],
  ],
  data1 = [
    ['Col_0-Row_0', 'Col_1-Row_0', 0.1],
    ['Col_0-Row_1', 'Col_1-Row_0', 152.9],
    ['Col_1-Row_0', 'Col_2-Row_0', 153],
    ['Col_1-Row_1', 'Col_2-Row_0', 91],
    ['Col_1-Row_1', 'Col_2-Row_0', 221],
    ['Col_1-Row_1', 'Col_2-Row_0', 200],
    ['Col_2-Row_0', 'Col_1-Row_1', 10],
  ]

const chart = Highcharts.chart('container', {
  chart: {

    height: (9 / 16 * 80) + "%",
    marginBottom: 60, // display circulra link
    marginRight: 60 // display circulra link
  },
  title: {
    text: 'Sankey toggle link visibilty'
  },
  plotOptions: {
    series: {
      animation: false,
      minLinkWidth: 1,
      nodePadding: 50,
      colors: ['#0dcaf0'],
      clip: false, // display circulra link
      dataLabels: {
        enabled: true,

        // set data label position
        align: "left",
        verticalAlign: "top",
        y: -20,
        x: -5,

        // show data labels taht overlap
        allowOverlap: true,
        padding: 0,

        // handle data labels that flow outside the plot area
        overflow: "allow",
        crop: false,

        style: {
          fontSize: "12px",
          fontFamily: "Arial, sans-serif",
          color: "black",
        },
      },
    },
  },
  series: [{
    data: data0,
    nodes: nodes,
    type: 'sankey',
  }, {
    data: data1,
    nodes: nodes,
    visible: false,
    type: 'sankey',
  }]
});
#container {
  height: 90hw;
  margin: 1em auto;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/sankey.src.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<button id="btn_show" class="autocompare">expand</button>
<button id="btn_hide" class="autocompare">hide</button>
<div id="container"></div>


<script>
  document.getElementById('btn_show').addEventListener('click', e => {
    seriesHide();
    seriesShow(1);
  });
  document.getElementById('btn_hide').addEventListener('click', e => {
    seriesHide();
    seriesShow(0);
  });

  function seriesHide() {
    chart.series.forEach(ser => ser.hide())
  }

  function seriesShow(i) {
    var series = chart.series[i];
    series.show();
  }
</script>
Vikero
  • 13
  • 5

1 Answers1

0

I prepared a demo based on a post from SO, hiding branches seems to be a good approach.

Highcharts.chart('container', {
  chart: {
    events: {
      load() {
        //hide nodes after initial load
        let chart = this,
          nodes = chart.series[0].nodeLookup;

        for (let i in nodes) {
          if (nodes[i].column > 1) {
            nodes[i].graphic.hide();
            nodes[i].dataLabel.hide();
            nodes[i].linksTo[0].graphic.hide();
            nodes[i].visible = false;
          }
        }
      }
    }
  },
  title: {
    text: 'Highcharts Sankey Diagram'
  },
  accessibility: {
    point: {
      valueDescriptionFormat: '{index}. {point.from} to {point.to}, {point.weight}.'
    }
  },
  series: [{
    keys: ['from', 'to', 'weight'],
    data: [
      ['Brazil', 'Portugal', 5],
      ['Brazil', 'France', 1],
      ['Brazil', 'Spain', 1],
      ['Brazil', 'England', 1],
      ['Canada', 'Portugal', 1],
      ['Canada', 'France', 5],
      ['Canada', 'England', 1],
      ['Mexico', 'Portugal', 1],
      ['Mexico', 'France', 1],
      ['Mexico', 'Spain', 5],
      ['Mexico', 'England', 1],
      ['USA', 'Portugal', 1],
      ['USA', 'France', 1],
      ['USA', 'Spain', 1],
      ['USA', 'England', 5],
      ['Portugal', 'Angola', 2],
      ['Portugal', 'Senegal', 1],
      ['Portugal', 'Morocco', 1],
      ['Portugal', 'South Africa', 3],
    ],
    type: 'sankey',
    name: 'Sankey demo series',
    nodes: [{
      id: 'Brazil',
    }, {
      id: 'Portugal',
      events: {
        click() {
          //show nodes
          let series = this.series,
            nodes = series.nodeLookup;

          for (let i in nodes) {
            if (nodes[i].id === "Portugal") {
              if (nodes[i].visible) {
                nodes[i].graphic.hide()
                nodes[i].dataLabel.hide();
                nodes[i].visible = false;
              } else {
                nodes[i].graphic.show()
                nodes[i].dataLabel.show();
                nodes[i].visible = true;
              }

            }
          }
          this.linksFrom.forEach(link => {
            if (link.graphic.visibility == "visible") {
              link.graphic.hide()

            } else {
              link.graphic.show()
            }
          })
        }
      }
    }, {
      id: 'Mexico',
    }, {
      id: 'France',
    }],
  }]

});
#csv {
    display: none;
}

.highcharts-figure,
.highcharts-data-table table {
    min-width: 310px;
    max-width: 800px;
    margin: 1em auto;
}

.highcharts-data-table table {
    font-family: Verdana, sans-serif;
    border-collapse: collapse;
    border: 1px solid #ebebeb;
    margin: 10px auto;
    text-align: center;
    width: 100%;
    max-width: 500px;
}

.highcharts-data-table caption {
    padding: 1em 0;
    font-size: 1.2em;
    color: #555;
}

.highcharts-data-table th {
    font-weight: 600;
    padding: 0.5em;
}

.highcharts-data-table td,
.highcharts-data-table th,
.highcharts-data-table caption {
    padding: 0.5em;
}

.highcharts-data-table thead tr,
.highcharts-data-table tr:nth-child(even) {
    background: #f8f8f8;
}

.highcharts-data-table tr:hover {
    background: #f1f7ff;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/sankey.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<figure class="highcharts-figure">
    <div id="container"></div>
    <p class="highcharts-description">
        Sankey charts are used to visualize data flow and volume
        between nodes. The wider lines indicate larger volumes.
    </p>
</figure>

Demo: https://jsfiddle.net/BlackLabel/sm01jtof/1/

EDIT

Updated demo to show/hide nodes in sankey graph using update method.

Demo: https://jsfiddle.net/BlackLabel/80ruyxdq/4/

Sebastian Hajdus
  • 1,422
  • 1
  • 5
  • 14
  • Small issue to fix with links. After setting the 'links.show()', the 'link.graphic.visibility' is set to 'inherit'. I guess the fix would be to change the condition check and use 'hidden' instead of the 'visible' `if (link.graphic.visibility == "hidden"){...}` – Vikero Jun 09 '22 at 15:16
  • How to assure that all descendent nodes are hidden together with the parent? Do we have an option to get all the descendants of the node? I guess I could give the className to all descendants and check it together with column. – Vikero Jun 09 '22 at 15:32
  • I slightly changed the setting to hide and show nodes on the sankey chart --> [example](https://jsfiddle.net/BlackLabel/sm01jtof/3/). – Sebastian Hajdus Jun 10 '22 at 09:55
  • Thanks, you nailed it! Like that it is much better. This is all what I needed to go on with dev. – Vikero Jun 10 '22 at 11:10
  • There is a problem with the window resize (on the web browser and also jsFiddle). Hidden link becomes visible when changing the size. And when I drag from laptop to an external screen, then on top of that the node.graphics and node.label disappear. How can I fix it please? – Vikero Jun 10 '22 at 13:37
  • I used the [update](https://api.highcharts.com/class-reference/Highcharts.Point#update) method to hide the node, I change it by setting the color to transparent and update the color from the array. [example](https://jsfiddle.net/BlackLabel/80ruyxdq/2/) – Sebastian Hajdus Jun 13 '22 at 15:34
  • I can't hide links with update when node is in the last column. I can hide with linksTo, but then I have the resize problem. Could you suggest a solution? Please see my [fiddle](https://jsfiddle.net/Vikero/L3uvkfgn/) – Vikero Jun 16 '22 at 16:45
  • Problems when resizing accrues when changing graphic. Update is a more complex option for changing because includes redrawing the graph. – Sebastian Hajdus Jun 17 '22 at 12:14
  • Do you mean that the update is the right way to do it? Or I can use the previous method and get the same result? Could you have a look at the [fiddle](https://jsfiddle.net/Vikero/L3uvkfgn/) please. The problem is with links from Mexico to Angola. How can I apply the update method to these links? I want to click on Mexico and hide the link to Angola. Thanks! – Vikero Jun 17 '22 at 13:20
  • Updated demo to show/hide nodes in sankey graph using update method. https://jsfiddle.net/BlackLabel/80ruyxdq/4/ – Sebastian Hajdus Jun 17 '22 at 16:20