Bagzli
Bagzli

Reputation: 6569

Custom Apexchart

I am trying to create a graph with Apexcharts that looks like below. You can ignore the 2 vertical lines as they are not necessary.

Looking at the examples that apexcharts have, the closest thing I have found is Stacked Bar Charts. Maybe there is something better and I missed? If so please let me know.

https://apexcharts.com/javascript-chart-demos/bar-charts/stacked/

The way the chart below behaves is I get an array of data such as this:

[3, 7, 21, 55, 32, 3, 7, 58, 38] // and so on. You will notice the numbers can duplicate. 

To simply things I will use Book and pages as a reference. The X axis represents number of pages and Y axis represents number of books. So by looking at the image I posted you can see there are 22 books that have 100 or less pages. There are 2 books with greater than 100 but less than 300 pages and 1 book with more than 300 and less than 400 pages.

I am having a real hard time figuring out how to configure the stacked bar chart to display things in this manner. I am not looking for an answer on how to manipulate my data, but more of how to configure the settings of the graph in order to get the correct display.

I have tried several configurations to no avail. Any help on this is most appreciated!

Example

For reference to show work, some of things I have tried:

series: [{
        name: 'Range 1',
        data: [{ y: 44, x: 100 }, { y: 55, x: 100 }, { y: 41, x: 100 }, { y: 37, x: 100 }, { y: 22, x: 100 }, { y: 43, x: 100 }, { y: 21, x: 100 }]
    }, {
        name: 'Range 2',
        data: [{ y: 44, x: 200 }, { y: 55, x: 200 }, { y: 41, x: 200 }, { y: 37, x: 200 }, { y: 22, x: 200 }, { y: 43, x: 200 }, { y: 21, x: 200 }]
    }]

series: [{
        name: 'Range 1',
        data: [{ x: 44, y: 100 }, { x: 55, y: 100 }, { x: 41, y: 100 }, { x: 37, y: 100 }, { x: 22, y: 100 }, { x: 43, y: 100 }, { x: 21, y: 100 }]
    }, {
        name: 'Range 2',
        data: [{ x: 44, y: 200 }, { x: 55, y: 200 }, { x: 41, y: 200 }, { x: 37, y: 200 }, { x: 22, y: 200 }, { x: 43, y: 200 }, { x: 21, y: 200 }]
    }]
series: [{
        name: 'Range 1',
        data: [44, 55, 41, 37, 22, 43, 21]
    }, {
        name: 'Range 2',
        data: [53, 32, 33, 52, 13, 43, 32]
    }]

One of the largest issues I'm finding is that I can't seem to control values on the X axis or to keep the bars same width.

Here is an example of how it comes out from one of the attempts. Example 2

Lastly, the first image I showed above is generated from a Histogram from google charts. My requirements were to move all the google charts to apex charts so I'm trying to find something in apex charts equivalent to do the job.

Upvotes: 1

Views: 1769

Answers (1)

Badacadabra
Badacadabra

Reputation: 8497

There are two things that I do not really understand in your question: your data and why you want a stacked bar chart.

If you need to put the number of pages on your xaxis and the number of books on your yaxis, then a basic bar chart should be enough. I give you an example below:

let options = {
  series: [{
    name: 'Series',
    data: [22, 2, 2, 1, 0, 0, 2, 0]
  }],
  chart: {
    type: 'bar',
    height: 350
  },
  dataLabels: {
    enabled: false
  },
  xaxis: {
    categories: [0, 100, 200, 300, 400, 500, 600, 700],
    labels: {
      offsetX: -13
    },
    title: {
      text: 'Number of pages',
      offsetY: 100
    }
  },
  yaxis: {
    title: {
      text: 'Number of books'
    }
  },
  tooltip: {
    custom: ({series, seriesIndex, dataPointIndex, w}) => {
      return `<div class="arrow_box"><div>Book(s): <strong>${series[seriesIndex][dataPointIndex]}</strong></div><div>Pages: <strong>${w.globals.labels[dataPointIndex]}-${w.globals.labels[dataPointIndex] + 100}</strong></div>`;
    }
  }
};

let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
.arrow_box {
  padding: 10px;
}
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

<div id="chart"></div>

The trickiest part is the custom tooltip. I did this to put intervals in there instead of the category.


EDIT 1

Oops! I did not pay attention: my example above is not responsive (see labels). So maybe you could do something like that:

let options = {
  series: [{
    name: 'Series',
    data: [22, 2, 2, 1, 0, 0, 2]
  }],
  chart: {
    type: 'bar',
    height: 350
  },
  dataLabels: {
    enabled: false
  },
  xaxis: {
    categories: ['0-100', '101-200', '201-300', '301-400', '401-500', '501-600', '601-700'],
    title: {
      text: 'Number of pages',
      offsetY: 100
    }
  },
  yaxis: {
    title: {
      text: 'Number of books'
    }
  },
  responsive: [
    {
      breakpoint: 400,
      options: {
        xaxis: {
          title: {
            offsetY: 150
          }
        }
      }
    }
  ]
};

let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

<div id="chart"></div>

This is not very elegant but I did not find a better solution.


EDIT 2

After reading your comment, I updated my example:

let options = {
  series: [{
    name: 'Sci-fi',
    data: [44, 55, 41, 37, 22, 43, 21]
  }, {
    name: 'Fantasy',
    data: [53, 32, 33, 52, 13, 43, 32]
  }],
  chart: {
    type: 'bar',
    height: 350,
    stacked: true
  },
  dataLabels: {
    enabled: false
  },
  xaxis: {
    categories: ['0-100', '101-200', '201-300', '301-400', '401-500', '501-600', '601-700'],
    title: {
      text: 'Number of pages'
    }
  },
  yaxis: {
    title: {
      text: 'Number of books'
    }
  }
};

let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<div id="chart"></div>


EDIT 3

Using the analogy above, each stacked bar would show title of the book. As they are all different books.

If you want to do that, I think you will have to create one series for each book and just set one color to avoid getting an unreadable rainbow. But if you have a lot of books, you will most likely face performance issues.

You will find a better example below. It is not consistent because I randomized all series, but it seems closer to what you are trying to do.

function getAllSeries() {
  let allSeries = [];
  
  for (let i = 1; i <= 7; i++) {
    let series = {};
    
    series.name = `Book ${i}`;
    series.data = [];  
    
    for (let j = 0; j < 7; j++) {
      if ((Math.random() * 10) < 5) {
        series.data.push(1);
      } else {
        series.data.push(null);
      }
    }
    
    allSeries.push(series);
  }
  
  return allSeries;
}

let options = {
  series: getAllSeries(),
  chart: {
    type: 'bar',
    height: 350,
    stacked: true
  },
  dataLabels: {
    enabled: false
  },
  xaxis: {
    categories: ['0-100', '101-200', '201-300', '301-400', '401-500', '501-600', '601-700'],
    title: {
      text: 'Number of pages'
    }
  },
  yaxis: {
    title: {
      text: 'Number of books'
    }
  },
  legend: {
    show: false
  },
  colors: ['#269ffb'],
  stroke: {
    colors: ['#ffffff'],
    width: 1    
  },
  tooltip: {
    custom: ({series, seriesIndex, dataPointIndex, w}) => {
      return `<div class="arrow_box"><div>Name: <strong>${w.config.series[seriesIndex].name}</strong></div><div>Pages: <strong>${w.globals.labels[dataPointIndex]}</strong></div>`;
    }
  }
};

let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
.arrow_box {
  padding: 10px;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<div id="chart"></div>

Upvotes: 1

Related Questions