I have an angularjs line chart in my page. I am using chart.js as my chart. The data that I have at first is fake and I want to get the true data from the database. I have created a query that can get the date and the total number of members on that specific date. The query goes like this:
SELECT distinct a.time, COUNT(b.member_id) AS Members
FROM b
Inner JOIN a ON b.mir_id = a.mir_id
GROUP BY
a.time order by a.time
And this query returns data like this
I have a line chart code in my controller that goes like this one:
$scope.member;
adminService.getMember()
.then(function(data){
$scope.memberList = data.data.member;
$scope.member = $scope.memberList;
console.log($scope.memberList);
//alert($scope.ptypeList);
//localStorage.ProductType = JSON.stringify(data.data);
$rootScope.loader = false;
});
$scope.percent = 65;
$scope.anotherPercent = -45;
$scope.anotherOptions = {
animate:{
duration:0,
enabled:false
},
barColor:'#2C3E50',
scaleColor:false,
lineWidth:20,
lineCap:'circle'
};
$scope.percent2 = 25;
$scope.anotherPercent2 = -45;
$scope.anotherOptions2 = {
animate:{
duration:0,
enabled:false
},
barColor:'#2C3E50',
scaleColor:false,
lineWidth:20,
lineCap:'circle'
};
$scope.percent3 = 85;
$scope.anotherPercent3 = -45;
$scope.anotherOptions3 = {
animate:{
duration:0,
enabled:false
},
barColor:'#2C3E50',
scaleColor:false,
lineWidth:20,
lineCap:'circle'
};
//--------------
$scope.colors = ['#45b7cd', '#ff6384', '#ff8e72'];
$scope.labels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
$scope.data = [
[65, -59, 80, 81, -56, 55, -40],
[28, 48, -40, 19, 86, 27, 90]
];
$scope.datasetOverride = [
{
label: "Bar chart",
borderWidth: 1,
type: 'bar'
},
{
label: "Line chart",
borderWidth: 3,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
type: 'line'
}
];
$scope.labels1 = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
$scope.series1 = ['Series A', 'Series B'];
$scope.onClick = function (points, evt) {
console.log(points, evt);
};
$scope.datasetOverride1 = [{ yAxisID: 'y-axis-1' }];
$scope.options1 = {
scales: {
yAxes: [
{
id: 'y-axis-1',
type: 'linear',
display: true,
position: 'left',
data: $scope.member
},
]
}
}
I am quite confused on how can I assign the values I get from the database to the line chart. How can I do that?
First you should aggregate your data returned from the database.Use the SUM() function.The correct format should be this:
Date | Member
-------------------
2016-06-23 | 5
2016-06-24 | 10
In the controller you should have an array.
data = [{Date:"2016-0-23",Member:5},{Date:"2016-06-24",Member:10}];
To create a simple chart you need the data and labels.
vm.labels = data.map(function (property) {return propery.Date;});
vm.data = data.map(function (property) {return propery.Member;});
On the HTML page:
<canvas id="line" class="chart chart-line" chart-data="vm.data" chart-labels="vm.labels"></canvas>
Related
So Im trying to find an smart way to pass data with dates to chart.js.
On the x-axis i would like to show a time line for example a week,
14/06 15/06 16/06 17/06 18/06 19/06 20/6
But the data will not inculde every day
for example
[{'date': 15/06, 'bought': 2}, {'date': 17/06, 'bought': 5}]
for what I read, I would need to create a new array (same index number as the time period), compare the dates and replace the value depending on the index value...
Is there a better process?
I would like to show a time period for like a year.
LeeLenalee's perfectly shows how Chart.js is instructed to correctly parse your data. In order to obtain a time line, you'll also need to define the x-axis as a time cartesian axis.
Please take a look at below runnable code and see how it works.
new Chart('myChart', {
type: 'line',
data: {
datasets: [{
label: 'Purchases per day',
data: [
{ 'date': '15/06', 'bought': 2 },
{ 'date': '17/06', 'bought': 5 },
{ 'date': '20/06', 'bought': 3 }
],
borderColor: 'rgb(0, 0, 255)',
backgroundColor: 'rgba(0, 0, 255, 0.5)'
}]
},
options: {
parsing: {
xAxisKey: 'date',
yAxisKey: 'bought'
},
scales: {
y: {
ticks: {
stepSize: 1
}
},
x: {
type: 'time',
time: {
parser: 'DD/MM',
unit: 'day',
tooltipFormat:'MMM DD'
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment#2.27.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#0.1.1"></script>
<canvas id="myChart" height="90"></canvas>
You can just provide that array as is to chart.js, you only need to specify which field should be mapped to the x Axis and which field to the yAxis in the parsing block of the options object.
Live example:
var options = {
type: 'line',
data: {
datasets: [
{
label: '# of Votes',
data: [{'date': '15/06', 'bought': 2}, {'date': '17/06', 'bought': 5}, {'date': '20/06', 'bought': 3}],
borderWidth: 1
}
]
},
options: {
parsing: {
xAxisKey: 'date',
yAxisKey: 'bought'
}
}
}
var 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.3.2/chart.js"></script>
</body>
I am using highcharts and want to bind dynamic json data to pie chart.Here is my dynamic string
for(i = 0; i < month.length; i++){
pi_data+='{name:"'+month[i]+'",y: '+ percent[i] +',color: Highcharts.getOptions().colors['+ i
+']},';
}
Here i am generate json string and bind in pie chart data option below
{
type: 'pie',
name: 'Total Percentage',
data: [pi_data],
center: [100, 50],
size: 100,
showInLegend: false,
}
My return string is
{name:"January",y: 24.78,color: Highcharts.getOptions().colors[0]},{name:"February",y: 14.69,color: Highcharts.getOptions().colors[1]},{name:"March",y: 26.51,color: Highcharts.getOptions().colors[2]},{name:"April",y: 34.01,color: Highcharts.getOptions().colors[3]}
If i put directly in data option it working but if i put variable in data option(inside [ ] in data:) it wont work.
I guess you want data to be an array, not a string of JS code (what you get from the loop; it's also malformed), so you need to compose pi_data properly. Try this:
// From the loop I assumed pi_data should be an array.
let pi_data = []
for(i = 0; i < month.length; i++){
pi_data.push({
name: month[i],
y: percent[i],
color: Highcharts.getOptions().colors[i],
});
}
{
type: 'pie',
name: 'Total Percentage',
data: pi_data, // No []!
center: [100, 50],
size: 100,
showInLegend: false,
}
The way you are formatting the data is incorrect. data parameter takes an array of items, where as here your passing is an object.
Try converting it to the following format:
let pi_data = month.map((item,index) => ({
name: item.month,
y: item.percent,
color: Highcharts.getOptions().colors[index]
}));
//Result
[
{ name: "January", y: 24.78, color: Highcharts.getOptions().colors[0] },
{ name: "February", y: 14.69 , color: Highcharts.getOptions().colors[1]},
{ name: "March", y: 26.51,color: Highcharts.getOptions().colors[2] },
{ name: "April", y: 34.01,color: Highcharts.getOptions().colors[3] }
]
And in the options just have this array placed
{
type: 'pie',
name: 'Total Percentage',
data: pi_data,
center: [100, 50],
size: 100,
showInLegend: false,
}
Fiddle for your reference: https://jsfiddle.net/vo3ch9L1/
I am working with a echarts javascript chart and trying to get it to work with my data in Zoomdata. I have the data grouped by 20 different computers so I am looking to do a stacked line chart with 20 lines. I know how to hard code this but I would like to link the data in Zoomdata to the code to display in the chart. Right now it just plots all 20 computers on one line.
import echarts from 'echarts'; //
import styles from './index.css';
// create chart container
const chartContainer = document.createElement('div');
chartContainer.style.width = '100%';
chartContainer.style.height = '100%';
chartContainer.classList.add(styles.chartContainer);
controller.element.appendChild(chartContainer);
const groupAccessor = controller.dataAccessors['Group By'];
const metricAccessor = controller.dataAccessors.Size;
//Need help
//Part Im having trouble with linking data in zoomdata to this chart
const chart = echarts.init(chartContainer);
const option = {
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value'
},
series: [
{
name:'邮件营销',
type:'line',
stack: '总量',
data:[120, 132, 101, 134, 90, 230, 210]
},
{
name:'联盟广告',
type:'line',
stack: '总量',
data:[220, 182, 191, 234, 290, 330, 310]
},
{
name:'视频广告',
type:'line',
stack: '总量',
data:[150, 232, 201, 154, 190, 330, 410]
},
{
name:'直接访问',
type:'line',
stack: '总量',
data:[320, 332, 301, 334, 390, 330, 320]
},
{
name:'搜索引擎',
type:'line',
stack: '总量',
data:[820, 932, 901, 934, 1290, 1330, 1320]
}
]
};
//Rest of code
controller.update = data => {
// Called when new data arrives
option.series[0].data = reshapeData(data);
chart.setOption(option);
};
function reshapeData(data) {
return data.map(d => ({
name: groupAccessor.raw(d),
value: metricAccessor.raw(d),
datum: d,
itemStyle: { //tell the chart you would like to use the colors selected
color: groupAccessor.color(d),//tell the chart you would like to use the colors selected
}, //tell the chart you would like to use the colors selected
}));
}
chart.on('mousemove', param => {
controller.tooltip.show({
event: param.event.event,
data: () => param.data.datum,
});
});
chart.on('mouseout', param => {
controller.tooltip.hide();
});
chart.on('click', param => {
controller.menu.show({
event: param.event.event,
data: () => param.data.datum,
});
});
controller.createAxisLabel({
picks: 'Group By',
position: 'bottom',
orientation: 'horizontal',
});
controller.createAxisLabel({
picks: 'Size',
position: 'bottom',
orientation: 'horizontal',
});
The json looks like:
[
{
current: {
count: 1508,
metrics: null,
na: false
},
group: [
"Computer1"
]
},
{..},
{..}
]
Thanks for adding the json details. If I understood it good, the value you want to display on each line must be current.count, and the name of each series is given by the first item in the group array (I don't know why it's an array, though).
Here is the code I would write if I want to map your data on ECharts:
/*
* incremental update counter. This will be displayed
* on the xAxis by being pushed to options.xAxis.data array.
*/
let updateCount = 0,
// initialize series as empty
const options = {
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value'
},
series: []
}
controller.update = data => {
updateCount++
if (options.series.length > 0) {
// Called when new data arrives
options.xAxis.data.push('record ' + updateCount)
options.series = updateData(data)
} else {
// Called only once to initialize
options.xAxis.data.push('record ' + updateCount)
options.series = initData(data)
}
// you can remove the following line if your chart is already reactive.
chart.setOption(option)
}
// the init function.
const initData = data => {
// transform each item in the data array into a series entry.
data.map(item => {
return {
name: item.group[0],
type: 'line',
stack: 'defaultStack',
data: [item.current.count]
}
})
}
// the update function.
const updateData = newData => {
// push new data counts to its respective series data.
options.series.forEach((item, index) => {
item.data.push(newData[index].current.count)
}
}
It's a bit long but more secure way to parse your raw data into an ECharts option. Let me know if you have any issue with this, I haven't tested yet so it's only brain code.
I am trying to add labels to my bar chart. See the JS fiddle and code below. How would I change my code to add labels?
http://jsfiddle.net/amwmedia/8kqvyhqv/
var myNewChart;
var data = [
{
value: 30,
label: "hello",
color: "#F7464A"
}, {
value: 50,
color: "#E2EAE9"
}, {
value: 100,
color: "#D4CCC5"
}, {
value: 40,
color: "#949FB1"
}, {
value: 100,
color: "#4D5360"
},
];
var options = {
animation: true,
animationEasing: 'easeInOutQuart',
animationSteps: 80,
multiTooltipTemplate: "<%= datasetLabel %> - <%= value %>"
};
var ctx = document.getElementById("myChart")
.getContext("2d");
myNewChart = new Chart(ctx).Doughnut(data, options);
I noticed your jsfiddle is using chart.js version 1. My answer uses version 2, as that is all I could find documentation for.
Looks like all you need to do is put labels in the data object:
var data = {
labels: [
"label1",
"label2",
"label3",
"label4",
"label5"
],
datasets: [
{
data: [
30,
50,
100,
40,
100
],
backgroundColor:[
'#F7464A',
'#E2EAE9',
'#D4CCC5',
'#949FB1',
'#4D5360'
]
}]
};
See fiddle. (this is using Chart.js 2.0)
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 ^_^