I created a bubble chart using ChartJs and populating data dynamically using Json.
See the code below.
for (var i = 0; i < response.data.length; i++) {
var point_data = [];
point_data.push({
x: response.data[i]['return_tickets'].toString(),
y: Math.round(response.data[i]['return_percentage']).toString(),
r: Math.round((response.data[i]['return_percentage'])).toString()
});
data.push({ label: response.data[i]['staff_name'], data: point_data, backgroundColor: getRandomColor(), hoverRadius:4 });
}
new Chart(document.getElementById("bubbleChart"), {
type: 'bubble',
data: {
datasets: data
},
options: {
title: {
display: true,
text: ''
}, scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: "Return Tickets %"
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: "Return Tickets"
}
}]
}
}
});
It generates the desired chart as below
The problem is when I hover over any bubble the size of the bubble increases exponentially.
How to keep the size same ?
I'm setting the hoverRadius property of the dataset but it does nothing for me.
Problem is with your this line of code:
{ label: response.data[i]['staff_name'], data: point_data, backgroundColor: getRandomColor(), hoverRadius:4 }
This is not a valid JSON. Values must be either strings or arrays. Most probably issue is at label: response.data[i]['staff_name'] or in point_data (I can see you are making x, y and r values .toString() that maybe not required). Check it again. Create a valid JSON and then try by setting hoverRadius: 0, it will work.
Setting hoverRadius: 0 working fine for me. Bubble size will not change on mouse over if you set hoverRadius: 0.
Below is working example:
var chart = new Chart(ctx, {
type: 'bubble',
data: {
datasets: [{
label: 'Bubble',
data: [{
x: 5,
y: 55,
r: 27.5
}],
backgroundColor: 'rgba(0, 119, 290, 0.6)',
hoverRadius: 0
}]
},
options: {
tooltips: {
callbacks: {
label: function(t, d) {
return d.datasets[t.datasetIndex].label +
': (Day:' + t.xLabel + ', Total:' + t.yLabel + ')';
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="ctx"></canvas>
Checkout official documentation for more info : https://www.chartjs.org/docs/latest/charts/bubble.html#dataset-properties
I have already faced the same issue also fixed it by typecasting for every x,y & z. I just convert it to float
'x' => (float) $x_axis_value,
'y' => (float) $y_axis_value,
'r' => (float) $radious_value,
Related
I am trying to remove the grid lines on the Radar chart on chart.js v2 for react.
Desired Result
but keeping the outermost line while removing the inner lines and numbers
I have attempted to use the following code but it only returns a runtime error saying "category" is not a registered scale.
const options = {
scales: {
x: {
grid: {
display: false
}
},
y: {
grid: {
display: false
}
}
}
}
This can be done through the following options.
scale: {
ticks: {
stepSize: 1,
callback: (v, i, values) => i + 1 < values.length ? '' : v
},
gridLines: {
color: [0, 0, 0, 0, '#ccc']
}
}
For further details, please consult the Styling page from the Chart.js v2.9.4 documentation.
Please take a look at below runnable code and see how it works. Note that it uses a generic approach for defining gridLines.color.
const labels = ['Things 1', 'Things 2', 'Things 3', 'Things 4', 'Things 5'];
const data = [0, 3, 5, 2, 5];
const max = Math.ceil(Math.max(...data));
new Chart('radar-chart', {
type: 'radar',
data: {
labels: labels,
datasets: [{
data: data,
fill: true,
backgroundColor: 'rgba(0, 0, 255,0.2)',
borderColor: 'rgb(0, 0, 255)'
}]
},
options: {
legend: {
display: false
},
scale: {
ticks: {
stepSize: 1,
max: max,
callback: (v, i, values) => i + 1 < values.length ? '' : v
},
gridLines: {
color: Array.from(Array(max).keys()).map((v, i) => i + 1 < max ? 0 : '#ccc')
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<canvas id="radar-chart" height="80"></canvas>
From the error you are getting it seems like you are using Chart.js V3 and not V2. To get what you want you need to import and register everything if you want to use treeshaking, I suggest you do this at the latest part and for development import everything like so:
import Chart from 'chart.js/auto';
To hide and get the result what you want your config needs to look like this:
const labels = ['Things 1', 'Things 1', 'Things 1', 'Things 1', 'Things 1'];
const data = [0, 3, 5, 2, 3];
new Chart('radar-chart', {
type: 'radar',
data: {
labels: labels,
datasets: [{
data: data,
fill: true,
backgroundColor: 'rgba(0, 0, 255,0.2)',
borderColor: 'rgb(0, 0, 255)'
}]
},
options: {
plugins: {
legend: {
display: false
}
},
scales: {
r: {
ticks: {
stepSize: 1,
callback: (v, i, values) => i + 1 < values.length ? '' : v
},
grid: {
color: data.map((v, i) => i + 1 < data.length ? 0 : '#ccc')
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
<canvas id="radar-chart" height="80"></canvas>
Notice that I specify a r scale instead of x and y
I am trying to make a chart which has years along the x-axis and dollar amounts along the y-axis. I finally got close to what I'm looking for, but I found that because the x coordinates are numbers, ChartJS is putting commas in them which looks really strange for years.
After some digging, I used the callbacks. options.plugin.tooltip.callbacks.label worked to let me remove commas in the tooltips, but when I use options.scales.x[0].ticks.callback to try to fix the labels on the bottom, not only does it not work, but I don't see the console.log statement in their ever being printed so it seems it's not even calling the callback. I've tried several variations of how to do the callback based on what I found online and on Stack Overflow which I think correspond to the different ways ChartJS did this in different versions. (I'm on version 3.5.1.)
Then, I realized that... none of the options under options.scales appear to have any effect. I change the min, the title, the tick settings (color to red, callback, etc.) and it has no effect. (This also explains why I was having trouble when using the line chart and had to switch to scatter; apparently type: 'linear' wasn't being picked up nor did it do anything different when I set it to type: 'date' or whatever the exact working was for that.)
Meanwhile, the other options like options.showLine or options.elements do have an effect and I'm seeing the chart and not getting any errors in the console. So, it is picking up the options, just ignoring everything I have in options.scales.
Here is the relevant code:
// Sample data added to make this example self-contained
// This is my internal data format
let data = {
"Series1": [ {x: 2001, y: 100 }, {x: 2002, y: 110 }, {x: 2003, y: 107 }, ],
"Series2": [ {x: 2001, y: 107 }, {x: 2002, y: 102 }, {x: 2004, y: 95 }, ],
}
// Define data //////////////////////////////////////////////////////
// I convert data to format ChartJS wants and add a few options
let datasets = [];
for(let label in data) {
let c = colorIterator.next().value
datasets.push({
label: label,
data: data[label],
backgroundColor: c,
borderColor: c,
});
}
// Define options //////////////////////////////////////////////////////
let chartConfig = {
type: 'scatter',
data: { datasets: datasets, },
options: {
title: { display: false },
indexAxis: 'x', responsive: true, maintainAspectRatio: false,
showLine: true,
elements: {
line: { display: true, tension: 0, borderWidth: 1, fill: false, },
point: { radius: 3 }
},
interaction: { mode: 'x', },
scales: {
x: [{
type: 'linear',
min: 1995, max: (new Date()).getFullYear()+1, stepSize: 1,
title: { display: true, text: 'Year' },
ticks: {
display: true,
major: { enabled: true },
color: 'red',
callback: function(value, index, ticks) {
console.log(value);
return Chart.Ticks.formatters.numeric.apply(this, [value, index, ticks])
.replace(",","");
}
}
}],
y: [{
title: { display: true, text: '$' },
ticks: {
display: true,
color: 'red',
},
}],
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if(label) {
let x = context.label.replace(",","");
let y = context.formattedValue;
return 'Year ' + x + ' "' + label + '": $' + y;
} else { return 'x'; }
},
},
},
},
}
};
// MAKE CHART //////////////////////////////////////////////////////
let mainChart = new Chart(document.getElementById(c.id), chartConfig);
As described in the docs the scales are not arrays. All the scales are objects in the scale object.
So you will need to change your code to this:
options: {
scales: {
x: {
// x options
},
y: {
// y options
},
}
}
How can I move my labels on my x axes in between another x axes label. Nothing seems to work and I was unable to find anything on the docs. Is there a workaround? I'm using line chart time series.
https://www.chartjs.org/samples/latest/scales/time/financial.html
Currently, with the code I have its generating the figure below:
var cfg = {
elements:{
point: {
radius: 4
}
},
data: {
datasets: [
{
label: 'vsy',
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
borderColor: window.chartColors.red,
data: firstData,
type: 'line',
pointRadius: 2,
fill: false,
lineTension: 0,
borderWidth: 2
},
{
label: 'de vsy',
backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
borderColor: window.chartColors.blue,
data: dataMaker(15),
type: 'line',
pointRadius: 2,
fill: false,
lineTension: 0,
borderWidth: 2
}
],
},
options: {
animation: {
duration: 0
},
scales: {
xAxes: [{
type: 'time',
distribution: 'series',
offset: true,
time: {
unit: 'month',
displayFormats: {
month: 'MMM'
}
},
ticks: {
autoSkip: true,
autoSkipPadding: 75,
sampleSize: 100
},
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index',
}
}
};
This is what I have now:
I want the labels on the x-axis to be on center instead of below the y axis grid line.
Thanks to uminder, with his comment it solves the issue but now I have a conflicting tooltip which lie on a same grid. When I hover to april line first point it shows me mar 30 which lies just above it and vice versa.
I fixed it by changing the mode to nearest but why is it activating the another point?
The option you're looking for is offsetGridLines.
If true, grid lines will be shifted to be between labels.
xAxes: [{
...
gridLines: {
offsetGridLines: true
}
In most cases, this produces the expected result. Unfortunately it doesn't work for time axes as documented in Chart.js issue #403. Thanks to Antti Hukkanen, there exists a workaround.
Please have a look at below runnable code snippet to see how it works.
function generateData() {
var unit = 'day';
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
function randomPoint(date, lastClose) {
var open = randomNumber(lastClose * 0.95, lastClose * 1.05).toFixed(2);
var close = randomNumber(open * 0.95, open * 1.05).toFixed(2);
return {
t: date.valueOf(),
y: close
};
}
var date = moment().subtract(1, 'years');
var now = moment();
var data = [];
for (; data.length < 600 && date.isBefore(now); date = date.clone().add(1, unit).startOf(unit)) {
data.push(randomPoint(date, data.length > 0 ? data[data.length - 1].y : 30));
}
return data;
}
var TimeCenterScale = Chart.scaleService.getScaleConstructor('time').extend({
getPixelForTick: function(index) {
var ticks = this.getTicks();
if (index < 0 || index >= ticks.length) {
return null;
}
// Get the pixel value for the current tick.
var px = this.getPixelForOffset(ticks[index].value);
// Get the next tick's pixel value.
var nextPx = this.right;
var nextTick = ticks[index + 1];
if (nextTick) {
nextPx = this.getPixelForOffset(nextTick.value);
}
// Align the labels in the middle of the current and next tick.
return px + (nextPx - px) / 2;
},
});
// Register the scale type
var defaults = Chart.scaleService.getScaleDefaults('time');
Chart.scaleService.registerScaleType('timecenter', TimeCenterScale, defaults);
var cfg = {
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
backgroundColor: 'red',
borderColor: 'red',
data: generateData(),
type: 'line',
pointRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2
}]
},
options: {
animation: {
duration: 0
},
scales: {
xAxes: [{
type: 'timecenter',
time: {
unit: 'month',
stepSize: 1,
displayFormats: {
month: 'MMM'
}
},
gridLines: {
offsetGridLines: true
}
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index'
}
}
};
var chart = new Chart('chart1', cfg);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart1" height="90"></canvas>
For chartJs v3 you can use offset property:
scales: {
x: {
grid: {
offset: true
}
},
...
}
I have used a Bubble Chart on Chart.js to create sliders to show comparable performance and they currently look a bit like this:
What am I trying to do
I want to add data labels just above / in my 'bubbles' with my values in. Much like the '10' you can see on each bubble here.
What have I done to achieve this
This is not standard Chart.js functionality but I found this post which was discussing a similar issue for bar / line charts.
I've installed the plugin that post suggested but the data label it shows is for the radius of the bubble and I want to it to be the x-axis of the bubble.
I've also tried to use the code from some of the answers on that post, but with absolutely no luck.
My Code
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.bundle.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
<div class="container" >
<h2>Chart.js — Line Chart Demo</h2>
<div>
<canvas id="myChart"></canvas>
</div>
</div>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
ctx.height = 1000;
var myChart = new Chart(ctx, {
type: 'bubble',
data: {
datasets: [
{
label: 'Your Data',
data: [
{x: 78.7, y: 0, r: 10, name: "Performance"}
],
backgroundColor: "rgba(153,255,51,0.6)"
},
{
label: 'Average',
data: [
{x: 100.7, y: 0, r: 10, name: "Performance"} // The labe needs to be X. not R.
],
backgroundColor: "rgba(255,0,128,0.6)"
}
]
},
options: {
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: [{
ticks: {
min: 50, // Controls where axis starts
max: 120 // Controls where axis finishes
},
gridLines: {
display: false,
lineWidth: 3 // Width of bottom line
}
}]
}
}
});
</script>
Thanks in advance
I've managed to find the answer to this question, basically by taking apart the bubble chart example from the chartjs-plugin-datalabels plugin.
Below is a working example. Pay attention to the section in options that says 'plugin'.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.bundle.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
<div class="container" >
<h2>Chart.js — Line Chart Demo</h2>
<div>
<canvas id="myChart"></canvas>
</div>
</div>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
ctx.height = 1000;
var myChart = new Chart(ctx, {
type: 'bubble',
data: {
datasets: [
{
label: 'Your Data',
data: [
{x: 78.7, y: 0, r: 10, name: "Performance"}
],
backgroundColor: "rgba(153,255,51,0.6)"
},
{
label: 'Average',
data: [
{x: 100.7, y: 0, r: 10, name: "Performance"} // The labe needs to be
],
backgroundColor: "rgba(255,0,128,0.6)"
}
]
},
options: {
plugins: { // Look at this bit
datalabels: {
anchor: function(context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 50 ? 'end' : 'center';
},
align: function(context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 50 ? 'end' : 'center';
},
color: function(context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 50 ? context.dataset.backgroundColor : 'white';
},
font: {
weight: 'bold'
},
formatter: function(value) {
return 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: [{
ticks: {
min: 50, // Controls where axis starts
max: 120 // Controls where axis finishes
},
gridLines: {
display: false,
lineWidth: 3 // Width of bottom line
}
}]
}
}
});
</script>
If all you want to do is changing the label, there is an easier solution. From the docs of chartjs-plugin-datalabels:
Data values are converted to string ('' + value). If value is an object, the following rules apply first:
value = value.label if defined and not null
else value = value.r if defined and not null
else value = 'key[0]: value[key[0]], key[1]: value[key[1]], ...'
Therefore, it is sufficient to specify a label in your data points:
data: [{ x: 78.7, y: 0, r: 10, name: "Performance", label: `${Math.round(x)}` }],
I've been trying to display somewhat complex data on my webpage and chose chart.js to do so.
Therefor I need to group multiple stacked bars horizontally.
I already found this fiddle for "normal" bars but couldn't quite change it to work with horizontalBar yet.
Stackoverflow question: Chart.js stacked and grouped bar chart
The original Fiddle (http://jsfiddle.net/2xjwoLq0/) has
Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.bar);
And I just replaced the .bar everywhere in the code with .horizontalBar (well knowing that this won't make the cut).
Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.horizontalBar);
Since that didn't quite work, I tried adding the second stacked modifier as suggested for horizontal bars here:
Horizontal stacked bar chart with chart.js and flipped the functions for X and Y calculation (calculateBarY/calculateBarX)
Which quite work either because the stacks won't get merged onto each other correctly.
http://jsfiddle.net/2xjwoLq0/3/
I would appreciate if anyone could help me out on this one.
Looking for something similar, I took a look on example you gave, and decide to write something.
Rather than trying to fix the code or reusing the 'groupableBar', I get Chart.js code from Chart.controllers.horizontalBar and rewrite some part in functions calculateBarY, calculateBarHeight.
Just reused the getBarCount function from your example.
Chart.defaults.groupableHBar = Chart.helpers.clone(Chart.defaults.horizontalBar);
Chart.controllers.groupableHBar = Chart.controllers.horizontalBar.extend({
calculateBarY: function(index, datasetIndex, ruler) {
var me = this;
var meta = me.getMeta();
var yScale = me.getScaleForId(meta.yAxisID);
var barIndex = me.getBarIndex(datasetIndex);
var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0;
var stackIndex = this.getMeta().stackIndex;
if (yScale.options.stacked) {
if(ruler.datasetCount>1) {
var spBar=ruler.categorySpacing/ruler.datasetCount;
var h=me.calculateBarHeight(ruler);
return topTick + (((ruler.categoryHeight - h) / 2)+ruler.categorySpacing-spBar/2)+(h+spBar)*stackIndex;
}
return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing;
}
return topTick +
(ruler.barHeight / 2) +
ruler.categorySpacing +
(ruler.barHeight * barIndex) +
(ruler.barSpacing / 2) +
(ruler.barSpacing * barIndex);
},
calculateBarHeight: function(ruler) {
var returned=0;
var me = this;
var yScale = me.getScaleForId(me.getMeta().yAxisID);
if (yScale.options.barThickness) {
returned = yScale.options.barThickness;
}
else {
returned= yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight;
}
if(ruler.datasetCount>1) {
returned=returned/ruler.datasetCount;
}
return returned;
},
getBarCount: function () {
var stacks = [];
// put the stack index in the dataset meta
Chart.helpers.each(this.chart.data.datasets, function (dataset, datasetIndex) {
var meta = this.chart.getDatasetMeta(datasetIndex);
if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) {
var stackIndex = stacks.indexOf(dataset.stack);
if (stackIndex === -1) {
stackIndex = stacks.length;
stacks.push(dataset.stack);
}
meta.stackIndex = stackIndex;
}
}, this);
this.getMeta().stacks = stacks;
return stacks.length;
}
});
var data = {
labels: ["January", "February", "March"],
datasets: [
{
label: "Dogs",
backgroundColor: "rgba(255,0,0,0.2)",
data: [20, 10, 25],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Cats",
backgroundColor: "rgba(255,255,0,0.2)",
data: [70, 85, 65],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Birds",
backgroundColor: "rgba(0,255,255,0.2)",
data: [10, 5, 10],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: ":-)",
backgroundColor: "rgba(0,255,0,0.2)",
data: [20, 10, 30],
stack: 2,
xAxisID: 'x-axis-1',
yAxisID: 'y-axis-0'
},
{
label: ":-|",
backgroundColor: "rgba(0,0,255,0.2)",
data: [40, 50, 20],
stack: 2,
xAxisID: 'x-axis-1',
yAxisID: 'y-axis-0'
},
{
label: ":-(",
backgroundColor: "rgba(0,0,0,0.2)",
data: [60, 20, 20],
stack: 2,
xAxisID: 'x-axis-1',
yAxisID: 'y-axis-0'
},
]
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
type: 'groupableHBar',
data: data,
options: {
scales: {
yAxes: [{
stacked: true,
type: 'category',
id: 'y-axis-0'
}],
xAxes: [{
stacked: true,
type: 'linear',
ticks: {
beginAtZero:true
},
gridLines: {
display: false,
drawTicks: true,
},
id: 'x-axis-0'
},
{
stacked: true,
position: 'top',
type: 'linear',
ticks: {
beginAtZero:true
},
id: 'x-axis-1',
gridLines: {
display: true,
drawTicks: true,
},
display: false
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<canvas id="myChart"></canvas>
Also put example on jsfiddle here: https://jsfiddle.net/b7gnron7/4/
Code is not strongly tested, you might found some bugs especially if you try to display only one stacked group (use horizontalBar instead in this case).
Your post is a little bit old... not sure that you still need a solution, but it could be useful for others ^_^