Chartjs bar chart appears empty when page loads - javascript

I am using the ChartJS library to display a bar chart on my HTML page. The issue I am facing is when the page loads, it displays an empty bar chart without the data I have passed into it and without rendering the bars. After one click to the legend, the chart resizes and my labels appear on the x-axis, on the second click the bars are rendered and the y-axis populates to my passed in data. I am not sure why the chart is behaving this way.
I tested the chart with the code provided in the chart.js documentation and it appears instantly. I think the issue has to do with how I am calling my express backend to retrieve data from my endpoint.
Not sure how to resolve this issue. Any help is appreciated.
index.html:
<canvas
id="patents-per-category-bar-chart"
width="400"
height="400"
></canvas>
<script type="text/javascript">
var categoryLabels = [];
var categoryValues = [];
var centerLabels = [];
var centerValues = [];
$.getJSON("http://localhost:5000/api").done((data) => {
for (let item in data.patentsPerCategory) {
if (!data.patentsPerCategory.hasOwnProperty(item)) {
continue;
}
categoryLabels.push(item);
categoryValues.push(data.patentsPerCategory[item]);
}
for (let item in data.patentsPerCenter) {
if (!data.patentsPerCenter.hasOwnProperty(item)) {
continue;
}
centerLabels.push(item);
centerValues.push(data.patentsPerCenter[item]);
}
});
var ctx = document
.getElementById("patents-per-category-bar-chart")
.getContext("2d");
var barChartConfig = {
type: "bar",
data: {
labels: categoryLabels,
datasets: [
{
backgroundColor: "blue",
label: "# Patents Per Category",
data: categoryValues,
},
],
},
options: {
legend: {
onClick: null,
},
responsive: true,
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
},
},
],
},
},
};
var categoryBarChart = new Chart(ctx, barChartConfig);
</script>
mock data returned from the api:
{
"category": {
"health medicine and biotechnology": 37,
"instrumentation": 38,
"storage": 30,
"systems": 71,
"aeronautics": 1,
"electronics": 47,
"optics": 60,
"materials": 119,
"undefined": 3,
"communications": 32,
"sensors": 102,
"robotics": 37,
"software": 49,
"propulsion": 9,
"manufacturing": 40,
"environment": 24,
"aerospace": 79
}
}
After returning this data from the api, I iterate over it and push the keys and values into separate arrays which are categoryLabels, categoryValues. Then pass these arrays directly into the labels and data for the chart
Created a jsFiddle:
https://jsfiddle.net/tkdamxr5/2/
It works fine in the jsFiddle enviornment so the issue must be in the way I am calling my data using jQuery. Can anyone clarify how I need to call my express backend to get the data and pass it into the chart so it works correctly?

