Parsing JSON data into Chart.js bar chart - javascript

I'm trying to use Chart.js to generate a bar chart using dynamically generated data from Oracle DB. I'm having trouble getting the data in the right format, I think I'm close but I've been stuck for a while.
My JSON file:
[{"REGION":"Poland","REV_VALUE":"2263"},{"REGION":"United States","REV_VALUE":"1961"},{"REGION":"Spain","REV_VALUE":"555"},{"REGION":"United Kingdom","REV_VALUE":"380"},{"REGION":"Germany","REV_VALUE":"314"}]
And here is my barchar.js file:
$(document).ready(function(){
$.ajax({
url: "http://localhost/DWH/dataJSON.php",
method: "GET",
dataType : 'JSON',
success: function(data) {
console.log(data);
var region = [];
var value = [];
for(var i in data) {
region.push(data[i].REGION);
value.push(data[i].REV_VALUE);
}
var chartdata = {
labels: region,
datasets : [
{
label: 'Region',
backgroundColor: 'rgba(200, 200, 200, 0.75)',
borderColor: 'rgba(200, 200, 200, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: value.map(function(x) {return x * 1;})
}
]
};
var ctx = $("#myChart");
var barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata
});
},
error: function(data) {
console.log(data);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
I tried to implement a solution that I found in other topics, but still without success.
Any help would be very much appreciated!

I made this quickly to give you an example to help you out, you were in the right direction. I have the snippet using hardcoded data for example purposes, and then at the bottom I used the Ajax method.
Parsed the data as so, similar to what you were doing by using data.map().
let region = [];
let rev_value = [];
try {
data.map((item) => {
rev_value.push(item.REV_VALUE);
region.push(item.REGION);
});
} catch (error) {
console.log(error);
}
Then to use the data I just simply used a spread operator for the array contents [...].
labels: [...region],
data: [...rev_value],
Example 1 using Canvas.js simple example with your data hardcoded.
var ctx = document.getElementById('myChart').getContext('2d');
let data = [{
"REGION": "Poland",
"REV_VALUE": "2263"
}, {
"REGION": "United States",
"REV_VALUE": "1961"
}, {
"REGION": "Spain",
"REV_VALUE": "555"
}, {
"REGION": "United Kingdom",
"REV_VALUE": "380"
}, {
"REGION": "Germany",
"REV_VALUE": "314"
}];
let region = [];
let rev_value = [];
try {
data.map((item) => {
rev_value.push(item.REV_VALUE);
region.push(item.REGION);
});
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [...region],
datasets: [{
label: 'Regions',
data: [...rev_value],
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
}
}]
}
}
});
} catch (error) {
console.log(error);
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
Example 2 using your template and an Ajax call, change the URL for the request.
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
<script>
function grab() {
/* Promise to make sure data loads */
return new Promise((resolve, reject) => {
$.ajax({
url: "/data.json",
method: "GET",
dataType: 'JSON',
success: function(data) {
resolve(data)
},
error: function(error) {
reject(error);
}
})
})
}
$(document).ready(function() {
grab().then((data) => {
console.log('Recieved our data', data);
let regions = [];
let value = [];
try {
data.forEach((item) => {
regions.push(item.REGION)
value.push(item.REV_VALUE)
});
let chartdata = {
labels: [...regions],
datasets: [{
label: 'Region',
backgroundColor: 'rgba(200, 200, 200, 0.75)',
borderColor: 'rgba(200, 200, 200, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: [...value]
}]
};
let ctx = $("#myChart");
let barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata
});
} catch (error) {
console.log('Error parsing JSON data', error)
}
}).catch((error) => {
console.log(error);
})
});
</script>

You can try something like this :
dataPoints: variable ? variable.map((v) => ({x: (v.region), y: v.value})) : []

Related

update chart in chart js without reloading the page

