Using Chart.js, trying to display a diagonal line (representing goal) over a bar graph (representing actual. I would like the actuals line to overlay the bar graph.
var ctx = document.getElementById(id).getContext('2d');
window[id] = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
label: 'Actual',
data: [10, 20, 30, 40],
backgroundColor: 'steelblue',
}, {
label: 'Goal',
data: [10, 20, 30, 40],
fill:false,
// Changes this dataset to become a line
type: 'line',
backgroundColor: "red",
borderColor:"red"
}],
labels: ['January', 'February', 'March', 'April']},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
But my chart comes out looking like this:
I've tried changing the order using the order: parameter for the bar and line but it did not change the appearance.
SOLUTION
The way I got this to work was to have the line elements first in the dataset.
Adding order:1 and order:2 to the bar/line datasets did not affect the display.
Related
As showed in the picture the points are cut in half when reaching bottom or top edges (when the data is 1 or 5 in this example).
I tried padding, adding some 'fake' data to extend the limits of 1 and 5 and removing it with callback function on ticks. None worked as expected
This is my config for this chart.
const config = {
type: 'line' as ChartType,
data: data,
options: {
pointStyle: 'circle',
//pointBackgroundColor: 'white',
scales: {
y: {
ticks: {
maxTicksLimit: 5,
stepSize: 1,
},
min: 1,
max: 5,
reverse: true,
},
},
},
};
Removing min and max, results in the expected output.
But I need min and max, cause I want fixed Y axes values
Any clues how to fix this?
You can use the afterDataLimits hook to set the max and min of the scale, that way it still overflows the chart area:
const ctx = document.getElementById('chart').getContext('2d');
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
data: [12, 19, 3, 10, 2, 3],
borderColor: 'pink',
backgroundColor: 'pink',
radius: 10
}]
},
options: {
scales: {
y: {
afterDataLimits: (scale) => {
scale.max = 10;
scale.min = 0;
}
},
},
},
});
<canvas id="chart" width="250" height="120" />
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.6.0/dist/chart.min.js"></script>
I have a chart where I already know the set amount of ticks I'll need. There's 3 with a grouped bar type chart. I'm scratching my head over how to force it. Right now it's showing 0 to whatever number ends up in my data set and auto scales as required.
By default it's assumed I'm using numbers to scale but in this scenario it's a Positive, neutral, negative (those labels literally) on Y-Axis that are the data points related to a specific date on X axis (with 2 grouped bars labeled AM/PM).
The Chart.js documentation doesn't seem to explain how to tweak when working outside of numbers on the ticks configurations and I'm not sure how to shoehorn this in. Any ideas? Below is the code for as far as I've gotten.
The screenshot example I basically simulated the 3 data points by choosing 4,8 and 12. I would like those labels to be (negative,positive,neutral) and make all other ticks disappear.
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Date/MoonCenter', 'Date/MoonCenter', 'Date/MoonCenter'],
datasets: [{
label: 'Dataset 1', backgroundColor: window.chartColors.red,
stack: 'Stack 0',
data: [4, 12, 4, 8, 12, 4]
},{
label: 'Dataset 1', backgroundColor: window.chartColors.blue,
stack: 'Stack 1',
data: [8, 8, 12, 4, 4, 12]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
you just need add the callback in the ticks,
<canvas id="myChart" width="400" height="400"></canvas>
<script src='Chart.js'></script>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Date/MoonCenter', 'Date/MoonCenter', 'Date/MoonCenter'],
datasets: [{
label: 'Dataset 1', backgroundColor: window.chartColors.red,
stack: 'Stack 0',
data: [4, 12, 4, 8, 12, 4]
}, {
label: 'Dataset 1', backgroundColor: window.chartColors.blue,
stack: 'Stack 1',
data: [8, 8, 12, 4, 4, 12]
}]
},
options: {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
callback: function (label, index, labels) {
switch (label) {
case 4:
return 'negative';
case 8:
return 'positive';
case 12:
return 'neutral';
}
}
}
}
]
}
}
});
</script>
Additional to saul's answer:
Just add max-settings to the y-axis.
ticks: {
max: 12
}
You also have to do callbacks for the tooltip if you want to display "positive", "negative" and "neutral" instead of 4, 8 and 12.
We use the Chart.js library in our codebase and I need to create a histogram, which is not one of their default chart types. So I'm attempting to override the x-axis tick marks on a bar chart so that they appear at the left and right corners of each bar instead of directly underneath.
In the below example I've gotten the x-axis how I want it by adding an extra item in the labels array and displaying a second x-axis in the options. But, because there's now an extra label, the bars are taking up 4/5ths of the width, leaving space for a non-existent data point.
Is there some way that I can specify to ignore the missing data point? Or offset the bars? Or am I barking up the wrong tree?
The documentation is a little hard to parse through, so I'm not sure if there's something simple I'm missing.
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [0, 1, 2, 3, 4],
datasets: [{
label: 'Group A',
data: [12, 19, 3, 5],
backgroundColor: 'rgba(255, 99, 132, 1)',
}]
},
options: {
scales: {
xAxes: [{
display: false,
barPercentage: 1.30,
}, {
display: true,
}],
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
canvas { max-width: 200px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="20" height="20"></canvas>
Edit: I realize there are other libraries that could achieve something similar and I am looking into other options. But, I've posted this just in case someone out there knows of a solution via Chart.js, which would be ideal.
Here's an example of what the end result I'm going for is:
I believe you can get the result you want by using the max parameter on the ticks configuration of the x axes.
By using 2 different x axes with different maximums you can label the bars differently from how they're drawn. Resulting in labeling the marks in between the bars without drawing an extra "empty" bar.
var ctx = document.getElementById("myChart").getContext('2d');
var dataValues = [12, 19, 3, 5];
var dataLabels = [0, 1, 2, 3, 4];
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: dataLabels,
datasets: [{
label: 'Group A',
data: dataValues,
backgroundColor: 'rgba(255, 99, 132, 1)',
}]
},
options: {
scales: {
xAxes: [{
display: false,
barPercentage: 1.3,
ticks: {
max: 3,
}
}, {
display: true,
ticks: {
autoSkip: false,
max: 4,
}
}],
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
canvas { max-width: 200px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="20" height="20"></canvas>
Can Chart.js v2.x generate a combined stacked bar chart with 2 unstacked lines utilizing one y-axis? If so, how?
Below fiddle has 2 y-axis. The descending line, would render better if the right y-axis had a maximum value of 6000 as does the left axis.
jsfiddle example.
Below is the code for reference.
// set default no fill beneath the line
Chart.defaults.global.elements.line.fill = false;
// stacked bar with 2 unstacked lines - nope
var barChartData = {
labels: ['2016', '2017', '2018', '2019'],
datasets: [{
type: 'bar',
label: 'a',
yAxisID: "y-axis-0",
backgroundColor: "rgba(217,83,79,0.75)",
data: [1000, 2000, 4000, 5000]
}, {
type: 'bar',
label: 'b',
yAxisID: "y-axis-0",
backgroundColor: "rgba(92,184,92,0.75)",
data: [500, 600, 700, 800]
}, {
type: 'line',
label: 'c',
yAxisID: "y-axis-0",
backgroundColor: "rgba(51,51,51,0.5)",
data: [1500, 2600, 4700, 5800]
}, {
type: 'line',
label: 'd',
yAxisID: "y-axis-1",
backgroundColor: "rgba(151,187,205,0.5)",
data: [5000, 3000, 1000, 0]
}]
};
var ctx = document.getElementById("chart").getContext("2d");
// allocate and initialize a chart
var ch = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title: {
display: true,
text: "Chart.js Bar Chart - Stacked"
},
tooltips: {
mode: 'label'
},
responsive: true,
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true,
position: "left",
id: "y-axis-0",
}, {
stacked: false,
position: "right",
id: "y-axis-1",
}]
}
}
});
Turns out, I just needed a modification or two so that the 2 y-axis use the same scale. See this jsfiddle. Now the chart renders better. The key, in my case, is adding a ticks node and these two properties to both yAxes objects:
ticks: {
beginAtZero: true,
suggestedMax: 5800
}
Naturally, the suggestedMax value would not be hard coded. Further, since the 2 scales are now the same, I hid the right scale with this property setting display: false.
As the fiddle shows, we now have 2 unstacked lines on a stacked bar chart nicely rendered.
Use this as the data for the graph:
var barData = {
labels: ['test1','test2'],
datasets: [
{
label: 'stack1',
backgroundColor: 'yellow',
borderColor: 'white',
borderWidth: 1,
stack: '1',
data: [5,4,3,2,1]
},
{
label: 'stack2',
backgroundColor: 'blue',
borderColor: 'white',
borderWidth: 1,
stack: '2',
data: [1,2,3,4,5]
}
]
};
This is the component to render the data:
<Bar data={barData} options={{scales: { xAxes: [{stacked:true}} }], yAxes:[{stacked:true}}] } }}}} />
I'm trying to control the order in which new (after first render) series are added to a stacked column chart in Highcharts. Right now, if you simply use addSeries, the newly added series is added to the bottom of the stack. Here's a simplified version of what I'm doing
var chart = new Highcharts.Chart({
chart: {
type: 'column',
renderTo: 'container'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar']
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: 'base',
data: [10, 20, 30]
}, {
name: 'sec',
data: [30, 20, 10]
}]
});
var i = 0;
$('#add').on('click', function (e) {
chart.addSeries({
data: [32, 43, 42],
name: ++i,
index: 0 //??????
});
});
Here's a fiddle of this: http://jsfiddle.net/6bCBf/
Any one can think of a way to reverse/control where Highcharts inserts the new series?
I've tried setting the index of the new series to 0, but that does nothing. Setting it to -1 adds the new series to the bottom of the array, but then that 'stacking' does not work properly
You can set index and zIndex to keep order between layers, then add serie with appropriate parameters.
Example: http://jsfiddle.net/6bCBf/5/
var chart = new Highcharts.Chart({
chart: {
type: 'column',
renderTo: 'container'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar']
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [
{
name: 'base',
data: [10, 20, 30],
index:2,
zIndex:10
},
{
name: 'sec',
data: [30, 20, 10],
index:1,
zIndex:9
}
]
},function(chart){
$('#add').on('click', function (e) {
chart.addSeries({
data: [32, 43, 42],
index: 0,
zIndex:1
});
});
});
Highcharts also supports a yAxis.reversedStacks property which, if set to false, will reverse the order of the stacking data points. In the OP's JSFiddle, the first series, "base", appeared on the top of the chart, while the second series, "sec", appeared below it. Setting reversedStacks: false as in this updated JSFiddle reverses that order, and the new series appears on the top of the stack instead of the bottom.