javascriptplotlyplotly.js

Plotly.js bar add secondary text for x-axis bars


I am trying to implement the following chart

enter image description here

I tried the following:

data: Plotly.Data[] = [
    {
      type: 'bar',
      x: ['GHS 1', 'GHS 2', 'GHS 3', 'GHS 4', 'GHS 5'],
      y: [3, 4, 20, 15, 6],
      width: 0.7,
      marker: {
        color: [
          '#FF0000',
          '#FFB340',
          '#FFD940',
          '#95BC28',
          '#009933'
        ]
      }
    }
];

layout = {
    yaxis: {
      showgrid: false,
      showline: true,
      showticklabels: false,
      automargin: true,
      title: {
        text: 'Class Probability',
        standoff: 0
      }
    },
    xaxis: {
    },
    font: { size: 16 },
    width: '100%',
    height: '100%'
  };

Output:

enter image description here

How can I add a secondary text under each x-axis bar?


Solution

  • Plotly allows to use <br> tags for the labels that are set in x. Each label has its corresponding <text> element in the DOM, given the string 'a <br> b', it will create 2 <tspan> (subtext) elements for each part 'a' and 'b', which allows to create CSS rules for each distinct part (ie. so we can adjust the font size for the secondary text) :

    .xaxislayer-above .xtick text tspan:not(:first-child) {
      font-size: 13px;
    }
    
    const x = ['GHS 1', 'GHS 2', 'GHS 3', 'GHS 4', 'GHS 5'];
    
    const range = ['< 5', '5-50', '50-300', '300-2000', '> 2000'];
    const unit = 'mg/kg';
    
    const xlabels = x.map((xi, i) => `${xi}<br><br>ALD ${range[i]}<br>${unit}`);
    

    You can assign xlabels to x data directly. Or you can keep them (x's) "clean" and assign the full labels as ticktext in the layout :

      xaxis: {
        tickmode: 'array',
        tickvals: x,
        ticktext: xlabels
      }
    

    screenshot

    Note that it will also override the xs in the hover data (even the second method, which is thus less useful than expected..). You will probably need to set hoverinfo: 'text' and define a custom array in hovertext (or use hovertemplate).