Figured it out. In my original code I was using
$.getJSON('http://localhost:5000/api').done((data) => {}
to call my expressjs backend.
I changed it to use
$.ajax({
url: "http://localhost:5000/api",
success: function (result) {
let labels = [];
let data = [];
for (let item in result.category) {
if (!result.category.hasOwnProperty(item)) {
continue;
}
labels.push(item);
data.push(result.category[item]);
}
},
error: function(err) { console.log(err); }
})
and was able to display my bar chart successfully and as expected.

Related

How to add/display multiple chart.js line charts, on same page properly?

From a few weeks(sadly I'm not very experienced with vue and chart.js ), I'm trying to properly display N number of times, component with LineChart and value, for N number of sensors fetched via API, on a single page.
The project is on Vue.Js 3 including Chart.js. I'm NOT using any of the VueJs wrappers for charts, only the Chart.js lib itself!
What I've done so far: displaying the components with LineChart and values inside them successfully, N number of times, but...
My problem is that, the data for every chart includes data from the other charts, or something like that. Also when I try to update the charts later, same behavior happens. Which is not what I want, every chart, should have only the data for itself...
Her is the chart config on creation (I need them with the same style for now)
const datasets = {
labels: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
datasets: [
{
// one line only
data: [0],
fill: true,
backgroundColor: ["rgba(20, 120, 60, 0.3)"],
borderColor: ["rgba(20, 120, 60, 0.9)"],
borderWidth: 2,
pointRadius: 0
}
]
}
const chartData = {
type: "line",
data: {}, // empty object
options: {...}
}
Here is the code for the create and update:
setup(props){
let cChart = null
let chart = null
function chartDataUpdate(ch) {
const chh = ch //eslint trows error if i not do that here
chh.data = datasets
chh.data.datasets[0].data.push(parseInt(props.thermData, 10))
if (chh.data.datasets[0].data.length > 10) {
chh.data.datasets[0].data.splice(0, 1)
}
chh.update()
chh.data = {}
}
function createChart(ctx) {
const myChart = new Chart(ctx, chartData)
return myChart
}
onMounted(() => {
cChart = {}
cChart = document.getElementById(props.id).getContext("2d")
if (cChart !== null) {
chart = createChart(cChart)
}
})
watchEffect(() => {
setInterval(() => {
if (cChart !== null) {
chartDataUpdate(chart)
}
}, 3000)
if (typeof props.thermData !== "number") {
isDataType.value = true
}
})
}
May be the problem is, because I'm using the same datasets object for all or something else.
I'm open for any ideas, or solutions. Thank you in advance.

Python to chart.js

I have sqlite database with single table. I am trying to read data with Python and pandas and return the data as json file in a function. Then the goal is to use Javascript to fetch the json data and use it for chart.js.
Here is my Python Code that should read the data form the database:
#cherrypy.expose
def chart_data(self):
cnx = sqlite3.connect('Production.db', check_same_thread=False)
daily_df = pd.read_sql_query("SELECT * FROM data_object", cnx)
return daily_df.to_json()
Then here is the part of the JavaScript code that I am trying to use to fetch data from that python call:
function get_chart_data() {
fetch('/chart_data').then( x => {
return x.json();
}).then( x => {
console.log(x);
});
}
In this instance i am trying to print the data in console.log just to see if i am getting data from Python. However I need this data to be fed into chart.js
var data = {
labels: [],
datasets: [{
label: "Dataset",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: [],
}]
};
var options = {
maintainAspectRatio: false,
scales: {
yAxes: [{
stacked: true,
gridLines: {
display: true,
color: "rgba(255,99,132,0.2)"
}
}],
xAxes: [{
gridLines: {
display: false
}
}]
}
};
Chart.Bar('chart', {
options: options,
data: data
});
And finally, the sqilite table has these columns:timestamp,capacity,max_capacity, true_count.
There is only 24 rows of data, one for each hour of the day.
And here is where I am stuck. I am not sure how to properly pull this data into the chart. The goal is to plot true count over the 24h period.
With the code I have so far I know i am very close but i am missing something to make this work.
Am I pulling the data properly with javascript from python?
And how do i then push that json data in javascript into label variable and data variable in chart.js?
I have made some progress. I am now able to get data to javascript console log while using your ajax example.
/* chart.js chart examples */
$(document).ready(function(){
var _data;
var _labels;
$.ajax({
url: "chart_data",
type: "get",
success: function(response) {
full_data = JSON.parse(response);
_data = full_data['true_count'];
_labels = full_data['timestamp'];
},
});
// chart colors
var colors = ['#007bff','#28a745','#333333','#c3e6cb','#dc3545','#6c757d'];
/* large line chart */
var chLine = document.getElementById("chLine");
var chartData = {
labels:_labels,
datasets: [
{
data:_data,
backgroundColor: [
'rgba(42, 157, 244, 0.1)'
],
borderColor: [
'rgba(42, 157, 244, 1)',
'rgba(33, 145, 81, 0.2)',
],
borderWidth: 1
}]
};
if (chLine) {
new Chart(chLine, {
type: 'line',
data: chartData,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false
}
}]
},
legend: {
display: false
}
}
});
}
;
});
So if i do console.log(full_data) i get my data from python in json format as i wanted. However, i am getting error that says: full_data is not defined at the line where I am saying that labels: full_data['timestamp']
It seems that my full data is not accessable from the chart block. I am sure i am misplacing few brackets to make this work but I am unable to figure out where.
Any ideas?
My json file looks like this:
[{"timestamp":"00:00:00.000000","true_count":0},{"timestamp":"01:00:00.000000","true_count":0},{"timestamp":"02:00:00.000000","true_count":0},{"timestamp":"03:00:00.000000","true_count":0},{"timestamp":"04:00:00.000000","true_count":0},{"timestamp":"05:00:00.000000","true_count":0},{"timestamp":"06:00:00.000000","true_count":2},{"timestamp":"07:00:00.000000","true_count":5},{"timestamp":"08:00:00.000000","true_count":7},{"timestamp":"09:00:00.000000","true_count":8},{"timestamp":"10:00:00.000000","true_count":12},{"timestamp":"11:00:00.000000","true_count":15},{"timestamp":"12:00:00.000000","true_count":20},{"timestamp":"13:00:00.000000","true_count":17},{"timestamp":"14:00:00.000000","true_count":14},{"timestamp":"15:00:00.000000","true_count":13},{"timestamp":"16:00:00.000000","true_count":11},{"timestamp":"17:00:00.000000","true_count":19},{"timestamp":"18:00:00.000000","true_count":22},{"timestamp":"19:00:00.000000","true_count":16},{"timestamp":"20:00:00.000000","true_count":14},{"timestamp":"21:00:00.000000","true_count":10},{"timestamp":"22:00:00.000000","true_count":7},{"timestamp":"23:00:00.000000","true_count":4}]
I have been trying to parse this so timestamp goes to _labels and true_count goes to _data but no luck.
Here is what i have:
$(document).ready(function(){
var _data =[];
var _labels = [];
$.ajax({
url: "chart_data",
type: "get",
success: function(response) {
full_data = JSON.parse(response);
full_data.forEach(function(key,index){
_data = key.true_count;
_labels= key.timestamp;
});
//_data = [full_data['true_count']];
//_labels = [full_data['timestamp']];
},
});
Any suggestion what am I doing wrong now?
I am sharing my example which I used using Google charts .I am fetching live data from OPC Server using ajax and updated my real-time graph. It won't be a big difference if you use database instead of opc server. I hope you can relate it with your example.
Html
<div class="row" id="grap">
<div class="col-lg-12">
<div class="row">
<div class="col-12">
<div class="card">
<div class="chart-wrapper">
<div id="graph"></div>
</div>
</div>
</div>
</div>
</div>
</div>
This is django file from where I am passing data to gettemp() function via ajax call in json format. In your case it is database and there wont be issue.
Views.py
def plcdata(request):
url="opc.tcp://127.0.0.1:9000"
client=Client(url)
client.connect()
print("Client Connected")
data={}
dt=[]
while True:
pres=client.get_node("ns=2;i=2")
Pressure=pres.get_value()
adp=client.get_node("ns=2;i=3")
ap=adp.get_value()
rh=client.get_node("ns=2;i=4")
r=rh.get_value()
sp=client.get_node("ns=2;i=5")
s=sp.get_value()
nitro=client.get_node("ns=2;i=6")
n=nitro.get_value()
o2n=client.get_node("ns=2;i=7")
o=o2n.get_value()
hgl=client.get_node("ns=2;i=8")
h=hgl.get_value()
stempress=client.get_node("ns=2;i=9")
sps=stempress.get_value()
cond=client.get_node("ns=2;i=10")
co=cond.get_value()
dmwp=client.get_node("ns=2;i=11")
dmp=dmwp.get_value()
dmwf=client.get_node("ns=2;i=12")
dmf=dmwf.get_value()
chwp=client.get_node("ns=2;i=13")
chp=chwp.get_value()
chwt=client.get_node("ns=2;i=14")
cht=chwt.get_value()
icp=client.get_node("ns=2;i=16")
ip=icp.get_value()
icf=client.get_node("ns=2;i=15")
iff=icf.get_value()
ict=client.get_node("ns=2;i=17")
it=ict.get_value()
dcpp=client.get_node("ns=2;i=19")
dpp=dcpp.get_value()
dcff=client.get_node("ns=2;i=18")
dff=dcff.get_value()
dctt=client.get_node("ns=2;i=20")
dtt=dctt.get_value()
#Time=client.get_node("ns=2;i=3")
#Ti=Time.get_value()
#Ti1=datetime.time(Ti.hour,Ti.minute,Ti.second)
ti=datetime.now()
ti1=(str(ti.strftime('%Y-%m-%d %H:%M:%S')))
dt.append(str(Pressure)+','+ti1+','+str(ap)+','+str(r)+','+str(s)+','+str(n)+','+str(o)+','+str(h)+','+str(sps)+','+str(co)+','+str(dmp)+','+str(dmf)+','+str(chp)+','+str(cht)+','+str(ip)+','+str(it)+','+str(iff)+','+str(dpp)+','+str(dtt)+','+str(dff))
data['final']=dt
return JsonResponse(data)
Please check the getTemp() function as data is recieved from django in the success function. This is the part where you will have to make changes as per your requirement.
JS
<script type="text/javascript">
google.charts.load('current', {
callback: function () {
var chart = new google.visualization.LineChart(document.getElementById('graph'));
var options = {'title' : 'CTL-2 AIR PRESSURE (Bar)',
titleTextStyle: {
fontName: "Arial",
fontSize: 18,
},
animation: {
duration: 1000,
easing: 'out',
startup: true
},
hAxis: {
title: 'Time',
format: "HH:mm:ss",
textStyle: {
fontSize : 14,
bold:'true',
},
},
vAxis: {
title: 'Air Pressure',
format: '0.00',
textStyle: {
fontSize : 14,
bold:'true',
},
},
height: 450,
width:1000,
legend:'bottom'
};
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Time');
data.addColumn('number', 'Air Pressure');
var go=[];
function getTemp() {
$.ajax({
type:"get",
url:"{% url 'plcdata' %}",
success:function(dat){
for(i=0;i<dat.final.length;i++){
var go=dat.final[i].split(',');
var tm = new Date();
if(data.hg.length>15){
data.removeRow(0);
}
data.addRow([tm, Number(go[0])]);
chart.draw(data, options);
}
return dat;
},
error: function(){
console.log("Error Occurred");
}
})
}
getTemp();
setInterval(getTemp, 3000);
},
packages:['corechart']
});
</script>
[1]: https://i.stack.imgur.com/bMWVB.png

Chart.js loads data when i resize window

My chart isnt refreshing when i click search. My chart works and shows the data only when i search and resize the window. I tried moving my chart function inside my search function but it gives me an error. Is there another approach to this? my code is:
$(`#stock-search`).click(function(){
var searchValue = $('#stock-name').val();
$.getJSON(`https://sandbox.iexapis.com/stable/stock/${searchValue}/chart/1m?token=demo`,
function(data){
console.log(data);
for (x = 0; x < 22; x++){
const time = data[`${x}`].label;
xlabel.push(time);
const value = data[`${x}`].high;
ydata.push(value);
console.log(value);
console.log(time);
}
});
});
const ctx = document.getElementById('myChart').getContext('2d');
const xlabel= [];
const ydata= [];
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: xlabel,
datasets: [{
label: "Highs of the month",
data: ydata,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
callback: function(value, index, values) {
return '$' + value;
}
}
}]
}
}
});
You may want to look at this Question though while a bit dated does seems to provide numerous ways to accomplish your goal:
chart.js load totally new data

