Related
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
Hello I am running into a problem that seems very simple but I can't find any solution online. Basically I am trying to use flask alongside javascript and using jinja templates to communicate between the two. I have an html file and the jinja template is working to fill out the boxes as I expect however anything in between tags that includes jinja will not run. Any help is much appreciated! The different cases are:
#this will run
<script>alert( 'Hello, 1' );</script>
#this won't
<script>alert( {{TableTitle}} );</script>
#I saw a tutorial that did this but it also won't run
{% block javascript %}
<script>alert( {{TableTitle}} );</script>
{% endblock %}
#when I view the source of the loaded page I see that jinja template has worked and get this:
<script>alert( test_data );</script>
#the ultimate goal is to make this run:
{% block javascript %}
<script>
alert('hello inside')
$(document).ready(function () {
alert( 'Hello, 5' );
const config = {
type: 'line',
data: {
labels: [],
datasets: [
{% for line in lines %}
{
label: {{line}},
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [],
fill: false,
}
{% endfor %}
],
},
options: {
responsive: true,
title: {
display: true,
text: {{TableTitle}}
},
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Time'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Magnitude'
}
}]
}
}
};
const context = document.getElementById('canvas').getContext('2d');
const lineChart = new Chart(context, config);
const source = new EventSource("{{url_for('jsplotter')}}");
source.onmessage = function (event) {
const data = JSON.parse(event.data);
if (config.data.labels.length === 20) {
config.data.labels.shift();
config.data.datasets[0].data.shift();
}
config.data.labels.push(data.time);
{%for i in range(lines|length)%}
config.data.datasets[{{i}}].data.push(data.value[{{i}}]);
{%endfor%}
lineChart.update();
}
});
</script>
{% endblock %}
#which gets transformed into:
<script>
alert('hello inside')
$(document).ready(function () {
alert( 'Hello, 5' );
const config = {
type: 'line',
data: {
labels: [],
datasets: [
{
label: 1V0_REF,
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [],
fill: false,
}
{
label: 1V35_REF,
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [],
fill: false,
}
],
},
options: {
responsive: true,
title: {
display: true,
text: test_data
},
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Time'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Magnitude'
}
}]
}
}
};
const context = document.getElementById('canvas').getContext('2d');
const lineChart = new Chart(context, config);
const source = new EventSource("/jsplotter");
source.onmessage = function (event) {
const data = JSON.parse(event.data);
if (config.data.labels.length === 20) {
config.data.labels.shift();
config.data.datasets[0].data.shift();
}
config.data.labels.push(data.time);
config.data.datasets[0].data.push(data.value[0]);
config.data.datasets[1].data.push(data.value[1]);
lineChart.update();
}
});
</script>
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 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
};
Is it possible to add drag and zoom on ChartJS? I would like to do something similar like here.
Here is how I draw my line chart:
<canvas class="square_margin_less" id="myChart" width="100" height="30" > </canvas>
<script>
new Chart(document.getElementById("myChart").getContext('2d'),
{
type: 'line',
data: {
labels: {{ data.labels|safe }},
datasets:
[{
label: 'x',
data: {{ data.x }},
borderColor: 'rgba(233,105,118,1)',
},
{
label: 'y',
data: {{ data.y }},
borderColor: 'rgba(96,143,239,1)'
},
{
label: 'z',
data: {{ data.z }},
borderColor: 'rgba(144,247,136,1)'
}]
},
});
</script>
There is some way of personalizing this?
I didn't find "drag and zoom" functionality for Chart.js as well as simple example with "pan and zoom" version so I've decided to implement demo version own my own.
List of external scripts is very important: hammer-js, then Chart.bundle.js and chartjs-plugin-zoom.js.
const config = {
type: 'line',
data: {
labels: [new Date('2019-08-20'), new Date('2019-08-25'), new Date('2019-08-30')],
datasets: [{
label: 'Line',
data: [2, 5, 3],
borderColor: '#D4213D',
fill: false,
}, ],
},
options: {
scales: {
xAxes: [{
type: 'time',
}, ],
},
pan: {
enabled: true,
mode: 'xy',
},
zoom: {
enabled: true,
mode: 'xy', // or 'x' for "drag" version
},
},
};
window.onload = function() {
new Chart(document.getElementById('chart'), config);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/0.6.6/chartjs-plugin-zoom.js"></script>
<html>
<body>
<div style="width:380px;">
<canvas id="chart"></canvas>
</div>
</body>
</html>
If someone is interesting in other libraries, I found one interesting solution on Vicotry website with "brush and zoom" functionality for line charts: https://formidable.com/open-source/victory/guides/brush-and-zoom/.
EDIT: In the "drag" version you will have to use for zoom:
drag: {
borderColor: 'hsl(35, 100%, 60%)',
borderWidth: '3',
backgroundColor: 'hsl(35, 100%, 60%)',
},