i trying to create a chart when users search and it works but the problem when user search again it throw Uncaught Error: Canvas is already in use and when i try to destroy it it throw another error says that destroy is not function, I need a way to make the chart change when user serach without the need to reload the page
my code
var endpoint = "/api/chart/data";
myform.addEventListener("submit", function (e) {
e.preventDefault();
var name = document.querySelector("#name").value;
var amount = document.querySelector("#amount").value;
$.ajax({
method: "GET",
url: endpoint + "?name=" + name + "&amount=" + amount,
success: function (data) {
labels = data.labels;
data = data.data;
console.log("success");
console.log(name);
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels:labels,
datasets: [
{
label: "# of Votes",
data: data,
backgroundColor: [
"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)",
],
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,
borderRadius: 5,
},
],
},
options: {
responsive: true,
scales: {
x: {
min: -100,
max: 100,
ticks: {
color: '#fff',
},
beginAtZero: true,
},
y: {
ticks: {
color: '#fff',
},
beginAtZero: true,
},
},
},
});
},
error:function(){
console.error('enter valid data')
}
});
});
The problem is that the myChart variable is declared inside the scope of the AJAX success function. The variable only exists within the function body during its execution. When the user performs a new search, the success function is invoked again but the initially created myChart variable does no longer exist.
You can solve your problem by creating myChart at the beginning in the global scope as follows.
var myChart = new Chart('myChart', {
type: "bar",
data: {
labels: [], // initialize with an empty array
datasets: [{
label: "# of Votes",
data: [], // initialize with an empty array
...
});
Your event listener and AJAX request would then look as shown below. Note that I set the labels and data on the existing chart and call myChart.update() afterwards. This is cleanest and the most efficient way to deal with new data. For further details, please consult Updating Charts from chart.js documentation.
var endpoint = "/api/chart/data";
myform.addEventListener("submit", function(e) {
e.preventDefault();
var name = document.querySelector("#name").value;
var amount = document.querySelector("#amount").value;
$.ajax({
method: "GET",
url: endpoint + "?name=" + name + "&amount=" + amount,
success: function(data) {
myChart.data.labels = data.labels;
myChart.data.datasets[0].data = data.data;
myChart.update();
},
error: function() {
console.error('enter valid data')
}
});
});

vuechartJs make a label dynamic

I'm trying to do a pie chart with vue chart, I am trying to convert an object into an array to update de label in vuechartjs and make it dynamic according to the api, but it seems almost impossible. My goal is to fetch the concert name in the label and then fetch (data) how many booking we have for each concert. Would someone would be kind enough to help ? I have tried everything. thanks Here is my code :
<script>
import { Pie } from 'vue-chartjs'
export default {
extends: Pie,
data () {
return {
bandNames:[],
booking:[],
bandName:[],
data:[],
chartData: {
labels:[],
datasets: [{
borderWidth: 1,
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 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)',
],
data: [1000]
}]
},
options: {
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
}
}
},
created(){
var vm = this;
this.axios
.get('http://localhost:3000/booking', {})
.then(function (response) {
console.log(response.data);
vm.booking = response.data;
});
this.axios
.get('http://localhost:3000/concerts', {})
.then(function (response) {
console.log(response.data);
vm.bandNames = response.data;
vm.bandNames.forEach((item)=>{
vm.bandName.push(item.band)
})
vm.chartData.labels = vm.bandName[0]
var data = []
var i = vm.bandName.length
for(var a = 0 ; a < i ; a++){
data.push([vm.bandName[a]])
vm.chartData.labels = data
}
});
},
mounted () {
this.renderChart(this.chartData, this.options)
}
}
You can directly push the labels to the chartOptions in the loop , so change this :
vm.bandNames.forEach((item)=>{
vm.bandName.push(item.band)
})
vm.chartData.labels = vm.bandName[0]
by :
vm.bandNames.forEach((item)=>{
vm.chartData.labels.push(item.band)
})

How can i slice an array in django template?

So I am trying to achieve how to show 5 name into the chart instead off all name:
here is my views.py:
def index(req):
labels = [
{"name": 'data'},
{"name": 'hello'},
{"name": 'wassup'},
{"name": "waddddup"},
{"name": "heyyyyy"},
{"name": "dsfdsfd"},
{"name": "qqqq"},
{"name": "23f3f"},
{"name": "23f"},
{"name": "zzzz"},
]
values = []
def label_chart(labels):
label_test = []
for i in labels:
label_test.append(i['name'])
dataJSON = dumps(label_test)
return dataJSON
data = {
'data': label_chart(labels),
}
return render(req, 'index.html', data)
and here is my template javascript index.html:
<script type="text/javascript">
var data_labels = JSON.parse(`{{ data | safe }}`);
console.log(data_labels);
var endpoint = '/api/chart/data/'
$.ajax({
method: "GET",
url: endpoint,
success: function (data) {
labels = data.labels
defaultData = data.default
setChart()
},
error: function (error_data) {
console.log("error")
console.log(error_data)
}
})
function setChart() {
let y = [10, 3, 5, 9, 1];
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data_labels,
datasets: [{
label: '# of Votes',
data: y,
backgroundColor: [
'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)'
],
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
}
}]
}
}
});
}
</script>
I already tried to slice in python which is like this:
data = {
'data': label_chart(labels)[:5],
}
but it will give me an error like this on browser:
VM245:1 Uncaught SyntaxError: Unexpected end of JSON input
You are slicing the JSON blob, not the list of labels, you can slice the labels with:
data = {
'data': label_chart(labels[:5]),
}
try returning list from you function label_chart and then slice it.
def label_chart(labels):
label_test = []
for i in labels:
label_test.append(i['name'])
return label_test
data = {
'data': label_chart(labels)[:5],
}

