i am using angular and i required to draw a graph/chart i have a data that contains name and time.
in the above situtaion name represents the name of customer and the time represent tha time of call he make(a single customer can make several calls so a customer can have many times). i want to draw a chart in such a way that we can see a customer make a call on this time.
i tried to use chart.js and try line and scatter chart but unable to get desired result.
any suggestion which chart i can use and or how to achieve this
thankyou in advance
Using a scatter chart is a good choice. The solution however depends on the format of your data. Let's presume, it looks like this:
const data = [
{ name: 'Rachel', calls: ['2021-03-01 10:15', '2021-03-01 18:02', '2021-03-02 06:48'] },
{ name: 'William', calls: ['2021-03-01 13:24', '2021-03-02 08:41', '2021-03-02 11:13'] },
{ name: 'Barbara', calls: ['2021-03-01 07:58', '2021-03-01 15:47', '2021-03-02 10:16'] }
];
You need to create a dataset for each user and provide the data in point format where the values of distinct users are different but all values of a same user are identical. This can be done using the Array.map() method as follows:
data.map((user, i) => ({
label: user.name,
data: user.calls.map(call => ({ x: call, y: i + 1 }))
}))
Now you also need to define a ticks.callback function on the y-axis that transforms the numeric tick value back to the user name
yAxes: [{
ticks: {
...
callback: v => v % 1 == 0 ? data[v - 1].name : undefined
}
}],
Please take a look at below runnable code and see how it works.
const data = [
{ name: 'Rachel', calls: ['2021-03-01 10:15', '2021-03-01 18:02', '2021-03-02 06:48'] },
{ name: 'William', calls: ['2021-03-01 13:24', '2021-03-02 08:41', '2021-03-02 11:13'] },
{ name: 'Barbara', calls: ['2021-03-01 07:58', '2021-03-01 15:47', '2021-03-02 10:16'] }
];
const colors = ['red', 'blue', 'green'];
new Chart('myChart', {
type: 'scatter',
data: {
datasets: data.map((user, i) => ({
label: user.name,
data: user.calls.map(call => ({ x: call, y: i + 1 })),
backgroundColor: colors[i],
pointRadius: 4
}))
},
options: {
responsive: true,
tooltips: {
callbacks: {
title: tooltipItem => data[tooltipItem[0].datasetIndex].name,
label: tooltipItem => tooltipItem.xLabel
}
},
scales: {
yAxes: [{
ticks: {
min: 0.5,
max: data.length + 0.5,
stepSize: 0.5,
callback: v => v % 1 == 0 ? data[v - 1].name : undefined
}
}],
xAxes: [{
type: 'time',
time: {
unit: 'hour',
displayFormats: {
hour: 'MMM-DD HH'
},
tooltipFormat: 'MMM-DD HH:mm'
},
gridLines: {
lineWidth: 0
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
<canvas id="myChart" height="80"></canvas>
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
},
}
}
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,
I am working on drowing a Gantt diagram like on Chartjs.
What am I trying to do is painting and HorizontalBarChart with time type, as a mixed type where I set a min value for each bar, however seems it does not work.
My code:
new Chart(document.getElementById("customChart"), {
type: 'horizontalBar',
data: {
labels: ['Item 1', 'Item 2'],
datasets: [
{
type: 'horizontalBar',
label: 'Bar Component1',
data: [new Date(2017,02,26) ],
options:{
scales:{
xAxes: [{
type: 'time',
unit: 'day',
unitStepSize: 1,
time: {
displayFormats: {
'day': 'YYYY-MM-DD'
},
min: new Date(2017,03,24)
}
}]
}
}
},
{
type: 'horizontalBar',
label: 'Bar Component2',
data: [new Date(2017,02,14)],
options:{
scales:{
xAxes: [{
type: 'time',
unit: 'day',
unitStepSize: 1,
time: {
displayFormats: {
'day': 'YYYY-MM-DD'
},
min: new Date(2017,02,10)
}
}]
}
}
}
]
}
});
Is there any workaround in order to implement this? Should I use another library?
Unfortunately, there is no way to configure chart.js to produce a gantt chart because each dataset that you plot on the graph either starts at the origin (the min value set on the scale) or is stacked right on top of each other. You cannot configure a chart to stack bars but show them in different "lanes" (which is what a gantt chart would require).
Even if you try to create multiple scales (which is looks like you are attempting), it will not work because the 2nd bar will still start at the origin (however the 2nd scale's origin would be the min value you specified). In other words, both bars will still touch the y axis.
You had several problems with you chart.js configuration. First, you cannot define scale config in a dataset. Second, you tried to use several time scale options, but they must be inside the time object.
I cleaned up everything just so you can see how to correctly define a chart. Here is a codepen demonstrating this.
Currently [November 2018] chart.js is not able todo so.
However if you are willing to apply a patch, there is a pull request pending, which would implement exactly this feature: https://github.com/chartjs/Chart.js/pull/5262
For my purposes I adapted the code of https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.bar.js
## -453,10 +453,12 ## module.exports = function(Chart) {
helpers.canvas.clipArea(chart.ctx, chart.chartArea);
- for (; i < ilen; ++i) {
- if (!isNaN(scale.getRightValue(dataset.data[i]))) {
- rects[i].draw();
- }
+ if (dataset.label != 'noshow') {
+ for (; i < ilen; ++i) {
+ if (!isNaN(scale.getRightValue(dataset.data[i]))) {
+ rects[i].draw();
+ }
+ }
}
helpers.canvas.unclipArea(chart.ctx);
Utilizing bar chart like this:
var gapdemo= new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: ["todo1", "todo2", "todo3", "todo4"],
datasets: [{
type: 'horizontalBar',
label: 'noshow',
data: [1,2,4,3],
},{
type: 'horizontalBar',
label: 'showme',
data: [3,2,2,1],
},{
type: 'horizontalBar',
label: 'noshow',
data: [1,5,3,4],
},{
type: 'horizontalBar',
label: 'showme',
data: [2,2,1,4],
}]
},
options: {
scales: {
xAxes: [{
id: 'x-axis-1',
stacked: true
}],
yAxes: [{
id: 'y-axis-1',
stacked: true,
ticks: {beginAtZero: true}
}]
}
}
});
This results in a chart like that:
barchart with gaps
Since version 2.9.0, Chart.js supports floating bars. Individual bars can now be specified with the syntax [min, max].
This makes it possible to draw a Gantt chart.
var dates = [new Date("2019-12-24"), new Date("2019-12-26"), new Date("2019-12-30"), new Date("2020-1-2"), new Date("2020-1-4"), new Date("2020-1-9"), new Date("2020-1-10") ];
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: dates.map((d, i) => "Task " + i).splice(1),
datasets: [
{
label: 'Tasks',
data: dates.map((d, i) => i == 0 ? null : [dates[i - 1], d]).slice(1),
backgroundColor: 'lightblue',
borderWidth: 1
}
]
},
options: {
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
day: 'YYYY-MM-DD'
}
},
ticks: {
min: dates[0].getTime(),
max: dates[dates.length - 1].getTime()
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.1.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart"></canvas>
I am a bit out of my comfort zone, since I normally do analytics and not fancy front-ends. However, I would like to have a real-time demo of some of my work, so it becomes easier to understand and not just numbers in a matrix. I have looked around and found something semi-relevant and come this far:
(It has four series like I want to and it iterates - to some degree)
https://jsfiddle.net/023sre9r/
var series1 = this.series[0],
series2 = this.series[1],
series3 = this.series[2],
series4 = this.series[3];
But I am totally lost on how to remove the random number generators without loosing nice things like the number of data points in a view (seems to depend on the for loop?!). Remove the extra title "Values" right next to my real y-axis title. And of cause how to get a new data point from a XML-file every second.
Ideally I want to have an XML-file containing 4 values, which I update approximately every 200ms in MATLAB. And every second I would like my 4 series chart to update. Is it not relatively easy, if you know what you are doing?! :-)
Thanks in advance!
I simplified your example and added clear code showing how to fetch data from server and append it to your chart using series.addPoint method. Also if you want to use XML, just convert it to JS object / JSON.
const randomData = () => [...Array(12)]
.map((u, i) => [new Date().getTime() + i * 1000, Math.random()])
Highcharts.chart('container', {
chart: {
renderTo: 'container',
type: 'spline',
backgroundColor: null,
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load () {
const chart = this
setInterval(() => {
// Fetch example below (working example: https://github.com/stpoa/live-btc-chart/blob/master/app.js)
// window.fetch('https://api.cryptonator.com/api/ticker/btc-usd').then((response) => {
// return response.json()
// }).then((data) => {
// chart.series[0].addPoint({ x: data.timestamp * 1000, y: Number(data.ticker.price) })
// })
chart.series.forEach((series) => series.addPoint([new Date().getTime(), Math.random()], true, true))
}, 3000)
}
}
},
title: {
text: null
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: [{
title: {
text: 'Temperature [°C]',
margin: 30
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
}, {
}],
tooltip: {
formatter: function() {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' + Highcharts.numberFormat(this.y, 4);
}
},
legend: {
enabled: true
},
exporting: {
enabled: false
},
rangeSelector: {
enabled: false
},
navigator: {
enabled: false
},
scrollbar: {
enabled: false
},
series: [{
name: 'Setpoint',
data: randomData()
}, {
name: 'Return',
data: randomData()
}, {
name: 'Supply',
data: randomData()
}, {
name: 'Output',
data: randomData()
}]
})
Live example: https://jsfiddle.net/9gw4ttnt/
Working one with external data source: https://jsfiddle.net/111u7nxs/