Lets say I have a Donut chart with 5 items in data like this
const data = {
labels: ['E-commerce', 'Enterprise', 'Green', 'Grey', 'Purple'],
datasets: [
{
label: '# of Votes',
data: [12, 19, 3, 5, 3],
backgroundColor: ['#C07CC3', '#9C3848', '#9DDBAD', '#ADA8B6', '#606EDA'],
borderWidth: 1,
},
],
}
I don't want it to show all the legends as I don't have space or whatever reason
How can I hide the Green and purple in this example?
I mean only from legends not from chart
I see two easy ways, how you could approach this problem:
(I personally I would use the second option below, it is more configurable, but it needs just abit of coding)
You can simply delete the labels you want to delete from the labels- array, and they won't show up in the legend.
But keep in mind you would have to change the order of the data and backgroundColor arrays, to match this change.
Here a short demo:
const data = {
labels: ['E-commerce', 'Enterprise', 'Grey'], // <-- just remove the unwanted labels
datasets: [{
data: [12, 19, 5, 3, 3], // <-- reorder
backgroundColor: ['#C07CC3', '#9C3848', '#ADA8B6', '#9DDBAD', '#606EDA'], // <-- reorder
borderWidth: 1,
}],
};
const config = {
type: 'doughnut',
data: data,
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
usePointStyle: true,
},
}
},
}
};
new Chart(
document.getElementById('chart'),
config
);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>
Better and cleaner (but some coding is needed), you can filter out label-items, you don't want to display, with the function array filter. (details can be found in the documentation)
UPDATED Alternative Version Demo:
here only the Top 3 labels (limiting the amount of labels with the variable maxLabelsToShow) will be shown (sort order is descending, but changing this is would be easy)
function getLabelsOnlyTopX(num, data, labels){
let selectedLabels = []
//we don't want to alter the order
let helperData = [...data];
//sort in descending order
helperData.sort( (a,b) => b-a);
//get top X Values
helperData = helperData.slice(0, num);
//get index for the data
let indexes = data.map( (value, index) => ({value,index}) ).filter(item => helperData.some(n1 => n1 == item.value))
//slecet only labels with the correct index
selectedLabels = labels.filter((value, index) => indexes.some( n => n.index == index))
// just be sure that a maximum of num labels are sent
return selectedLabels.slice(0, num);
}
let maxLabelsToShow = 3;
let serverData = [12, 19, 3, 5, 3]
let labels = ['E-commerce', 'Enterprise', 'Green', 'Grey', 'Purple'];
// Calling the newly created function
let showOnly = getLabelsOnlyTopX(maxLabelsToShow, serverData, labels);
const data = {
labels: labels,
datasets: [{
data: serverData,
backgroundColor: ['#C07CC3', '#9C3848',
'#9DDBAD', '#ADA8B6', '#606EDA'],
borderWidth: 1,
}],
};
const config = {
type: 'doughnut',
data: data,
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
usePointStyle: true,
/* FILTER function */
filter: function(item, chart) {
return showOnly.indexOf( item.text) > -1;
}
},
}
},
}
};
new Chart(
document.getElementById('chart'),
config
);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>
Related
I am trying to figure out how to render a section of each column in a simple, single series, column chart with multiple colors. Using series.zones:
series: [
{
name: "Mod",
colorByPoint: true,
data: seriesData,
zones: [
{ value: 101, color: '#1D681B' },
{ value: 121, color: '#ECC518' },
{ color: '#D50D0D' }
]
}
]
I can get each column to be a different color based on the zone that the y value is within.
In my example above the zone are:
0 through 100 should be green
101 to 120 should be yellow
121 and above should be red
The above works to an extent, but looks like the following:
However, what my boss wants is something like this:
Can this be achieved using highcharts?
Instead of zones you can use stacked columns. Below is a simple example of how you can automatically calculate series structure:
const steps = [100, 20];
const data = [42, 100, 96, 120, 110, 90, 140];
const series = [{
color: '#1D681B',
data: []
}, {
linkedTo: ':previous',
color: '#ECC518',
data: []
}, {
linkedTo: ':previous',
color: '#D50D0D',
data: []
}];
data.forEach((dataEl, i) => {
let rest = dataEl;
let counter = 0;
let value;
while (rest > 0) {
value = steps[counter] < rest ? steps[counter] : rest;
series[counter].data.push({
x: i,
y: value
});
rest -= value;
counter++;
}
});
Highcharts.chart('container', {
chart: {
type: 'column'
},
yAxis: {
reversedStacks: false
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series
});
Live demo: http://jsfiddle.net/BlackLabel/3h6o0ncg/
Docs: https://www.highcharts.com/docs/advanced-chart-features/stacking-charts
I'm trying to shorten my chart legends, so I'm using the beforeRender plugin to change the text of the legend. However, once the chart is drawn, it seems to keep the original label size (see below snippet, legends are offset to the left instead of in the centre and if you click on orange, it toggles one of the earlier items).
The same happens if I try in beforeDraw and if I use beforeInit or beforeLayout, the legends don't seem to have been created yet.
Is there any way to get the chart to redraw the legends with the new text? Or change the legend text so that it is rendered properly?
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'pie',
data: {
labels: ['red - some other text that appears after', 'blue - some other text that appears after', 'green - some other text that appears after', 'orange - some other text that appears after'],
datasets: [{
data: [4, 2, 10, 3],
backgroundColor: ['red', 'blue', 'green', 'orange'],
}],
},
options: {
responsive: true,
},
plugins: [{
beforeRender: chart => {
chart.legend.legendItems.forEach(label => {
const labelParts = label.text.split(' - ');
const newLabel = label;
newLabel.text = labelParts[0];
return newLabel;
});
},
}],
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
<div style="width: 100%">
<canvas id="canvas"></canvas>
</div>
A better approach would be to use a custom generateLabels function like so:
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'pie',
data: {
labels: ['red - some other text that appears after', 'blue - some other text that appears after', 'green - some other text that appears after', 'orange - some other text that appears after'],
datasets: [{
data: [4, 2, 10, 3],
backgroundColor: ['red', 'blue', 'green', 'orange'],
}],
},
options: {
responsive: true,
legend: {
labels: {
generateLabels: function(chart) {
const data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
const meta = chart.getDatasetMeta(0);
const style = meta.controller.getStyle(i);
return {
text: label.split(' - ')[0],
fillStyle: style.backgroundColor,
strokeStyle: style.borderColor,
lineWidth: style.borderWidth,
hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
}
}
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
<div style="width: 100%">
<canvas id="canvas"></canvas>
</div>
I am trying to achieve the Tooltip shown below in the first image. Inside of the tooltip I need to display the yAxes and xAxes data. The chart.js version I am using is 3.7.0
My tooltip looks like this:
The tooltip that I am trying copy:
The chart.js documentation is quite hard for me to understand. Is there any guru that can explain to me.
Question: Why is my tooltip returning the yAxes data, that I return as a variable(label) as undefined?
Are there any other options I can use to make my chart look like the chart in the second picture?
My Code:
tooltip: {
displayColors: false,
backgroundColor: 'rgba(45,132,180,0.8)',
bodyFontColor: 'rgb(255,255,255)',
callbacks: {
title: function(item, everything){
return;
},
label: function(item, everything){
//console.log(item);
//console.log(everything);
let first = item.yLabel;
let second = item.xLabel;
let label = first + ' ppm';
return label;
}
}
}
Thank you in advance for your time and efforts, please help me figure out what am I doing wrong!
yLabel and xLabel dont exist anymore on the tooltip, they are V2 syntax.
You can just axess the y object in the parsed section to get the y value. Then you can use the afterBody callback to show the x label like so:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
}]
},
options: {
plugins: {
tooltip: {
displayColors: false,
backgroundColor: 'rgba(45,132,180,0.8)',
bodyFontColor: 'rgb(255,255,255)',
callbacks: {
title: () => {
return
},
label: (ttItem) => (`${ttItem.parsed.y} ppm`),
afterBody: (ttItems) => (ttItems[0].label)
}
}
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.js"></script>
</body>
js and I have two datasets:
data1 = [[0,1],[2,3],[5,7]] and data2 = [[1,4],[2,6],[5,2],[7,1]] for example.
Each data list contains lists that represent points to plot on a same chart. (x and y values)
I want to plot exactely like this :
https://www.chartjs.org/samples/latest/charts/line/multi-axis.html
But as you can see, my data lists don't have the same x or y values and they don't even have the same size, so I can't use the regular:
data: {labels = [1,2,3,4,5],
data = [7,8,3,1,2],
data = [9,1,2,3,4]} //for example
How can I code this chart only with javascript (no jQuery please) ? I didn't find anything on the Internet that might help.
Any suggestions would matter to me !
You can use a scatter chart, that accepts the data as an array of objects containing x and y properties. To turn it into a line chart, define showLine: true inside the data configuration objects.
Given your data structures, the following line of code produces the data structure expected by Chart.js.
data1.map(o => ({ x: o[0], y: o[1] }))
Please have a look at below runnable code snippet.
const data1 = [[0,1],[2,3],[5,7]];
const data2 = [[1,4],[2,6],[5,2],[7,1]];
new Chart('line-chart', {
type: "scatter",
responsive: true,
data: {
datasets: [
{
data: data1.map(o => ({ x: o[0], y: o[1] })),
label: 'Dataset 1',
showLine: true,
fill: false,
borderColor: 'red'
},
{
data: data2.map(o => ({ x: o[0], y: o[1] })),
label: 'Dataset 2',
showLine: true,
fill: false,
borderColor: 'blue'
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="line-chart" height="80"></canvas>
I'm creating charts using Chart.js and I want to show the labels for the bars in the legend, not the title of the dataset (there is only one), please see the below image as an example:
My current legend just looks like this:
I have looked through the docs but to no avail, I found them very confusing actually.
Here is my current code:
var chart_0 = new Chart($('#cp_chart_0'), {
type: 'bar'
, data: {
labels: ['Blue','Green','Yellow','Red','Purple','Orange']
, datasets: [{
label: 'Dataset 1'
, borderWidth: 0
, backgroundColor: ['#2C79C5','#7FA830','#7B57C3','#ED4D40','#EC802F','#1DC6D3']
, data: ['12','2','5','0','9','1']
}]
}
});
Thanks!
In one of the most recent releases of Chart.js 2.1.x, they added back this functionality. So go get the latest release first. Then insert the code below.
It is located under the options and legend. Here is how you use it:
options: {
legend: {
position: 'right'
}
}
Easiest way is to provide your data with multiple sets :
data: {
labels: ['total votes']
, datasets: [{
label: 'Blue'
, backgroundColor: ['#2C79C5']
, data: ['12']
},{
label: 'Green'
, backgroundColor: ['#7FA830']
, data: ['2']
},
...
]
}
But you can generate a custom labels using generateLabels - http://www.chartjs.org/docs/#chart-configuration-legend-configuration
Or even customise the whole legend, including formatting, with legendCallback - http://www.chartjs.org/docs/#chart-configuration-common-chart-configuration
This solution uses Chart.js version 3. You can pre-process your data using the Plugin Core API. The API offers different hooks that may be used for executing custom code.
I use the beforeInit hook to create individual datasets for each defined label/value pair. Note that the data of these new datasets are defined in point format (for instance [{ x: 1, y: 12 }]):
beforeInit: chart => {
let dataset = chart.config.data.datasets[0];
chart.config.data.datasets = chart.config.data.labels.map((l, i) => ({
label: l,
data: [{ x: i + 1, y: dataset.data[i] }],
backgroundColor: dataset.backgroundColor[i],
categoryPercentage: 1
}));
chart.config.data.labels = undefined;
}
Further you need to define a second x-axis that will contain the labels.
x1: {
offset: true,
gridLines: {
display: false
}
}
The labels on x1 need to be collected and defined programmatically each time the hidden state of a dataset changes. This can be done in the beforeLayout hook.
beforeLayout: chart => chart.options.scales.x1.labels = chart.config.data.datasets.filter((ds, i) => !chart.getDatasetMeta(i).hidden).map(ds => ds.label)
Please take a look at below runnable code and see how it works.
new Chart('chart', {
type: 'bar',
plugins: [{
beforeInit: chart => {
let dataset = chart.config.data.datasets[0];
chart.config.data.datasets = chart.config.data.labels.map((l, i) => ({
label: l,
data: [{ x: i + 1, y: dataset.data[i] }],
backgroundColor: dataset.backgroundColor[i],
categoryPercentage: 1
}));
chart.config.data.labels = undefined;
},
beforeLayout: chart => chart.options.scales.x1.labels = chart.config.data.datasets.filter((ds, i) => !chart.getDatasetMeta(i).hidden).map(ds => ds.label)
}],
data: {
labels: ['Blue', 'Green', 'Yellow', 'Red', 'Purple', 'Orange'],
datasets: [{
data: ['12', '2', '5', '0', '9', '1'],
backgroundColor: ['#2C79C5', '#7FA830', '#FFF200', '#ED4D40', '#800080', '#EC802F']
}]
},
options: {
interaction: {
intersect: true,
mode: 'nearest'
},
plugins: {
legend: {
position: 'right'
},
tooltip: {
callbacks: {
title: () => undefined
}
}
},
scales: {
y: {
beginAtZero: true
},
x: {
display: false
},
x1: {
offset: true,
gridLines: {
display: false
}
}
}
}
});
canvas {
max-width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.min.js"></script>
<canvas id="chart" height="120"></canvas>