I am using the Flask framework with render_template. Flask return list to the whether.html file. I use Chart.js in the whether.html file to create graphs from the lists returned by the flask. When I use the Chart.js code inside the HTML file it works fine but when I want to copy the same javascript code to an external line.js file and link it back to my whether.html then I see SyntaxError: expected property name, got '%' javascript error in the console.
I would appreciate any help regarding the problem.
JavaScript within whether.html
{% extends "index.html" %}
{% block content %}
<!-- bar chart canvas element -->
<canvas id="myChart" width="600" height="400"></canvas>
<p id="pointSelected">Point selected:</p>
<script>
// Global parameters:
// do not resize the chart canvas when its container does (keep at 600x400px)
Chart.defaults.global.responsive = false;
// define the chart data
var chartData = {
labels : [{% for item in labels %}
"{{item}}",
{% endfor %}],
datasets : [{
label: '{{ legend }}',
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data : [{% for item in values %}
{{item}},
{% endfor %}],
spanGaps: false
},
{
label: 'Sensor 2',
fill: false,
lineTension: 0.1,
borderColor: "#3e95cd",
data : [{% for item in values %}
{{item + 3}},
{% endfor %}],
}
]
}
// get chart canvas
var holder = document.getElementById("myChart");
var ctx = document.getElementById("myChart").getContext("2d");
// create the chart using the chart canvas
var myChart = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function(tooltipItems, data) {
return tooltipItems.yLabel + ' degrees';
}
}
},
}
});
// get the text element below the chart
var pointSelected = document.getElementById("pointSelected");
// create a callback function for updating the selected index on the chart
holder.onclick = function(evt){
var activePoint = myChart.getElementAtEvent(evt);
console.log(activePoint);
console.log('x:' + activePoint[0]._view.x);
console.log('maxWidth: ' + activePoint[0]._xScale.maxWidth);
console.log('y: ' + activePoint[0]._view.y);
console.log('index: ' + activePoint[0]._index);
pointSelected.innerHTML = 'Point selected... index: ' + activePoint[0]._index;
};
</script>
{% endblock %}
line.js file
// Global parameters:
// do not resize the chart canvas when its container does (keep at 600x400px)
Chart.defaults.global.responsive = false;
// define the chart data
var chartData = {
labels : [{% for item in labels %}
"{{item}}",
{% endfor %}],
datasets : [{
label: '{{ legend }}',
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data : [{% for item in values %}
{{item}},
{% endfor %}],
spanGaps: false
},
{
label: 'Sensor 2',
fill: false,
lineTension: 0.1,
borderColor: "#3e95cd",
data : [{% for item in values %}
{{item + 3}},
{% endfor %}],
}
]
}
// get chart canvas
var holder = document.getElementById("myChart");
var ctx = document.getElementById("myChart").getContext("2d");
// create the chart using the chart canvas
var myChart = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function(tooltipItems, data) {
return tooltipItems.yLabel + ' degrees';
}
}
},
}
});
// get the text element below the chart
var pointSelected = document.getElementById("pointSelected");
// create a callback function for updating the selected index on the chart
holder.onclick = function(evt){
var activePoint = myChart.getElementAtEvent(evt);
console.log(activePoint);
console.log('x:' + activePoint[0]._view.x);
console.log('maxWidth: ' + activePoint[0]._xScale.maxWidth);
console.log('y: ' + activePoint[0]._view.y);
console.log('index: ' + activePoint[0]._index);
pointSelected.innerHTML = 'Point selected... index: ' + activePoint[0]._index;
};
whether.html file
{% extends "index.html" %}
{% block content %}
<!-- <script src='static/Chart.min.js'></script> -->
<script src='static/js/Chart.js'></script>
<script src='static/js/line.js'></script>
<!-- <canvas id="line-chart" width="300" height="150"></canvas> -->
<h1>Temperature Sensor #1</h1>
<!-- bar chart canvas element -->
<canvas id="myChart" width="600" height="400"></canvas>
<p id="pointSelected">Point selected:</p>
{% endblock %}
Jinja work only with html files, you can't use it's tags in another files. But you can simply render little script with variables which contains needed values in html template and than use them in external script, for example:
{% extends "index.html" %}
{% block content %}
<!-- bar chart canvas element -->
<canvas id="myChart" width="600" height="400"></canvas>
<p id="pointSelected">Point selected:</p>
<script>
var labels = [{% for item in labels %}
"{{item}}",
{% endfor %}]
var data = [{% for item in values %}
{{item}},
{% endfor %}]
// and so on for each variable
// it's important to import external script
// after variables declaration, not before
</script>
<script src="external-script.js"></script>
{% endblock %}
and than you can simply use them in external script like:
var chartData = {
labels : labels,
// and so on
};
Related
The chart.html does not show the bar chart, which is supposed to be the one in https://www.chartjs.org/docs/latest/getting-started/
In chart.html
{% extends "base.html" %}
{% block js %}
<div>
<canvas id="myChart"></canvas>
</div>
<script src="../static/js/try.js"></script>
{% endblock %}
In try.js
import 'https://cdn.jsdelivr.net/npm/chart.js';
const ctx = document.getElementById('myChart');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
The import failed in try.js.
The solution is to relocate the import in chart.html.
In chart.html :
{% extends "base.html" %}
{% block js %}
<div>
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="../static/js/try.js"></script>
{% endblock %}
I tried this, which worked.
I recently trying to make dashboard which datas from mongodb with flask. But I cannot send datas to chart.js. I got the data from mongodb and send to javascript and try to loop data with jinja2.
#app.route("/dashboard")
def dashboard():
limit = request.args.get("limit",12,type=int)
dashboardDatas = mongo.db.dashBoard
dashDatas = dashboardDatas.find().limit(limit)
return render_template("dashboard.html", dashDatas = dashDatas)
<canvas id="myChart" height="50"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [ {% for item in dashDatas %}
'{{item._id}}',
{% endfor %} ],
datasets: [{
label: '# of Votes',
data: [ {% for item in dashDatas %}
{{item.logistic}},
{% endfor %}],
borderColor: [
'rgba(255, 99, 132, 1)',
],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
],
borderWidth: 0.5
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
And I got empty chart. What did I do wrong?
My approach is to store the labels and data in lists in the Flask view, pass them to the template and transform them to JSON with the tojson filter.
Suppose you have labels = ['a', 'b', 'c'] and data = [1, 2, 3] in your view. You can pass them to Chart.js in your template as
let chart = new Chart(ctx, {
type: 'line',
data: {
labels: {{ labels|tojson }},
datasets: [{
label: 'My 1st dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: {{ data|tojson }}
}]
});
Version (library) 1 of chartjs has important differences to version 2 in terms of usability. Fine references are:
. version 1: https://blog.ruanbekker.com/blog/2017/12/14/graphing-pretty-charts-with-python-flask-and-chartjs/
. version 2: https://towardsdatascience.com/flask-and-chart-js-tutorial-i-d33e05fba845
I am trying to plot a chart with two bars and two lines. the issue is that the lines wont go start at 0.
I have tried to artificially create points on the x axis to make them go all the way but it won't do the trick. Here is what my code look like for the graph:
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: document.getElementById('tag1').textContent == 'ITEM TIME SUPPLY ANALYSIS'? ["Desired time supply","Actual time Supply"] :[ 'jours de stock désirés','jours de stock actuel'] ,
datasets: [{
label: document.getElementById('tag1').textContent == 'ITEM TIME SUPPLY ANALYSIS'? "limit max time supply (days)": "limite max jours de stock désirés",
data: [
{
x: 0,
y: [{% for dr in reference %} {{ dr.cap_ts }}, {% endfor %}]
},
{
x: 30,
y: [{% for dr in reference %} {{ dr.cap_ts }}, {% endfor %}]
},
{
x: 60,
y: [{% for dr in reference %} {{ dr.cap_ts }}, {% endfor %}]
},
{
x: 90,
y: [{% for dr in reference %} {{ dr.cap_ts }}, {% endfor %}]
},
],
type: 'line',
backgroundColor: [
'rgba(0, 0, 0, 0)',
],
borderColor: [
'rgba(54, 162, 235, 1)',
],
borderWidth: 5
}, {
label: document.getElementById('tag1').textContent == 'ITEM TIME SUPPLY ANALYSIS'? "limit min time supply (days)": "limite min jours de stock désirés",
data: [
{
x: 0,
y: [{% for dr in reference %}{{ dr.min_ts}}, {% endfor %}]
},
{
x: 30,
y: [{% for dr in reference %}{{ dr.min_ts}}, {% endfor %}]
},
{
x: 60,
y: [{% for dr in reference %}{{ dr.min_ts}}, {% endfor %}]
},
{
x: 90,
y: [{% for dr in reference %}{{ dr.min_ts}}, {% endfor %}]
},
],
type: 'line',
backgroundColor: [
'rgba(0, 0, 0, 0)',
],
borderColor: [
'rgba(255, 99, 132, 1)',
],
borderWidth: 3
}, {
data: [
{x:30,
y: {% for dr in reference %}{{ dr.dts}}, {% endfor %}
},
{ x: 60,
y: {% for dr in reference %}{{ dr.actual_ts}}, {% endfor %}
},
],
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: {
scaleShowLabels: false,
type: 'linear',
position: 'bottom',
xAxes: [{
maxBarThickness: 90,
ticks: {
beginAtZero: true,
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
}
}
})
At this point I don't know what to try, I can't find much on chart.js documentation and I am new to javascript, any help would be very appreciated on this
This is happening because chart.js sets the offset property in the x scale to true for bar charts so the bar is in the middle of the grid instead of on the gridLine as is with line charts.
You can set the offset to false but then the first and last bar will look weird because they are half of the width.
Live example:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red',
borderColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
type: 'bar',
backgroundColor: 'blue'
}
]
},
options: {
scales: {
x: {
offset: false
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
</body>
I have a line chart in ChartJS with euro's values. I'd like to be able to change the data in $.
The Euro Chart works well but I'm not able to change the datas.
My Chart:
<canvas id="myChart" width="820" height="650"></canvas>
let ctx = document.getElementById("myChart");
Chart.defaults.global.defaultFontSize = 15;
var dataEu = [{{{ cote_1989_eu_base_eu }}}, {{{ cote_2004_base_eu }}}, {{{ cote_2014_base_eu }}}, {{{ cote_2017_base_eu }}}, {{{ cote_actual_base_eu }}}];
var dataUsd = [{{{ cote_1989_eu_base_usd }}}, {{{ cote_2004_base_eu }}}, {{{ cote_2014_base_usd }}}, {{{ cote_2017_base_usd }}}, {{{ cote_actual_base_usd }}}];
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["1989", "2004", "2014", "2017", "2019"],
datasets: [
{
spangaps: true,
label: 'Exceptionnel',
data: dataEu,
backgroundColor: 'transparent',
borderColor: '#00C853',
borderWidth: 4,
pointWidth: 3,
pointRadius: 5,
pointHoverRadius: 6,
pointBorderColor: '#FFF',
pointBackgroundColor: '#00C853',
pointBorderWidth: 1,
pointHitRadius: 100,
datalabels: {
display: false
}
}]}
});
How can I change the data afterwards, replacing dataEu by dataUsd, if I click on a radio button for example ?
if (radioButtonEu.checked = true) {
???
}
Assuming dataUs and dataEu are arrays with values, you can access and change the data of your chart easily with javascript like this:
myChart.data.datasets[0].data = dataUs; // assuming dataUs is an array
After doing that you need to rerender the chart with
myChart.update();
Heres a fully functional CODEPEN EXAMPLE. Feel free to manipulate and play around with it.
I am working with chart.js in my ionic 2 application if i implement canvas element with out ngSwitch condition for rendering it works fine but when i use condition i got error with native element not defined so canvas element not rendered because canvas element not ready at the time of subscribe chart data. how can i solve this.
#ViewChild('todayChart') todayChart;
#ViewChild('yesterdayChart') yesterdayChart;
ionViewWillEnter() {
this.homeauth.todaychart().subscribe((table) => {
var labels = [], datay = [], datum = [], timestamp = [];
for (var i = 0; i <= table.length - 1; i++) {
datum.push(table[i].chartdate);
labels.push(table[i].z10s3);
datay.push(table[i].z10s6);
timestamp.push(table[i].timestamp);
}
this.heutechart = new Chart(this.todayChart.nativeElement, {
type: 'line',
data: {
xLabels: labels,
datasets: [
{
label: 'G.Oil', fill: true, lineTension: 0.1, backgroundColor: "rgba(75,192,192,0.4)", borderColor: "rgba(75,192,192,1)",
pointHoverBorderWidth: 2, pointRadius: 1, pointHitRadius: 10, data: datay, spanGaps: false,
}
],
},
});
});
this.homeauth.yesterdaychart().subscribe((table) => {
var labels = [], datay = [], datum = [];
for (var i = 0; i <= table.length - 1; i++) {
datum.push(table[i].chartdate);
labels.push(table[i].z10s3);
datay.push(table[i].z10s6);
}
this.vortagschart = new Chart(this.yesterdayChart.nativeElement, {
type: 'line',
data: {
xLabels: labels,
datasets: [
{
label: 'G.Oil', fill: true, lineTension: 0.1, backgroundColor: "rgba(75,192,192,0.4)", borderColor: "rgba(75,192,192,1)",
pointHoverBorderWidth: 2, pointRadius: 1, pointHitRadius: 10, data: datay, spanGaps: false,
}
],
}
});
});
}
html:
<ion-segment [(ngModel)]="category">
<ion-segment-button value="today"> 24h </ion-segment-button>
<ion-segment-button value="yesterday"> 48h </ion-segment-button>
</ion-segment>
<div [ngSwitch]="category">
<div *ngSwitchCase="'today'">
<canvas #yesterdayChart> </canvas>
</div>
</div>
<div [ngSwitch]="category">
<div *ngSwitchCase="'yesterday'">
<canvas #todayChart></canvas>
</div>
</div>
you dont have to use ng-switch for each case.
It should be like so:
<div [ngSwitch]="category">
<div *ngSwitchCase="'today'"> <!-- case 1 -->
<canvas #yesterdayChart> </canvas>
</div>
<div *ngSwitchCase="'yesterday'">
<canvas #todayChart></canvas> <!-- case 2 -->
</div>
</div>
Add if conditions in the component since only one of these elements will be present in the DOM.
if(this.todayChart){
this.heutechart = new Chart(this.todayChart.nativeElement, {
type: 'line',
data: {
xLabels: labels,
datasets: [
{
label: 'G.Oil', fill: true, lineTension: 0.1, backgroundColor: "rgba(75,192,192,0.4)", borderColor: "rgba(75,192,192,1)",
pointHoverBorderWidth: 2, pointRadius: 1, pointHitRadius: 10, data: datay, spanGaps: false,
}
],
},
});
});
}
//Similarly for yesterdayChart