Displaying Data on a Pie chart in ChartsJs

I was able to create this doughnut chart that displays data. However, now that I look at it, I would like add the number value of the foods (100,200,300) below, on a second line, instead of having next to the food item itself. Is there a way to do this? I was thinking that since this is a nested array, looping through it may work? Any thoughts?
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
label1: [["Pizza: 100"], ["Hot Dogs: 200"], ["Burgers:300"]],
datasets: [{
label: '# of Votes',
data: [12, 19, 3],
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: {
tooltips: {
callbacks: {
title: function(tooltipItem, data, label1, label2) {
return data ['label1'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return data['datasets'][0]['data'][tooltipItem['index']];
},
afterLabel: function(tooltipItem, data) {
var dataset = data['datasets'][0];
var percent = Math.round((dataset['data'][tooltipItem['index']] / dataset["_meta"][0]['total']) * 100)
return '(' + percent + '%)';
}
},
backgroundColor: '#FFF',
titleFontSize: 16,
titleFontColor: '#0066ff',
bodyFontColor: '#000',
bodyFontSize: 14,
displayColors: false
}
}
});
<div>
<canvas id="myChart" height="100"></canvas>
<div id="chartjs-tooltip">
<table></table>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js">
</script>

Getting data into script tag from route?

I have almost everything I need to get everything working just as I want it, I’m only missing one thing.
This is my get request:
app.get('/:username/tasks', function (req, res) {
if (req.session.user === req.params.username) {
var photo;
countList = [],
categoryList = [];
db.User.findOne({
where: {
username: req.session.user
}
}).then(function (info) {
console.log(info.dataValues.picURL);
photo = info.dataValues.picURL
})
db.Tasks.findAndCountAll({
attributes: ['category'],
where: {
UserUsername: req.session.user
},
group: 'category'
}).then(function (result) {
for (var i = 0; i < result.rows.length; i++) {
categoryList.push(result.rows[i].dataValues.category);
countList.push(result.count[i].count);
}
console.log(categoryList);
console.log(countList);
})
db.Tasks.findAll({
where: {
UserUsername: req.params.username
}
}).then(function (data) {
res.render('index', {
data: data,
helpers: {
photo: photo,
countList: countList,
categoryList: categoryList
}
})
});
} else {
res.redirect('/');
}
})
The “findAndCountAll” function gives me this in return:
[ 'Health', 'Other', 'Recreational', 'Work' ] [ 5, 1, 1, 1 ]
Which are exactly the two arrays I need.
The problem is that I need to pass these values into a javascript script tag.
When I send them to index.handlebars with the helper function in “Tasks.findAll” I get the values. The problem is that if I add a script tag and pass the values into that script tag, it doesn’t work.
How else can I get these values into that script tag?
That’s the last piece of the puzzle.
Here is the js file I'm trying to put the data into:
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: [MISSING DATA HERE],
datasets: [{
label: '# of Votes',
data: [MISSING DATA HERE],
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)',
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
],
borderWidth: 1
}]
},
});
I wrote in caps where the missing data is in the file.
Any help is much obliged.
You should run all those queries in parallel using Promise.all and when all of them done render chart
const userPromise = db.User.findOne({
where: {
username: req.session.user
}
});
const tasksWithCountPromise = db.Tasks.findAndCountAll({
attributes: ['category'],
where: {
UserUsername: req.session.user
},
group: 'category'
}).then(function (result) {
for (var i = 0; i < result.rows.length; i++) {
categoryList.push(result.rows[i].dataValues.category);
countList.push(result.count[i].count);
}
return { countList, categoryList };
});
const allTasksPromise = db.Tasks.findAll({
where: {
UserUsername: req.params.username
}
});
Promise.all(userPromise, tasksWithCountPromise, allTasksPromise)
.then(([user, tasksWithCount, allTasks]) => {
res.render('index', {
data: allTasks,
helpers: {
photo: user.dataValues.picURL,
countList: tasksWithCount.countList,
categoryList: tasksWithCount.categoryList
}
})
});

Categories