Related
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!
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.
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.
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/apexcharts#3.36.0"></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/apexcharts#3.36.0"></script>
<div id="chart"></div>
I have bellow Code to display a Chart using Chart.js.
<canvas id="canvasline" width="200" height="200"></canvas>
<script>
var ctx = document.getElementById('canvasline').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['0', '30', '50'],
datasets: [{
data: [
{ x: "0", y: 0 },
{ x: "10", y: 10 },
{ x: "20", y: 20 },
{ x: "30", y: 30 },
{ x: "40", y: 40 },
{ x: "50", y: 50 },
],
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
display: true,
suggestedMin: 0,
suggestedMax: 100,
maxTicksLimit: 10
},
gridLines: {
display: true
}
}],
xAxes: [{
ticks: {
display: true,
suggestedMin: 0,
suggestedMax: 100,
maxTicksLimit: 3
},
gridLines: {
display: true
}
}]
}
}
});
</script>
Working Code Example:
https://jsfiddle.net/2vcrsq6n/
I am facing the below issues:
For the X-Axis label "30", I see X data "10" is getting displayed
At the runtime I get an JSON array with X and Y values as an array, I want to plot this X and Y numbers on the graph how should I implement it.
When the data is specified as individual points through objects that contain an x and an y property, you should not define data.labels.
Also make sure, the x and y values are numbers but not strings.
Please take a look at your amended code below that uses the most recent stable version of Chart.js (2.9.3).
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
data: [
{ x: 0, y: 0 },
{ x: 10, y: 10 },
{ x: 20, y: 20 },
{ x: 30, y: 30 },
{ x: 40, y: 40 },
{ x: 50, y: 50 }
],
showLine: true,
fill: false,
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
suggestedMin: 0,
suggestedMax: 100,
maxTicksLimit: 10
}
}],
xAxes: [{
ticks: {
suggestedMin: 0,
suggestedMax: 100,
maxTicksLimit: 3
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart"></canvas>
To update your chart with new data, simply add or replace the data in the dataset and invoke chart.update() afterwards.
myChart.data.datasets[0].data = <new data>;
myChart.update();
How can I change the size of each different dot in my scatter chart ?
var scatterChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: 'Scatter Dataset',
data: [{
x: -10,
y: 0
}, {
x: 0,
y: 15
}, {
x: 10,
y: 5,
}],
pointRadius: 15,
fill: false,
pointHoverRadius: 20
}]
},
options: {
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
}]
}
}
});
After this I want to change each dot size in matter of my ajax response data.
I tried to do this without the star ofc:
data: [{
x: -10,
y: 0
}, {
x: 0,
y: 15
}, {
x: 10,
y: 5,
pointRadius: 15,
*
}],
but with no success.
You should use a bubble chart that accepts the bubble radius in pixels (property r) for each data point.
Please take a look at this sample chart.
you can put each point in a separate series.
this will allow you to assign a separate radius.
datasets: [{
label: 'Scatter Dataset',
data: [{
x: -10,
y: 0
}],
pointRadius: 10,
fill: false,
pointHoverRadius: 20
}, {
label: 'hidden',
data: [{
x: 0,
y: 15,
}],
pointRadius: 20,
fill: false,
pointHoverRadius: 20
}, {
label: 'hidden',
data: [{
x: 10,
y: 5,
}],
pointRadius: 30,
fill: false,
pointHoverRadius: 20
}]
and to prevent multiple legend entries from being displayed,
we can filter out all but one series label.
legend: {
labels: {
filter: function(item, chart) {
return (item.text !== 'hidden');
}
}
},
see following working snippet...
$(document).ready(function() {
var scatterChart = new Chart(document.getElementById('chart').getContext('2d'), {
type: 'scatter',
data: {
datasets: [{
label: 'Scatter Dataset',
data: [{
x: -10,
y: 0
}],
pointRadius: 10,
fill: false,
pointHoverRadius: 20
}, {
label: 'hidden',
data: [{
x: 0,
y: 15,
}],
pointRadius: 20,
fill: false,
pointHoverRadius: 20
}, {
label: 'hidden',
data: [{
x: 10,
y: 5,
}],
pointRadius: 30,
fill: false,
pointHoverRadius: 20
}]
},
options: {
legend: {
labels: {
filter: function(item, chart) {
return (item.text !== 'hidden');
}
}
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
}]
}
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"></script>
<canvas id="chart"></canvas>
I figured out you can specify an array of values for pointRadius & pointStyle properties :
datasets: [
{
label: "Plan",
data: [10, 15, 5],
pointRadius: [10, 5, 15],
pointStyle: ["rect", "rect", "circle"],
},
],
This way you can specify a size of each dot individually
I'm trying to make a chart that displays data. I can't seem to get the x axis to work. If I add type:'linear', then it doesn't display the data, but the x-axes displays. If I don't add that, then the data gets displayed, but the x axes doesn't work.
var chart = new Chart(document.getElementById("graph"),
{
type: 'line',
data: {
//labels: [1500,1600,1700,1750,1800,1850,1900,1950,1999,2050],
datasets: [{
display: true,
data: [86,114,106,106,107,111,133,221,783,2478],
label: "Africa",
borderColor: "#3e95cd",
fill: false
}
]
},
options: {
scaleShowValues: true,
responsive: false,
title: {
display: true,
text: 'World population (in millions)'
},
scales: {
yAxes: [
{
type: 'linear',
ticks: {
beginAtZero:true,
min: -10,
max: 110,
}
}
],
xAxes: [{
display: true,
position: 'bottom',
//type: 'linear',
ticks: {
display:true,
min: 0,
max: 3000,
stepSize: 10,
autoSkip: true
}
}
]
}
}
});
The data does not fit the type of the chart, there should be two coordinates 'x' and 'y'. Line chart must have data like:
data: [{
x: 10,
y: 20
}, {
x: 15,
y: 10
}]
And delete this rows: min: -10,
max: 110,
That way the graph looks more beautiful and knows how to adjust the Y values itself.
I am making a line chart in chart.js, and am having an issue where I am trying to plot point data on the line but it is ignoring the x values I am giving, and instead putting them on the first available label.
this.myLineChart = new Chart(this.ctx, {
type: 'line',
data: {
labels: [0,2,4,6,8,10],
datasets: [{
label: 'mylabel1',
fill: false,
backgroundColor: 'blue',
borderColor: 'blue',
data: [{
x: 2.5,
y: 85
}, {
x: 3.5,
y: 85
}]
}]
},
options: {
title: {
display: true,
text: 'mytitle1'
},
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMin: 70,
suggestedMax: 100
}
}]
}
}
});
The result I get is this:
But instead I would like this line to be at the x values 2.5 and 3.5, so that it lies in between the 2 and 4 labels.
What should I change in the code to make it behave as I want?
In that case, you don't need to use labels array. Instead set x-axis' type to linear and minimum and maximum value for x-axis' ticks (perhaps stepSize as well) in your chart options, like so :
xAxes: [{
type: 'linear',
ticks: {
suggestedMin: 0,
suggestedMax: 10,
stepSize: 2
}
}]
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
myLineChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'mylabel1',
fill: false,
backgroundColor: 'blue',
borderColor: 'blue',
data: [{
x: 2.5,
y: 85
}, {
x: 3.5,
y: 85
}]
}]
},
options: {
title: {
display: true,
text: 'mytitle1'
},
scales: {
xAxes: [{
type: 'linear',
ticks: {
suggestedMin: 0,
suggestedMax: 10,
stepSize: 2 //interval between ticks
}
}],
yAxes: [{
display: true,
ticks: {
suggestedMin: 70,
suggestedMax: 100
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>