1

I am trying to create an interactive chart for a web app with data from python script.

The error is data from the python code is not transferred or updated on the chart.js script and not output on the html.

The flow of the 3 scripts: labels and data from python, goes into the chart.js to render the bar-chart and is output on the html

When I change Africa (data point) from 2447 to 5578, the chart is not updated. I am not sure if the issue is transferring from python or rendering the chart.

Python

from flask import Flask,render_template
app = Flask(__name__)

@app.route("/")
def result():
   labels = ["Africa", "Asia", "Europe", "Latin America", "North America"]

   data = [5578,5267,734,784,433]

   return render_template("result.html", labels=labels, data=data)
if __name__ == '__main__':
app.debug = True
app.run()

script1.js

new Chart(document.getElementById("bar-chart"), {
type: 'bar',
data: {
  labels: "{{labels}}",
  datasets: [
    {
      label: "Population (millions)",
      backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
      data: "{{data }}"
    }
  ]
},
options: {
  legend: { display: false },
  title: {
    display: true,
    text: 'Predicted world population (millions) in 2050'
  }
}
});

HTML

  <!DOCTYPE html>
<html>
  <head>
    <title>New</title>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"> 
</script>

  </head>
  <body>
  <h1>Test</h1>
    <div class="wrapper">
    <canvas id="bar-chart" width="800" height="450"></canvas>
    </div>

     <script src="{{ url_for('static', filename='script1.js') }}"></script>

   </body>
  </html>

5 Answers 5

7

script1.js is not being rendered by flask.render_template as it is only being linked to by the script tag. However, it is much better practice to send a request to the backend for jsonified data than attempt to render the values themselves in the template. Create an additional route in the Python file to return the values upon an ajax request:

import json
@app.route("/")
def result():
  return render_template("result.html")

@app.route('/get_data')
def get_data():
  labels = ["Africa", "Asia", "Europe", "Latin America", "North America"]
  data = [5578,5267,734,784,433]
  return flask.jsonify({'payload':json.dumps({'data':data, 'labels':labels})})

Do not forget to include jquery to support the ajax call in the HTML:

<head> 
  <title>New</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"> 
</head>

Lastly, in script1.js:

$(document).ready(function(){
   var _data;
   var _labels;
  $.ajax({
   url: "/get_data",
   type: "get",
   data: {vals: ''},
   success: function(response) {
     full_data = JSON.parse(response.payload);
     _data = full_data['data'];
     _labels = full_data['labels'];
   },

 });
 new Chart(document.getElementById("bar-chart"), {
  type: 'bar',
 data: {
   labels: _labels,
   datasets: [
   {
    label: "Population (millions)",
    backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
   data: _data
   }
   ]
   },
    options: {
    legend: { display: false },
     title: {
      display: true,
     text: 'Predicted world population (millions) in 2050'
   }
  }
 });
});
Sign up to request clarification or add additional context in comments.

8 Comments

can you explain the solution 1) How do I create an additional route in the Python file to return the values upon an ajax request 2) what is flask.jsonify({'payload':json.dumps({'data':data, 'labels':labels})}) 3) the first paragraph of the javascript ?
@Lko The additional route in the Python file has already been created (get_data). flask.jsonify is returning a stringified version of the the datastructure {'payload': {'data': [5578, 5267, 734, 784, 433], 'labels': ['Africa', 'Asia', 'Europe', 'Latin America', 'North America']}} which is then loaded into a javascript object.
or let me clarify what i am doing. I coded a python script with pandas and it outputs a few tables and line graphs. I am trying to create a web app, (where i can get user input and then output the line graphs and tables I have tried dash. I am trying it with flask, if there is a better way, please let me know
@Lko flask is certainly the simplest way to display the values from the pandas dataframe.
how about this part ? $(document).ready(function(){ var _data; var _labels; $.ajax({ url: "/get_data", type: "get", data: {vals: ''}, success: function(response) {
|
2

Code example in response to @Lko comment to keep js in a separate file, see my comment to the previous post.

File structure: \main.py \static\script1.js \templates\result.html

HTML:

    <!DOCTYPE html>
    <html>
      <head>
        <title>New</title>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script>

      </head>
      <body>
      <h1>Test</h1>
        <div class="wrapper">
        <canvas id="bar-chart" width="800" height="450"></canvas>
        </div>

        <!-- <script src="{{ url_for('static', filename='script1.js') }}"></script> -->
        <script type = "text/javascript">
            var labelsVar={{labels|tojson}};
            var dataVar={{data|tojson}};
        </script>
        <script type = "text/javascript"  src="{{ url_for('static', filename = 'script1.js') }}"></script>
      </body>
      </html>

Javascript:

  console.log(labelsVar);
  console.log(dataVar);
  new Chart(document.getElementById("bar-chart"), {
      type: 'bar',
      data: {
        labels: labelsVar,
        datasets: [
          {
            label: "Population (millions)",
            backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
            data: dataVar
          }
        ]
      },
      options: {
        legend: { display: false },
        title: {
          display: true,
          text: 'Predicted world population (millions) in 2050'
        }
      }
      });

1 Comment

hello, thank you! why cant var labelsVar={{labels|tojson}}; var dataVar={{data|tojson}}; line from the html go to the javascript ?
1

To render the javascript (replacing your variables) put the javascript in the html file to be rendered and use Flask jinja filter tojson: An example:

  <!DOCTYPE html>
  <html>
    <head>
      <title>New</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script>

    </head>
    <body>
    <h1>Test</h1>
      <div class="wrapper">
      <canvas id="bar-chart" width="800" height="450"></canvas>
      </div>

      <!-- <script src="{{ url_for('static', filename='script1.js') }}"></script> -->
      <script>
          //console.log({{labels|tojson}});
          //console.log({{data|tojson}});
          new Chart(document.getElementById("bar-chart"), {
              type: 'bar',
              data: {
                labels: {{labels|tojson}},
                datasets: [
                  {
                    label: "Population (millions)",
                    backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
                    data: {{data|tojson}}
                  }
                ]
              },
              options: {
                legend: { display: false },
                title: {
                  display: true,
                  text: 'Predicted world population (millions) in 2050'
                }
              }
              });
      </script>

    </body>
    </html>

2 Comments

If i were to put the section <script> in js instead of the html, how should i change {{labels|tojson}} & {{data|tojson}}. ?
It probably is better if you can load the data from javascript by calling an API. i.e. make an API using flask and make a HTTP GET on the API to load your data. But if you really want to take this approach, I suggest keeping as much of your javascript in the .js file and using a script section that renders the data portion, i.e. one script loads the data into variables and your main js script just uses the variables already defined. See the code example below. It then may be easier to write and debug your script as it's pure javascript.
0
data:JSON.parse('{{data}}')

I couldn't pass data from my flask app to script section in html so I did this and it worked.

Comments

0

You may pass the data on a list (with render_template) and retrieve it on html with:

labels: [{% for item in families %}
         "{{ item }}",
         {% endfor %}]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.