Duplicated Series of Data in Google Area Chart

I'm trying to plot a Chart using Google's Visualization API using some data returned from a database by a PHP script. My data is a JSON object in the format:
jsonObject = {
"routes":[{
"name":"Route 0",
"chart":{
"x":[ /* array of x values */ ],
"y":[ /* array of y values */ ]
}
},{
"name":"Route 1",
"chart":{
"x":[ /* array of x values */ ],
"y":[ /* array of y values */ ]
}
}]};
I'm trying to plot a chart of each member of jsonObject.routes individually using the following code:
function drawChart() {
var baseChart = jsonObject.routes[1].chart; // Want to manipulate this value to plot different sets of data
var chartData = [];
for (var g = 0; g < baseChart.x.length; g++) {
var dataPoint = {
c: [
{ v: baseChart.x[g] },
{ v: baseChart.y[g] },
]
};
chartData.push(dataPoint);
}
var dataJson = {
cols: [
{ role: "domain", type: "number", label: "Distance" },
{ role: "data", type: "number", label: "Main Route" },
],
rows: chartData
};
var dataTable = new google.visualization.DataTable(dataJson);
var chart = new google.visualization.AreaChart(document.getElementById('chart'));
var options = {};
chart.draw(dataTable, options);
}
However, whenever I try to access the latter objects of the jsonObject.route array, it seems to be pulling data for every object in the jsonObject.route array prior to it as well.
I've included a link to a Fiddle with a sample dataset at the bottom; the chart is fine when only plotting jsonObject.routes[0], but when trying to plot jsonObject.routes[1] it will plot the data from jsonObject.routes[0] too.
I suspect this is more of an issue with my Javascript code rather than with the Google Visualization API, but I've been pulling my hair out with it and can figure out why it's pulling data from all the elements in that array. Many thanks for any help!
Link to Fiddle
not sure i completely follow the question...
looking at the fiddle, the one chart seems to draw fine,
just need to sort the data to fix funny looking area
dataTable.sort([{column: 0}]);
see following snippet in order to draw separate charts for each --> jsonObject.routes
google.charts.load('current', {
callback: function () {
jsonObject.routes.forEach(function (route) {
var chartData = [];
route.chart.dist.forEach(function (x, index) {
chartData.push({
c: [
{v: x},
{v: route.chart.ele[index]}
]
});
});
var dataJson = {
cols: [
{ role: "domain", type: "number", label: "Distance" },
{ role: "data", type: "number", label: "Main Route" },
],
rows: chartData
};
var dataTable = new google.visualization.DataTable(dataJson);
dataTable.sort([{column: 0}]);
var options = {};
var container = document.getElementById('chart_div').appendChild(document.createElement('div'));
var chart = new google.visualization.AreaChart(container);
chart.draw(dataTable, options);
});
},
packages:['corechart']
});
note: definition of jsonObject is excluded above
AND
when building a working fiddle, i noticed that since jsonObject is so large,
once you leave the page and comeback,
the fiddle breaks it up into chunks, which then breaks the code
and only one chart is drawn
here is a working fiddle with far less data

