I have run my head into a brick wall with this one. I have a data set that tracks three data points over time. These data points can change independently of each other. I am trying to show the history of these changes in a line chart but I have yet to find out how to make a common x axis for the three.
The data is returned like this:
{
"Default": {
"Values": [
999,
799,
999
],
"Timestamps": [
"2015-03-01T03:31:16+00:00",
"2015-03-01T07:21:43+00:00",
"2015-03-01T14:02:22+00:00"
]
},
"Current": {
"Values": [
399,
849
],
"Timestamps": [
"2015-03-01T01:15:22+00:00",
"2015-03-01T21:30:43+00:00"
]
},
"CurrentPremium": {
"Values": [
500,
345,
200,
500
],
"Timestamps": [
"2015-02-01T14:24:00+00:00",
"2015-03-01T00:13:28+00:00",
"2015-03-01T09:56:43+00:00",
"2015-03-01T12:00:04+00:00"
]
}
}
The returned values indicate when this value changed from its previous value.
I am using a linechart from chartjs to visualize the data. For that I need to supply a common list of labels that match the data points for the lines so I need to align these three data sets somehow but I can't figure out how to achieve this.
I would use a library like lodash (to make utility things quicker) to pre process the data into a flat list of all timestamps and then for each dataset a matching list of values recording null if that data set does not have a timestamp from the merged flat list of all timestamps.
I have also added an option to my fork of chart js which would be useful here which would be to then populate sparse data to the lines still connect and you are not left with floating points that can be hard to see.
var datasets = {
"Default": {
"Values": [
999,
799,
999
],
"Timestamps": [
"2015-03-01T03:31:16+00:00",
"2015-03-01T07:21:43+00:00",
"2015-03-01T14:02:22+00:00"
]
},
"Current": {
"Values": [
399,
849
],
"Timestamps": [
"2015-03-01T01:15:22+00:00",
"2015-03-01T21:30:43+00:00"
]
},
"CurrentPremium": {
"Values": [
500,
345,
200,
500
],
"Timestamps": [
"2015-02-01T14:24:00+00:00",
"2015-03-01T00:13:28+00:00",
"2015-03-01T09:56:43+00:00",
"2015-03-01T12:00:04+00:00"
]
}
};
//merge and sort all timestamps in to one array (used lodash here just to make things easy
var timestamps = _.chain(datasets).pluck("Timestamps").reduce(function(previous, current, index) {
return previous.concat(current)
}).unique().sortBy(function(timestamp) {
return new Date(timestamp)
}).value();
//set up base chart data with colours
var chartDatasets = [{
fillColor: "rgba(220,120,120,0.2)",
strokeColor: "rgba(220,120,120,1)",
pointColor: "rgba(120,120,120,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
}, {
fillColor: "rgba(20,120,120,0.2)",
strokeColor: "rgba(20,120,120,1)",
pointColor: "rgba(20,120,120,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
}, {
fillColor: "rgba(120,120,120,0.2)",
strokeColor: "rgba(120,120,120,1)",
pointColor: "rgba(120,120,120,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
}]
//go through each dataset from server,
//for each dataset go through it's time stamps,
//go through the merged timestamps and if the timestamp is prresent in the dataset record the value other wise record null so we
//end up with a flat list of data that matches the flat time stamps
var datasetsIndex = 0;
_.forEach(datasets, function(dataset, key) {
var data = [];
_.forEach(timestamps, function(timestamp) {
var dataToPush = null;
_.forEach(dataset.Timestamps, function(datasetTimestamp, datasetTimestampIndex) {
if (datasetTimestamp === timestamp) {
dataToPush = dataset.Values[datasetTimestampIndex];
}
});
data.push(dataToPush);
});
chartDatasets[datasetsIndex].label = key;
chartDatasets[datasetsIndex].data = data;
datasetsIndex++;
});
var chartData = {
labels: timestamps,
datasets: chartDatasets
};
var chart = new Chart(document.getElementById("chart").getContext("2d")).Line(chartData, {
populateSparseData: true
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.3.1/lodash.js"></script>
<script src="http://quincewebdesign.com/cdn/Chart.js"></script>
<canvas id="chart" width="400" height="400"></canvas>
Related
I'm hoping I can add markup to each dataset individually so that I can change the colors with css.
var ctx = document.getElementById("myChart").getContext("2d");
var data = {
labels: ["(1)","(2)","(3)","(4)","(5)"],
datasets: [
{
label: "Food Chart",
fillColor: "#000066",
strokeColor: "transparent",
pointColor: "red",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: calcChart(),
}
]
}
var options = {
scaleShowHorizontalLines: true,
barValueSpacing : 5,
scaleBeginAtZero : true,
barValueSpacing : 25
}
var myBarChart = new Chart(ctx).Bar(data,options);
Since Chart.js and Canvasjs both use the canvas element to draw the charts you can't interact with the elements using CSS.
If you want to use custom CSS to the chart elements you will need to use a SVG library like highcharts.
I'm new to Javascript and now I'm tasked to display charts with Chart.js. I did grouping in Python and used Flask to build the web app. However, my chart is somehow not displayed and I'm not sure why.
HTML
<canvas id="barchart2" width="600" height="400"></canvas>
JS
<script>
var config = {
type: 'bar',
labels : [
"52",
"51",
"54",
"53",
"46",
"82",
"57",
"48",
"50",
"56",
],
datasets : [
{
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
data : [
611,
18,
11,
10,
9,
8,
6,
3,
2,
2,
]
}
]
},
options: {
legend: {
display: true,
},
title: {
display: true,
text: 'Top 10 District in Singapore',
}
},
};
window.onload = function() {
var ctx = document.getElementById("barchart2").getContext("2d");
window.myBar = new Chart(ctx, config);
};
</script>
When I used this JS instead
var barData = {
labels : [{% for item in lbl1 %}
"{{item}}",
{% endfor %}],
datasets : [
{
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
data : [{% for item in val1 %}
{{item}},
{% endfor %}]
}
]
}
// get bar chart canvas
var mychart = document.getElementById("barchart2").getContext("2d");
// draw bar chart
new Chart(mychart).Bar(barData);
It worked perfectly (note: without options. I tried to add options, but the options doesn't show although the charts still appears. That's why I wanna change to this format instead).
But when I use the window.onload function, the chart doesn't appear at all.
Would appreciate your help. Thanks!
Could you paste here the complete generated JS code with the data? Or review your data, because I think that might be the problem somehow.
Here's a JSFiddle with your original code (sans your data) that works:
https://jsfiddle.net/wj80597q/5/
var config = {
type: 'bar',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
data: [0, 10, 5, 2, 20, 30, 45]
}]
},
options: {
legend: {
display: true,
},
title: {
display: true,
text: 'Top 10 District in Singapore',
}
},
};
(function() {
var ctx = document.getElementById("barchart2").getContext("2d");
window.myBar = new Chart(ctx, config);
})()
I have a fully functional Chart.JS Barchart which loads as intended, however I would like to add the username to each bar which is associated to them so administrators (who can see all entries) can distinguish between them.
function BarChart(data) {
var barChartData = {
labels: data.Month,
datasets: [
{
label: 'Weight (kg)',
fillColor: "rgba(220,220,220,0.5)",
backgroundColor: "rgba(46, 44, 211, 0.7)",
highlightFill: "rgba(220,220,220,0.75)",
highlightStroke: "rgba(220,220,220,1)",
data: data.Weight
},
{
label: 'Steps',
fillColor: "rgba(0,0,0,0.5)",
backgroundColor: "rgba(215, 44, 44, 0.7)",
highlightFill: "rgba(0,0,0,0.5)",
highlightStroke: "rgba(0,0,0,0.5)",
data: data.Steps
}
]
}
var ctx = document.getElementById("barchart").getContext("2d");
window.myBar =new Chart(ctx, {
type: 'bar',
data: barChartData,
options: { responsive: true }
});
I have successfully passed through the Usernames and they can be called by using data.User, however when I append this to the Steps or Weight label, I end up with "Steps for: admin,admin,admin" (since I have three entries, all from admin).
Is it possible to have it so each bar has the username it belongs to?
Maybe not quite what you asked for, but you could add it to the tooltip.
options: {
tooltips:{
callbacks: {
afterLabel: function(e){return "added By:" +data.User[e.datasetIndex][e.index]}
}
}
}
https://jsfiddle.net/r71no58a/7/
The chart js v2 is overlapping with is there a way to move the labelString of scaleLabel further down so that it does not overlap.Please view the screen shot marked in yellow and red part.
Part of the code is as following
scales: {
xAxes: [{
display: true,
ticks: {
autoSkip: false,
autoSkipPadding: 20
},
scaleLabel: {
display: true,
labelString: "ProductName(ProductName)"
}
}],
There are two possible solutions to your problem:
1: This is for a line chart, but can easily tailored to a bar chart.
The legend is part of the default options of the ChartJs library. So
you do not need to explicitly add it as an option.
The library generates the HTML. It is merely a matter of adding that
to the your page. For example, add it to the innerHTML of a given DIV.
(Edit the default options if you are editing the colors, etc)
<div>
<canvas id="chartDiv" height="400" width="600"></canvas>
<div id="legendDiv"></div>
</div>
<script>
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "The Flash's Speed",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: "Superman's Speed",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
var myLineChart = new Chart(document.getElementById("chartDiv").getContext("2d")).Line(data);
document.getElementById("legendDiv").innerHTML = myLineChart.generateLegend();
</script>
2: Adding a legend template in chart options
You'll also need to add some basic css to get it looking ok.
//legendTemplate takes a template as a string, you can populate the template with values from your dataset
var options = {
legendTemplate : '<ul>'
+'<% for (var i=0; i<datasets.length; i++) { %>'
+'<li>'
+'<span style=\"background-color:<%=datasets[i].lineColor%>\"></span>'
+'<% if (datasets[i].label) { %><%= datasets[i].label %><% } %>'
+'</li>'
+'<% } %>'
+'</ul>'
}
//don't forget to pass options in when creating new Chart
var lineChart = new Chart(element).Line(data, options);
//then you just need to generate the legend
var legend = lineChart.generateLegend();
//and append it to your page somewhere
$('#chart').append(legend);
Either of these two options will work.
In your case the legend code will look something like this
(Assuming you already have a BarChart Generated)
<div id="legendDiv"></div>
document.getElementById("legendDiv").innerHTML = BarChart.generateLegend();
Then use css to format the legend however you would prefer (including adding spacing between the legend in the chart)
When I'm using an array to fill in my line chart it's kinda doing something odd.
I noticed when I add 7 new points it works properly like this:
But when I add 8(or more) new points instead of 7 the result is this:
below you can find my code:
<script>
var arrayGegevens = <?php echo json_encode($array); ?>;
var data =
{
labels: [],
datasets: [
{
label: "Machine activity",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: []
}]
};
var ctx = document.getElementById("canvas2").getContext("2d");
var myLineChart = new Chart(ctx).Line(data,
{
bezierCurve: false,
animation: false
});
for(i = 0; i < 8; i++) // 8 should be arrayGegevens.Length (=20)
{
myLineChart.addData([arrayGegevens[i]['MachineStatus']], arrayGegevens[i]['Time']);
}
</script>
So am I doing something wrong or is this a bug?
Seems like the problem was with the length of the labels (2015-3-24 14:55:00). I substringed them down to 14:55 and now I can fit way more of them in 1 line chart!