I am trying to figure out how to create some custom axis lables for my data. Im trying to plot time series data. Im using an XY scatter graph to do this. My data collection may be irregular..
My time is recorded as Unix Epoch time. ( ms after 1 Jan 1970 ). I'd like to be able to put human readable dates/times on the x axis. rather than display the epoch time. How would this be best approached?
http://6phrweatherstation.s3-website-ap-southeast-2.amazonaws.com
All you have to do is to add the custom tick callback.
You can go through this in the chartjs documentation. Here have a look: link.
The callback provides you the value of each label. You can edit it and return the edited value.
function renderChart(data, labels) {
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'scatter',
data: {
labels: labels,
datasets: [{
label: '48 Hours Pressure History HPa',
data: data,
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
},
]
},
options: {
scales: {
xAxes: [{
ticks: {
callback: function(value) {
return new Date(value).getDate() +"-"+ new Date(value).getMonth() + "-"+new Date(value).getFullYear();
}
}
}]
}
}
});
}
Related
I know this question has been asked a fair bit on here, but the solution that's been going around hasn't been working for me.
My chart renders in real time based on the start/end dates provided on the front-end (HTML date input widget). Since the default start time for that widget is 01/01/2019, charts.js will create a chart for the 01/01/2019 start/end times, and then proceed to produce the chart for the specified start/end dates. The 01/01/2019 chart shows on hover and I'd like to get rid of it.
function dayChart(labels_day, data_day) {
var ctx_day = document.getElementById('day-chart').getContext('2d');
var config = {
type: 'bar',
data: {
labels: labels_day,
// labels: ['Early Morning (00:00-05:59)', 'Morning (06:00-11:59)', 'Afternoon (12:00-18:59)', 'Night (19:00-23:59)'],
datasets: [{
label: '# of Orders by Day of the Week',
data: data_day,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 99, 132, 0.2)',
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)',
'rgba(255, 99, 132, 1)',
],
borderWidth: 1
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Taxi Orders calculated by day of the week'
},
scales: {
yAxes: [{
id: data_day,
display: true,
ticks: {
stepsize: 500,
min: 0,
}
}]
},
}
}
var chart_day = new Chart (ctx_day, config)
if (chart_day) {
chart_day.destroy();
chart_day = new Chart (ctx_day, config);
chart_day.update();
}
}
form section of html file
<form name="date-input" method="POST" action="/date-input/">
<label for="start">Start date:</label>
<input type="date" id="start" name="start_date" value="2019-01-01" min="2019-01-01" max="2019-06-30">
<label for="end">End date:</label>
<input type="date" id="end" name="end_date" value="2019-01-01" min="2019-01-01" max="2019-07-01">
</form>
async call for start/end dates
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script>
// global variables - so that chartjs doesn't show old data on hover
var chart_day;
var chart_hour;
var chart_payment;
var start_date = Date.parse($("#start").val()) / 1000; // const can't be re-assigned or redeclared. Date() to convert datetime into epoch time
var end_date = Date.parse($("#end").val()) / 1000; // divide by 1000 to get 10 digits (compatible with values in DB)
function ajaxRequest() {
var start_date = Date.parse($("#start").val()) / 1000;
var end_date = Date.parse($("#end").val()) / 1000;
console.log(start_date)
console.log(end_date)
$.ajax({ // initialize an AJAX request
type: "POST",
url: '/get-data/', // calls data from /date-input/ endpoint
data: {
'start_date': start_date, // add the order id to the POST parameters
'end_date': end_date,
'csrfmiddlewaretoken': "{{csrf_token}}",
},
success: function (data) { // `data` is from `homepage` view function
labels_payment = data.labels_payment
data_payment = data.data_payment
labels_hour = data.labels_hour
data_hour = data.data_hour
labels_day = data.labels_day
data_day = data.data_day
// call payment, hour, and dow methods to render in the frontend
setPaymentMethodChart(labels_payment, data_payment)
hourlyChart(labels_hour, data_hour)
dayChart(labels_day, data_day)
// console.log(data)
console.log(data.start_date)
console.log(data.end_date)
console.log(data.labels_payment)
console.log(data.data_payment)
},
error: function (data, xhr, status, error) {
console.log("yikes")
}
});
}
You correctly defined chart_day globally and even commented it as follows:
global variables - so that chartjs doesn't show old data on hover
The problem however lies in your dayChart function. Instead of using the globally defined chart_day variable, you defined an identically named variable in the local scope of the function.
The solution would be to replace the following code block:
var chart_day = new Chart (ctx_day, config)
if (chart_day) {
chart_day.destroy();
chart_day = new Chart (ctx_day, config);
chart_day.update();
}
...with this one:
if (chart_day) {
chart_day.destroy();
}
chart_day = new Chart (ctx_day, config);
I have been working on a broadband management website.I want to show the user how much data he/she has used.For example if the total data they have in their name is 300GB.If they have used 150GB the remaining is 150GB right?.How to do i visualize this using a doughnut chart,Using ChartJS.
I have some code going but im not sure how to accomplish this please help me out
var ctx = document.getElementById('myChart').getContext('2d');
var constdata=document.getElementById("constantdata").textContent;
var data=document.getElementById("data").textContent;
console.log(data);
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'doughnut',
// The data for our dataset
data: {
datasets: [{
label: 'My First dataset',
backgroundColor: ['red','green'],
borderColor: 'rgb(255, 99, 132)',
data: [300,150] //300 being the total data,150 being the data used
}]
},
// Configuration options go here
options: {}
But the above code isnt working out.Assume a doughnut chart,If the used data is 150GB(out of 300).The doughnut
chart must be like image1(please refer image 1)
But im getting image2(please refer image 2)
https://i.stack.imgur.com/nFTym.png //image 1
https://i.stack.imgur.com/MG99s.png //image 2
Assuming that the used data should appear in red, data should be defined as follows:
data: [used, total - used]
Please have a look at your amended code sample below.
const total = 300;
const used = 100;
var chart = new Chart(document.getElementById('myChart'), {
type: 'doughnut',
data: {
datasets: [{
label: 'My First dataset',
backgroundColor: ['red', 'green'],
borderColor: 'rgb(255, 99, 132)',
data: [used, total - used]
}]
},
options: {}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="90"></canvas>
I created a line chart with chart.js and when I populate it, the last column is wider than the previous columns. It has divided the dataset by the number of display columns and put the remainder into the final column. The number of data points varies and is greater than the number of columns and I have no idea either how many data points there will be or how many columns chart.js will chose to display. I can truncate the data in order to force the last column to match, but I don't know how many columns it's going to create before it renders the graph.
Is there a way to accomplish what I'm trying to do?
Update:
var options = {
layout: {
padding: {
top: 5
}
},
responsive: true,
legend: {
display: true,
position: 'bottom',
// disable legend onclick remove slice
onClick: null
}
};
var dataset = new Object();
dataset = [{
label: '',
data: [],
fill: false,
borderColor: "rgb(75, 192, 192)",
pointBackgroundColor: '#000000',
pointRadius: 1
}, {
label: 'Set Point',
data: [],
fill: false,
borderColor: "rgb(192, 192, 75)",
pointRadius: 1
}];
var lineChart = new Chart(graph, {
type: 'line',
data: {
labels: [],
datasets: dataset
},
options: options
});
lineChart.config.data.datasets[0].label = sensor.Name;
for (var i = 0; i < tempLen; i++) {
var tempData = sensor.TemperatureData[i];
lineChart.config.data.labels.push(new Date(tempData.Timestamp).format('Y-m-#d #H:i'));
lineChart.config.data.datasets[0].data.push(tempData.Value);
lineChart.config.data.datasets[1].data.push(sensor.SetPoint);
}
lineChart.update(0);
For some data visualisation I use ractive and chart.js. The initial drawing works great, but I can't find a way to update the chart automatically when my data changes. So far I got (simplified):
const Stats = '<canvas id="myChart" width="400" height="400"></canvas>'
new Ractive ({
el: '#stats',
template: Stats,
magic: true,
modifyArrays: true,
data: {docs}, // <= some JSON Data
computed: {
Data1() {
let tempList = this.get('docs');
// rearrange & filter Data
return tempList ;
},
Data2() {
let tempList2 = this.get('docs');
// rearrange & filter Data
return tempList2 ;
},
Data3() {
let tempList3 = this.get('docs');
// rearrange & filter Data
return tempList3 ;
},
}
},
onrender: function () {
let DataSet1 = this.get('Data1');
let DataSet2 = this.get('Data2');
let DataSet3 = this.get('Data3');
let ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Data 1", "Data 1", "Data 3"],
datasets: [{
label: 'All my Data',
data: [DataSet1.length, DataSet2.length, DataSet3.length],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(75, 192, 192, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(255, 159, 64, 1)',
'rgba(75, 192, 192, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: false
}
});
},
onchange: function () {
let newData = this.get('docs')
addData(myChart, label, newData)
function addData(chart, label, data) {
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.update();
}
}
});
Of Course I get an error in line chart.data.labels.push(label);, and also I'm quite sure that I would need my computed values in the onrenderfunction, not the initial Dataset. But I really have no clue how to get those into the update function, or if this function is the correct approach at all...
If you are working with 3rd party plugins I would recommend to use Ractive's decorators.
This post on ractivejs-and-jquery-plugins shows you a starting point how to implement a decorator based on a fileupload control.
In your case I would recommend to build a decorator with the data as parameter and do not forget to implement the UPDATE function (where in your case you gonna call the update method with the new data for your chart)
As I could not figure out how to write my own decorator for Chart.js I thought I post the solution that worked for me. I do not think it's best practice and for sure decorators would be a better way (therefore I do not mark this solution as correct answer), but it works:
const Stats = '<canvas id="myChart" width="400" height="400"></canvas>'
new Ractive ({
el: '#stats',
template: Stats,
magic: true,
modifyArrays: true,
data: {docs}, // <= some JSON Data
computed: {
Data1() {
let tempList = this.get('docs');
// rearrange & filter Data
return tempList ;
},
Data2() {
let tempList2 = this.get('docs');
// rearrange & filter Data
return tempList2 ;
},
Data3() {
let tempList3 = this.get('docs');
// rearrange & filter Data
return tempList3 ;
},
}
},
onrender: function () {
let DataSet1 = this.get('Data1');
let DataSet2 = this.get('Data2');
let DataSet3 = this.get('Data3');
let ctx = document.getElementById("myChart");
myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Data 1", "Data 1", "Data 3"],
datasets: [{
label: 'All my Data',
data: [DataSet1.length, DataSet2.length, DataSet3.length]
}]
}
});
},
onchange: function () {
let changedData1 = this.get('Data1');
let changedData2 = this.get('Data2');
let changedData3 = this.get('Data3');
myChart.data.datasets[0].data[0] = changedData1.length;
myChart.data.datasets[0].data[1] = changedData2.length;
myChart.data.datasets[0].data[2] = changedData3.length;
myChart.update();
}
}
});
I have a chartjs linechart diagram to show the sales of different products on a range of dates. The user can select a date range (for example from 2015-12-01 to 2015-12-10) to view the sales per day and thats fine and its working.
But if the user selects only one day (range from for example 2015-12-01 to 2015-12-01), he gets the correct diagram, but it doesn't look good:
As you can see, the points are stick to the y-axis. Is there a possibility, to center the points on the diagram?
Thats how it should look like:
Instead of hardcoding the labels and values with blank parameters, use the offset property.
const options = {
scales: {
x: {
offset: true
}
}
}
Documentation: https://www.chartjs.org/docs/latest/axes/cartesian/linear.html#common-options-to-all-cartesian-axes
You can check the length of your labels (or data) arrays and add dummy non-renderable points to the left and right by using empty string labels and null value, like so
var chartData = {
labels: ['', "A", ''],
datasets: [
{
fillColor: "rgba(255, 52, 21, 0.2)",
pointColor: "#da3e2f",
strokeColor: "#da3e2f",
data: [null, 20, null]
},
{
fillColor: "rgba(52, 21, 255, 0.2)",
strokeColor: "#1C57A8",
pointColor: "#1C57A8",
data: [null, 30, null]
},
]
}
Fiddle - https://jsfiddle.net/pf24vg16/
Wanted to add to the above answer and say that I got a similar effect on a time series scatter plot using this:
if (values.length === 1) {
const arrCopy = Object.assign({}, values);
values.unshift({x: arrCopy[0].x - 86400000, y: null});
values.push({x: arrCopy[0].x + 2 * 86400000, y: null});
}
That only handles for a single point, however. To add in functionality for multiple points, I did the following:
const whether = (array) => {
const len = array.length;
let isSame = false;
for (let i = 1; i < len; i++) {
if (array[0].x - array[i].x >= 43200000) {
isSame = false;
break;
} else {
isSame = true;
}
}
return isSame;
}
if (values.length === 1 || whether(arr[0])) {
const arrCopy = Object.assign({}, values);
values.unshift({x: arrCopy[0].x - 86400000, y: null});
values.push({x: arrCopy[0].x + 2 * 86400000, y: null});
}
You might notice I'm just subtracting/adding a day in milliseconds into the x values. To be honest, I was just having the worst of times with moment.js and gave up haha. Hope this helps someone else!
Note: my code has a tolerance of 43200000, or 12 hours, on the time. You could use moment.js to compare days if you have better luck with it than I did tonight :)
For your specific problem, try to modify the options->scales->xAxes option like so:
options: {
title: {
display: true,
text: 'mytitle1'
},
scales: {
xAxes: [{
type: 'linear',
ticks: {
suggestedMin: 0,
suggestedMax: (11.12*2),
stepSize: 1 //interval between ticks
}
}],
More info at: Chart JS: Ignoring x values and putting point data on first available labels