Related
I have an array in Django views.py and I want to send it to HTML and display a piechart, but
failed, I've tried many other methods and read many tutorials, in most of the case, they have
a field in models that store some number, and they display those number. In my case, I need to
calculate the subtotal of tasks that are in different states. I'm not sure how to output those
data to chart.js with proper labels or any other piechart if there's any recommendation?
views.py
def visualisation(request, project_id):
project = Project.objects.get(id=project_id)
counts_data = Todo.objects.aggregate(
to_do_count=Count('id', filter=Q(status='to_do')),
in_progress_count=Count('id', filter=Q(status='in_progress')),
done_count=Count('id', filter=Q(status='done'))
)
return render(request, 'todo_lists/progress.html', {"counts_data": counts_data})
html
<script>
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [1,2,3],
datasets: [{
label: '# of Votes',
data:{{counts_data}},
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive:false
}
});
});
</script>
You need to have the data in a structured manner for chart.js
Chart JS Data Structures https://www.chartjs.org/docs/latest/general/data-structures.html
Simply you could follow the Primitive structure as shown below or you could follow the Object structure with custom properties (need to do further data formatting and parsing).
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
// labels format ['label1', 'label2', 'label3', ]
// you can choose to have a static labels if you are sure that
// there is always a specific number of labels
labels: [{% for label in counts_data %} '{{ label }}', {% endfor %}],
datasets: [{
label: '# of Votes',
// data format [value1, value2, value3, ]
data: [{% for label, value in counts_data.items() %} {{ value }}, {% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: false
}
});
});
In your views, Todo.objects.aggregate(...) should return something like this (Values are provided as an example):
{'to_do_count': 3, 'in_progress_count': 6, 'done_count': 1}
counts_data = Todo.objects.aggregate(
to_do_count=Count('id', filter=Q(status='to_do')),
in_progress_count=Count('id', filter=Q(status='in_progress')),
done_count=Count('id', filter=Q(status='done'))
)
# counts_data = {'to_do_count': 3, 'in_progress_count': 6, 'done_count': 1}
This dictionary is then passed to the context with the key named as counts_data. Using this key name loop through the dictionary to create labels and data
labels: [{% for label in counts_data %} '{{ label }}', {% endfor %}], rendered as labels: [ 'to_do_count', 'in_progress_count', 'done_count', ],
data: [{% for label, value in counts_data.items() %} {{ value }}, {% endfor %}], rendered as data: [ 3, 6, 1, ],
<script>
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [1,2,3],
datasets: [{
label: '# of Votes',
data:counts_data,
success: function (data){
$('#todocount').html(counts_data.to_do_count);
$('#progress_count').html(counts_data.in_progress_count);
$('#progress_done').html(counts_data.done_count);
}
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive:false
}
});
});
</script>
this to me makes absolutely no logical sense.
my graph.js was working until it randomly just stopped after passing local storage as a prop. i refactored to make the prop passed in completely unrelated to the local storage... which still shouldn't matter.
for some reason every single number i put into the data field works EXCEPT when i put in props.score/number or ANYTHING reassigned that number. ive never seen anything like it. when i console log number is is 82. it is a number (it is blue in the console) yet when i put it into chart.js it just won't appear.
what the heck is going on?!
this feels like typing 2+2 into a calculator and getting 5. i literally have no idea i have now been trying to figure this out for maybe 4 hours with absolutely no answer. once again...
this error just happened randomly today my app was working fine prior to this...?!
did chart.js change something as of yesterday?
is this a random bug ?
i have never run into such a problem after backtracking for so long. makes no sense.
import {useEffect} from 'react'
import Chart from 'chart.js';
import './BreakDown.css'
const LineChart = (props) => {
const number=props.score ***i am trying to get props.score into the chart js data point.
console.log(number) ****this console logs 82
const newNumber=10+number
console.log(newNumber) ***this console logs 92
useEffect(()=>{
var ctx = document.getElementById('myLineChart');
var myChart = new Chart(ctx, {
type: 'line',
responsive:true,
data: {
labels: ['X', 'IQ', 'X'],
datasets: [{
label: 'Your Score',
data: [0,newNumber,0], ***no matter what i do plug in in either of these numebnrs here doesn't work.
backgroundColor: [
'rgba(54, 80, 235, 0.2)',
'rgba(54, 80, 235, 0.2)',
'rgba(54, 162, 235, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
],
borderWidth: 1,
},
{
label: 'Average',
data: [0, 100, 0],
backgroundColor: [
'rgba(54, 162, 235, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(54, 80, 235, 0.2)',
],
borderColor: [
'rgba(255, 99, 132, .5)',
'rgba(255, 99, 132, .5)',
'rgba(255, 99, 132, .5)',
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false,
suggestedMin: 70,
suggestedMax: 160,
stepSize: 10
}
}]
}
}
});
},[])
return (
<div >
<canvas id="myLineChart" width="650" height="400"></canvas>
</div>
)
}
export default LineChart
to make things EVEN more bizarre if i plug in newNumber into the chart it gives me 10 in this case EVEN though console.logging newNumber gives me 92... HUH?!
Your code works fine on the first render for me. I am not 100% sure from your description what you think is going wrong, but 1 problem I see is that useEffect will only run once due to the [] in the second parameter.
If your prop.score updates, useEffect() won't run again, which means your chart won't update.
The main change I did below was add props.score in the array for useEffect, this tells useEffect to run again if props.score changes. You can read more about this in the useEffect docs
import React, { useEffect } from 'react'
import Chart from 'chart.js';
const LineChart = (props) => {
const number = props.score //***i am trying to get props.score into the chart js data point.
console.log(number) //****this console logs 82
const newNumber = 10 + number
console.log(newNumber) //***this console logs 92
useEffect(() => {
var ctx = document.getElementById('myLineChart');
var myChart = new Chart(ctx, {
type: 'line',
responsive: true,
data: {
labels: ['X', 'IQ', 'X'],
datasets: [{
label: 'Your Score',
data: [0, newNumber, 0],
backgroundColor: [
'rgba(54, 80, 235, 0.2)',
'rgba(54, 80, 235, 0.2)',
'rgba(54, 162, 235, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
],
borderWidth: 1,
},
{
label: 'Average',
data: [0, 100, 0],
backgroundColor: [
'rgba(54, 162, 235, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(54, 80, 235, 0.2)',
],
borderColor: [
'rgba(255, 99, 132, .5)',
'rgba(255, 99, 132, .5)',
'rgba(255, 99, 132, .5)',
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false,
suggestedMin: 70,
suggestedMax: 160,
stepSize: 10
}
}]
}
}
});
}, [props.score])
return (
<div >
<canvas id="myLineChart" width="650" height="400"></canvas>
</div>
)
}
export default LineChart
I'm using Chart.js for my pie/bar charts and on the line and the bar chart all of the 'x' axis labels are not all showing for some reason, however in the pie chart they are:
Code below has been used and the 'type' has just been altered for the type of graph I wished to use:
var ctx = document.getElementById("my3Chart");
var mylineChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Time Management", "Career Coach", "Stress & Wellbeing", "Note Taking", "Exam Prep", "Presentations"],
datasets: [{
label: 'Module Tracker',
data: [6, 4, 2, 0, 3, 1],
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)'
],
borderColor: [
'rgba(255,99,132,1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
I've tested your code in a fiddle with Chart.js 2.0 for both bar/line and it looks fine. Chart takes in x-axis labels with:
labels: ["Time Management", "Career Coach", "Stress & Wellbeing", "Note Taking", "Exam Prep", "Presentations"]
The reason you can't see all your x-axis labels is that the width's are too thin. You can fix this by either expanding your width, or rotating your labels to be vertical instead.
400px width example: https://jsfiddle.net/swcy2opv/
Rotated labels example: https://jsfiddle.net/swcy2opv/1/
I have two charts, First chart shows the breakup of Shirt sales.
Second is the comparison of Blue Shirt vs Blue Trouser sales.
I want to import the Blue Shirt value from the first Chart to Second chart.
Here is the Code with two charts:
var ctx = document.getElementById("myChart1").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: 'Shirts',
data: [10, 10, 15, 5, 2, 3],
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)'
],
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)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
}
});
var ctx = document.getElementById("myChart2").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Blue Shirts", "Blue Trousers"],
datasets: [{
label: 'Sales',
data: [10, 8],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
}
});
Here is the JSFiddle (https://jsfiddle.net/kingBethal/L8x790fn/15/).
I found this thread describing getting data from click events: Click events on Pie Charts in Chart.js
I made also made a new fiddle here where it logs a chart object containing the chart data on chart click: https://jsfiddle.net/btnL9d2a/16/
myChart1Canvas.onclick = function(evt) {
var activePoints = myChart.getElementsAtEvent(evt);
if (activePoints[0]) {
var chartData = activePoints[0]['_chart'].config.data;
// `chartData` will be an object in the format {'Labels' : Array, 'datasets' : Array}.
console.log(chartData);
}
};
chartData.datasets[0].data is an array of the clicked-on chart's data.
I am trying to add data obtained from an ajax call to a chart using Chart.js.
The following code is not working:
$(document)
.ready(function () {
fetchBeds($("#site").val());
var ctx = $('#paretoChart');
var paretoChart = new Chart(ctx);
fetchChartData(1, '2016-10-28', '2016-11-2', paretoChart);
});
function fetchChartData(bed, start, end, chart) {
$.ajax({
url: "/reports/fetchChartData",
type: "GET",
data: {
bed: bed,
start: start,
end: end
},
dataType: "json",
success: function (response) {
var chartData = {
labels: response.data.labels,
datasets: [{
label: 'Pareto of Events',
data: response.data.chartData,
}]
};
chart.data = chartData;
console.log(chart);
chart.update();
}
});
}
When run, it doesn't generate any errors (my ajax call is working fine, verified in firefox). Simply nothing happens. I have a feeling it has to do with how I am applying the data to the chart. If I take the example data from the chart.js website and use that directly in the new Chart(...) call, it works fine.
Is it even possible to apply new data after the chart has been created?
Here is the data returned from the ajax call, just in case:
{"result":true,"message":null,"data":{"labels":["Plant","Process"],"chartData":["1","1"]}}
Thank you!
Alright I got the newest ChartJS and tried it out with your scenario.
My html:
<canvas id="myChart" width="200" height="200"></canvas>
Creating the chart:
$(function () {
var ctx = $("#myChart");
var myChart = new Chart(ctx, { type: 'bar', data: { labels: [], datasets: [] } });
UpdateChart(myChart)
});
I had to specify the type and a data object with empty labels and datasets for it to even render on the screen as an empty chart.
My function that updates the chart:
function UpdateChart(chart) {
var data = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
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)'
],
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)'
],
borderWidth: 1
}]
}
chart.data.labels = data.labels
chart.data.datasets = data.datasets
chart.update()
}
I tried doing chart.data = data but that didn't work for me. I had to specifically update data.labels then data.datasets before updating.
Worked fine by me, see my exact code below.
You have to make sure that you are using the updated .js file of the chart.js plugin. Of course, you have to include Jquery plugin on top of your every javascript file.
For this replication, I used the cdn provided by jquery and chart.js.
<canvas id="chart" height="400px" width="400px"></canvas>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js"> </script>
<script>
$.ajax({
url: "http://localhost:8081/chart.php",
dataType: "json",
success: function(response)
{
var ctx = document.getElementById("chart");
var myBarChart = new Chart(ctx, {
type: 'pie',
data: {
labels: response.data.labels,
datasets: [{
label: 'Number of Active Customers',
data: response.data.chartData,
backgroundColor: [
'rgba(75, 192, 192, 0.2)',
'rgba(255, 99, 132, 0.2)'
],
borderColor: [
'rgba(75, 192, 192, 1)',
'rgba(255,99,132,1)'
],
borderWidth: 1
}]
}
});
}
});
</script>
chart.php file contains only the response JSON code as you may see below.
{
"result":true,
"message":null,
"data":{
"labels":[
"Plant",
"Process"
],
"chartData":[
"10",
"1"
]
}
}