I have a radar chart in which "100" represents the global average value for a characteristic.
To make the chart more readable I want to make only the grid line that indicates the 100 value mark dashed.
Is there a way to do this?
Current chart code is here: jsfiddle.
const config = {
type: 'radar',
data: data,
options: {
elements: {
line: {
borderWidth: 3
},
point: {
pointRadius: 5
}
},
scales: {
r: {
angleLines: {
lineWidth: 2
},
grid: {
circular: true,
lineWidth: 2
}
}
}
}
};
In my opinion, the logically correct answer is to define grid.borderDash as follows:
grid: {
...
borderDash: ctx => ctx.tick.value == 100 ? [8, 4] : []
},
To make it work however, I had to use ctx.tick.value == 95 (This could be a bug in Chart.js). Please take a look at your amended code and see how it works.
let dataValues = [100, 120, 80, 100, 90, 110, 100, 100, 100]
const sum = dataValues.reduce((a, b) => a + b, 0);
const avg = sum / dataValues.length;
const sorted = [...dataValues].sort(function(a, b) {
return a - b;
});
const data = {
labels: dataValues.map((v, i) => 'Signal ' + (i + 1)),
datasets: [{
label: '9 signals',
data: dataValues,
fill: true,
backgroundColor: 'rgba(210, 203, 203, 0.4)',
borderColor: 'rgb(210, 203, 203, 0.6)',
pointBackgroundColor: function(context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value < sorted[3] ? 'blue' :
value < sorted[5] ? 'green' :
value < sorted[7] ? 'orange' :
'red';
},
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(255, 99, 132)'
}
]
};
const config = {
type: 'radar',
data: data,
options: {
elements: {
line: {
borderWidth: 3
},
point: {
pointRadius: 5
}
},
scales: {
r: {
suggestedMin: 70,
angleLines: {
lineWidth: 2
},
grid: {
circular: true,
lineWidth: 2,
borderDash: ctx => ctx.tick.value == 95 ? [8, 4] : []
},
ticks: {
stepSize: 5
}
}
}
}
};
let myChart = new Chart('myChart',
config
);
.chartBox {
width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<div class="chartBox">
<canvas id="myChart"></canvas>
</div>
Related
I have 3 charts on my canvas 1 stacked bar chart and 2 line charts.
Line charts have same Y values but located at different heights.
I have 3.6 version Chart js
dataset
is data for my stacked bars
Line and linePrediction are my graphs and have same values
const line = {
label: 'Signed',
data: [
{x: 1, y: 12226000},
{x: 2, y: 12716000},
{x: 3, y: 14176000},
...
],
backgroundColor: 'rgba(55, 128, 189, 1)',
borderColor: 'rgba(55, 128, 189, 1)',
tension: 0.4,
type: 'line',
order: 1,
}
const data = {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
datasets: [ ...dataset, line, linePrediction]
};
const config = {
type: 'bar',
data,
options: {
responsive: true,
plugins: {
tooltip: {
enabled: true,
callbacks: {
title: function(tooltipItems, data) {
return tooltipItems[0].formattedValue || '';
},
label: function(context) {
return ' ' + context.dataset.label || '';
}
}
},
legend: {
display: true,
position: 'bottom',
labels: {
padding: 10
}
}
},
scales: {
x: {
stacked: true
},
y: {
beginAtZero: true,
stacked: true
},
},
}
};
const chart = new Chart(document.getElementById('chart'), config);
From question ChartJS: How to set fixed Y axis max and min I'm attempting to limit the y axis values using:
ticks : {
max : 200,
min : -200
}
This is in order to prevent the charing "jumping" on incoming data to match the y-axis values range. If there is an alternative to prevent the data jumping please suggest, I assume setting max and min y values will prevent the chart "jumping" as the range is set to a static, rather than dynamic value.
fiddle: https://jsfiddle.net/adrianfiddleuser/yd4mfubp/10/
HTML:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<script src="https://github.com/nagix/chartjs-plugin-streaming/releases/download/v1.5.0/chartjs-plugin-streaming.min.js"></script>
</head>
<body>
<div>
<canvas id="myChart"></canvas>
</div>
<p>
<button id="randomizeData">Randomize Data</button>
<button id="addDataset">Add Dataset</button>
<button id="removeDataset">Remove Dataset</button>
<button id="addData">Add Data</button>
<span class="label">pause:</span>
<span><input type="checkbox" id="pause" class="control"></span>
</p>
</body>
javascript:
var chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
function randomScalingFactor() {
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
}
function onRefresh(chart) {
chart.config.data.datasets.forEach(function(dataset) {
dataset.data.push({
x: Date.now(),
y: randomScalingFactor()
});
});
}
var color = Chart.helpers.color;
var config = {
type: 'line',
data: {
datasets: [{
label: 'Dataset 1 (linear interpolation)',
backgroundColor: color(chartColors.red).alpha(0.5).rgbString(),
borderColor: chartColors.red,
fill: false,
lineTension: 0,
borderDash: [8, 4],
data: []
}, {
label: 'Dataset 2 (cubic interpolation)',
backgroundColor: color(chartColors.blue).alpha(0.5).rgbString(),
borderColor: chartColors.blue,
fill: false,
cubicInterpolationMode: 'monotone',
data: []
}]
},
options: {
title: {
display: true,
text: 'Line chart (hotizontal scroll) sample'
},
scales: {
xAxes: [{
type: 'realtime'
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'value',
ticks : {
max : 200,
min : -200
}
}
}]
},
tooltips: {
mode: 'nearest',
intersect: false
},
hover: {
mode: 'nearest',
intersect: false
},
plugins: {
streaming: {
duration: 20000,
refresh: 1000,
delay: 2000,
onRefresh: onRefresh
}
}
}
};
//window.onload = function() {
var ctx = document.getElementById('myChart').getContext('2d');
window.myChart = new Chart(ctx, config);
//};
document.getElementById('randomizeData').addEventListener('click', function() {
config.data.datasets.forEach(function(dataset) {
dataset.data.forEach(function(dataObj) {
dataObj.y = randomScalingFactor();
});
});
window.myChart.update();
});
var colorNames = Object.keys(chartColors);
document.getElementById('addDataset').addEventListener('click', function() {
var colorName = colorNames[config.data.datasets.length % colorNames.length];
var newColor = chartColors[colorName];
var newDataset = {
label: 'Dataset ' + (config.data.datasets.length + 1),
backgroundColor: color(newColor).alpha(0.5).rgbString(),
borderColor: newColor,
fill: false,
lineTension: 0,
data: []
};
config.data.datasets.push(newDataset);
window.myChart.update();
});
document.getElementById('removeDataset').addEventListener('click', function() {
config.data.datasets.pop();
window.myChart.update();
});
document.getElementById('addData').addEventListener('click', function() {
onRefresh(window.myChart);
window.myChart.update();
})
Setting the max and min y-axis values does not appear to fix the issue. How to prevent the chart from "jumping" on incoming data?
Your attempt with defining ticks.min and ticks.max is fine. The only problem is that you defined ticks at the wrong place. Change it as follows and it will work as expected.
yAxes: [{
scaleLabel: {
display: true,
labelString: 'value',
},
ticks: {
max: 100,
min: -100
}
}]
Please have a look at your amended JSFiddle.
I want to create chart as above. I ahve tried multiple ways to do but couldn't get any correct one.
Some sample code i'm showing below:
HTML code:
<canvas class='chartjs-gauge'></canvas>
JS CODE:
var config6 = {
type:"doughnut",
data: {
labels : ["Positive","Negative"],
datasets: [{
label: "Gauge",
data : [190, 10],
backgroundColor: [ "green","red" ]
}]
},
options: {
circumference: Math.PI,
rotation : Math.PI,
cutoutPercentage : 40, // precent
plugins: {
datalabels: {
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#ffffff',
color: function(context) {
return context.dataset.backgroundColor;
},
font: function(context) {
var w = context.chart.width;
return {
size: w < 512 ? 18 : 20
}
},
align: 'start',
anchor: 'start',
offset: 10,
borderRadius: 4,
borderWidth: 1,
formatter: function(value, context) {
var i = context.dataIndex;
var len = context.dataset.data.length - 1;
if(i == len){
return null;
}
return value+' mph';
}
}
},
legend: {
display: true
},
tooltips: {
enabled: true
}
}
};
But it is only showing chart as below:
Anybody know how to do it?
I am trying to position a label related to the dataset below a point on a bubble graph and to have the value displayed on top of the point.
I have tried returning two different values, but it only allows me to return one.
Because of this I have returned both values within the same string.
Is it possible to return the label and position it below the value of the dataset and to put the value above the point of the dataset?
If it isn't possible would it be possible to somehow get the text to align to the center after the line break I have added to the string?
Here is what I have so far
This is what I am trying to achieve, but with the value above the bubble
Here is my code so far:
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bubble',
data: {
datasets: [
{
label: 'Top',
data: [
{x: 110, y: 0, r: 12, name: "Performance"}
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,255,255,1)",
hoverBorderWidth : 2
},
{
label: 'Average',
data: [
{x: 75, y: 0, r: 12, name: "Performance"}
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,255,255,1)",
hoverBorderWidth : 2
},
{
label: 'You 2017',
data: [
{x: 55, y: 0, r: 15, name: "Performance"}
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor : "rgba(255,255,255,1)",
hoverBorderWidth : 2
},
{
label: 'You 2018',
data: [
{x: 90, y: 0, r: 15, name: "Performance"} // The labe needs to be
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor : "rgba(255,255,255,1)",
hoverBorderWidth : 2
}
]
},
options: {
legend: {
display: false
},
plugins: {
datalabels: {
anchor: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
align: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
color: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? context.dataset.borderColor : 'white';
},
font: {
weight: 'bold'
},
formatter: function (value, context) {
ctx.textAlign = "center";
return context.dataset.label + "\n" + Math.round(value.x);
},
offset: 2,
padding: 0
}
},
maintainAspectRatio: false,
scales: {
yAxes: [{
id: 'first-y-axis',
type: 'linear',
ticks: {
min: 0,
max: 1,
stepSize: 1,
display: false
},
gridLines: {
display: false,
drawBorder: false
}
}],
xAxes: [
{
id: 'first-x-axis',
ticks: {
min: 50, // Controls where axis starts
max: 120, // Controls where axis finishes
stepSize: 70 // Control the gap between the first x-axis value and the last x-axis value
},
gridLines: {
display: false,
lineWidth: 3 // Width of bottom line
}
}
]
}
}
});
Any help or suggestions would be greatly appreciated ^_^
I figured this out by applying 'textAlign' within the charts parameters and set it to centre.
You can see this in the code below:
plugins: {
datalabels: {
anchor: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
align: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
color: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? context.dataset.borderColor : 'white';
},
textAlign: 'center',
font: {
weight: 'bold',
alignment: 'right' // Is this the place to be doing this?
},
formatter: function (value, context) {
return context.dataset.label + '\n' + Math.round(value.x);
},
offset: 2,
padding: 0
}
},
Hope this helps ^^
I'm a bit stuck on adding conditional background colours to a row in ChartJS, based on numbers on the vertical axis.
Eg.
If the vertical axis is between 0 - 6, background colour for those rows is green.
If the vertical axis is between 6 - 12 background colour for those rows is grey
If the vertical axis is > 12 background colour for those rows is red
Has anyone done something like this before?
I've attached a picture that roughly describes the functionality.
Cheers!
There is no option to do this with chartjs. However you can write your own plugin and draw the background by yourself in the beforeDraw hook for example.
var chart = new Chart(ctx, {
plugins: [{
beforeDraw: function(chart) {
//..
}
}]
});
You can get all the information to calculate the height of an y-axis-segment from the chart parameter.
I've included a snippet below how this could be implemented. Note however that this is more a proof of concept than a proper implementation:
var canvas = document.getElementById('myChart');
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(51, 204, 51)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
var myLineChart = new Chart(canvas,
{
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [
{
label: '# of Votes',
fill: false,
backgroundColor: window.chartColors.blue,
borderColor: window.chartColors.blue,
data: [2, 5, 12.5, 9, 6.3]
}
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Conditional Background'
},
backgroundRules: [{
backgroundColor: window.chartColors.green,
yAxisSegement: 6
}, {
backgroundColor: window.chartColors.grey,
yAxisSegement: 12
}, {
backgroundColor: window.chartColors.red,
yAxisSegement: Infinity
}],
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
},
plugins: [{
beforeDraw: function (chart) {
var ctx = chart.chart.ctx;
var ruleIndex = 0;
var rules = chart.chart.options.backgroundRules;
var yaxis = chart.chart.scales["y-axis-0"];
var xaxis = chart.chart.scales["x-axis-0"];
var partPercentage = 1 / (yaxis.ticksAsNumbers.length - 1);
for (var i = yaxis.ticksAsNumbers.length - 1; i > 0; i--) {
if (yaxis.ticksAsNumbers[i] < rules[ruleIndex].yAxisSegement) {
ctx.fillStyle = rules[ruleIndex].backgroundColor;
ctx.fillRect(xaxis.left, yaxis.top + ((i - 1) * (yaxis.height * partPercentage)), xaxis.width, yaxis.height * partPercentage);
} else {
ruleIndex++;
i++;
}
}
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<canvas id="myChart" width="400" height="250"></canvas>
Shiffty's answer is right on point, however it only works if the background values are present on the yAxis, which is not always the case... depends on what fits. A more generic solution is to calculate the actual values:
var canvas = document.getElementById('myChart');
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(51, 204, 51)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
var myLineChart = new Chart(canvas,
{
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [
{
label: '# of Votes',
fill: false,
backgroundColor: window.chartColors.blue,
borderColor: window.chartColors.blue,
data: [2, 5, 12.5, 9, 6.3]
}
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Conditional Background'
},
backgroundRules: [{
backgroundColor: window.chartColors.green,
yAxisSegement: 6
}, {
backgroundColor: window.chartColors.grey,
yAxisSegement: 12
}, {
backgroundColor: window.chartColors.red,
yAxisSegement: 999999
}],
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
},
plugins: [{
beforeDraw: function (chart) {
var rules = chart.chart.options.backgroundRules;
var ctx = chart.chart.ctx;
var yAxis = chart.chart.scales["y-axis-0"];
var xaxis = chart.chart.scales["x-axis-0"];
for (var i = 0; i < rules.length; ++i) {
var yAxisSegement = (rules[i].yAxisSegement > yAxis.ticksAsNumbers[0] ? yAxis.ticksAsNumbers[0] : rules[i].yAxisSegement);
var yAxisPosStart = yAxis.height - ((yAxisSegement * yAxis.height) / yAxis.ticksAsNumbers[0]) + chart.chart.controller.chartArea.top;
var yAxisPosEnd = (i === 0 ? yAxis.height : yAxis.height - ((rules[i - 1].yAxisSegement * yAxis.height) / yAxis.ticksAsNumbers[0]));
ctx.fillStyle = rules[i].backgroundColor;
ctx.fillRect(xaxis.left, yAxisPosStart, xaxis.width, yAxisPosEnd - yAxisPosStart + chart.chart.controller.chartArea.top);
}
}
}]
});