Search code examples
highchartsarea-chart

Highcharts Issues filling the overlapping parts in Area charts for non-monotonic data


Highcharts.chart('container', {
  chart: {
    type: 'area'
  },
  plotOptions: {
    series: {
      connectNulls: false,
      // stacking: 'normal'
    }
  },
  
  series: [{
    fillOpacity: 0.75,
    data: [
      { x: 0, y: 29.9 },
      { x: 1, y: 71.5 },
      { x: 3, y: null },
      { x: 4.3, y: 129.2, color: 'red' },
      { x: null, y: null },
      { x: null, y: null },
      { x: 8, y: 216.0, color: 'yellow' },
      { x: 9, y: 135.6, color: 'purple' },
      { x: 7.2, y: 148.5, color: 'lime' },
      { x: 12, y: 216.4 },
      { x: 14, y: 194.1 }
    ]
  }]
});
<script src="https://code.highcharts.com/highcharts.js"></script>

<div id="container"></div>

I have troubles plotting the Highcharts area charts having non-monotonic data.

In given example, I would like to see:

  • the red area filled with blue color as well
  • the black-striped area possibly suggesting overlapping of multiple blue areas (using opacity or somewhat similar approach)

It looks like the Highcharts are using even-odd filling rule or something similar, but I cannot determine or find something about it in the manual.

enter image description here


Solution

  • You're running into a common limitation of Highcharts: it does not guarantee the proper display of data that isn't sorted by X-axis value.

    The easiest way I know of to achieve the visual effect you're looking for is to have multiple series defined, all sorted by X-axis value, but covering the appropriate combined area.

    Processing your raw data into multiple series is your responsibility as the Highcharts caller, but loosely speaking, I'd recommend the following structure:

    1. Split your raw data into monotonic increasing/decreasing segments, with overlapping boundary values.

      In your example, the series [0, 1, 3, 4.3, 8, 9, 7.2, 12, 14] becomes [0, 1, 3, 4.3, 8, 9], [9, 7.2], [7.2, 12, 14].

    2. For the decreasing segments, reverse their order to adhere to Highcharts' ordering requirements.

    3. Optionally, set the visibility of certain boundary points so that you don't render duplicate tooltips (or legend items) in the final chart.

    A demonstration of a potential result chart is below (omitting step 3 above):

    Highcharts.chart('container', {
      chart: {
        type: 'area'
      },
      plotOptions: {
        series: {
          connectNulls: false,
          color: '#2caffe'
        }
      },
      
      series: [{
        fillOpacity: 0.75,
        data: [
          { x: 0, y: 29.9 },
          { x: 1, y: 71.5 },
          { x: 3, y: null },
          { x: 4.3, y: 129.2, color: 'red' },
          { x: 5, y: null },
          { x: 8, y: 216.0, color: 'yellow' },
          { x: 9, y: 135.6, color: 'purple' },
        ]
      },{
        fillOpacity: 0.75,
        data: [
          { x: 7.2, y: 148.5, color: 'lime' },
          { x: 9, y: 135.6, color: 'purple' },
        ]
      },{
        fillOpacity: 0.75,
        data: [
          { x: 7.2, y: 148.5, color: 'lime' },
          { x: 12, y: 216.4 },
          { x: 14, y: 194.1 }
        ]
      }]
    });
    <script src="https://code.highcharts.com/highcharts.js"></script>
    
    <div id="container"></div>