Getting JSON from Google for Highmaps

I'm pretty rusty with JavaScript, so I'm hoping someone can help me out. I'm working with Highmaps and would like to link the map to data in a Google Spreadsheet. (It's a U.S. map of counties which will be updated regularly, so having it all in the script itself is a little unwieldy.)
This is what my code looks like now:
<script type="text/javascript">
var example = 'us-counties',
theme = 'default';
(function($) { // encapsulate jQuery
$(function() {
var data = [{
"code": "us-al-001",
"name": "Autauga County, AL",
"value": 0
},
…
{
"code": "us-pr-153",
"name": "Yauco Municipio, PR",
"value": 0
}],
countiesMap = Highcharts.geojson(Highcharts.maps['countries/us/us-all-all']),
lines = Highcharts.geojson(Highcharts.maps['countries/us/us-all-all'], 'mapline'),
options;
// Add state acronym for tooltip
Highcharts.each(countiesMap, function(mapPoint) {
mapPoint.name = mapPoint.name + ' County, ' + mapPoint.properties['hc-key'].substr(3, 2);
});
series: [{
name: 'County',
mapData: countiesMap,
data: data,
joinBy: ['hc-key', 'code'],
tooltip: {
enabled: true,
positioner: function () {
return { x: 0, y: 250 };
},
pointFormat: '{point.name}',
borders: 0.5
},
borderWidth: 0.5
}, {
type: 'mapline',
name: 'State borders',
data: [lines[0]],
color: 'white'
}, {
type: 'mapline',
name: 'Separator',
data: [lines[1]],
color: 'gray'
}]
};
// Instanciate the map
$('#container').highcharts('Map', options);
});
$(document).ready(function() {
$("#view-menu").click(function(e) {
$("#wrap").toggleClass("toggled");
});
$("#sidebar-close").click(function(e) {
$("#wrap").removeClass("toggled");
});
});
})(jQuery);
</script>
Of course, since there's over 3,200 counties, I'd rather store that data elsewhere and pull it into the var data = [] string, but I'm not sure how to do that.
Any help would be appreciated.
Although this isn't something I've done, it looks like this should be relatively straightforward to do (although nothing is as simple as it looks of course).
There is an API for Google Sheets (https://developers.google.com/google-apps/spreadsheets/) and you can Google examples of how to retrieve data - this one looks clear (https://developers.google.com/gdata/docs/json) although it does point out that there are newer versions of some of the relevant APIs.
If you pull in the JSON data from the Google Sheet you then just need to put the values into the 'value' element of your data variable. You could do all of that within your main function or do it separately and pass it to your function as a parameter.

Categories

Resources