0

I have a simple question that I am not able to solve no matter how hard I try:

When I keep var data outside the js function and replace Name, Duration, Color with random inputs, I get a pie chart. However, when I bring the var data inside the else statement with values that are successfully fetched per the console, the pie chart goes hidden w/o any js error popping in the console.

PY:

@blueprint.route('/Pie', methods=['GET', 'POST']) #change it to calendar retrieve
def Pie():
    return jsonify(color = colorID, Duration =  Duration_List, Name= Names)

JS:

 fetch("/Pie").then(response => response.json()).then(function (response) {
      if (response == null) {
        console.log("returned nothing");
      } else {
        console.log(response.Name);
        console.log(response.Duration);
        console.log(response.color);
        Name = JSON.stringify(response.Name);
        Duration = JSON.stringify(response.Duration);
        Color = JSON.stringify(response.color);
    var data = { 
      labels: Name,
      datasets: [{
        label: "Data",
        fill: true,
        backgroundColor: gradientStroke,
        borderColor: Color,
        borderWidth: 2,
        borderDash: [],
        borderDashOffset: 0.0,
        pointBackgroundColor: '#d048b6',
        pointBorderColor: 'rgba(255,255,255,0)',
        pointHoverBackgroundColor: '#d048b6', 
        pointBorderWidth: 20,
        pointHoverRadius: 4,
        pointHoverBorderWidth: 15,
        pointRadius: 4,
        data: Duration
      }]
    };
var myChart = new Chart(ctx, {
  type: 'doughnut',
  data: data,
  options: gradientChartOptionsConfigurationWithTooltipPurple
});
davidism
  • 121,510
  • 29
  • 395
  • 339

3 Answers3

1

I think your main problem is you've converted all the response data into strings - Charts.js would expect the data to be objects.

So if you just remove the JSON.stringify for the name, duration and color it should work.

costaparas
  • 5,047
  • 11
  • 16
  • 26
0

I am not sure but, can you try placing the chart object declaration next to the data? this might fix your issue...

fetch("/Pie").then(response => response.json()).then(function(response) {
      if (response == null) {
        console.log("returned nothing");
      } else {
        console.log(response.Name);
        console.log(response.Duration);
        console.log(response.color);
        Name = JSON.stringify(response.Name);
        Duration = JSON.stringify(response.Duration);
        Color = JSON.stringify(response.color);
        var data = {
          labels: Name,
          datasets: [{
            label: "Data",
            fill: true,
            backgroundColor: gradientStroke,
            borderColor: Color,
            borderWidth: 2,
            borderDash: [],
            borderDashOffset: 0.0,
            pointBackgroundColor: '#d048b6',
            pointBorderColor: 'rgba(255,255,255,0)',
            pointHoverBackgroundColor: '#d048b6',
            pointBorderWidth: 20,
            pointHoverRadius: 4,
            pointHoverBorderWidth: 15,
            pointRadius: 4,
            data: Duration
          }]
          var myChart = new Chart(ctx, {
            type: 'doughnut',
            data: data,
            options: gradientChartOptionsConfigurationWithTooltipPurple
          });
        };
Mahmoud
  • 9,729
  • 1
  • 36
  • 47
  • I think you should follow @costaparas advice, data should be an array of primitives. I will updated the sample. – Mahmoud Nov 28 '20 at 23:30
  • 1
    Sorry, I take my word back. Your solution actually worked! I realized that the error was that the pie chart and line graph were fighting for the same spot instead of different. –  Nov 29 '20 at 04:01
0

I wrote an answer previously which focused more on line charts, and created a repo with my method.I've adapted this to make a short gist which I think solves your Doughnut usecase.

Most of the functionality is built into the create_chart and load_chart functions, with the fetch call pushing data to the already existing chart object:

fetch(url)
    .then((response) => {
      return response.json();
    })
    .then((resp_data) => {

      // Push this data to the config object of this chart.

      resp_data.labels.forEach((label) =>{
          chart.data.labels.push(label);
      });
      
      resp_data.datasets.forEach((dataSet) => {
        chart.data.datasets.push({
          data: dataSet['Duration'],
          backgroundColor: dataSet['Color'],
          fill: false,
        })
      });

      // Finally update that visual chart
      chart.update();

    });

I've mocked a (slightly different) datastructure in the Pie method of the app, which will support multiple datasets:


@app.route('/Pie', methods=['GET', 'POST']) #change it to calendar retrieve
def Pie():
    datasets = [{'Duration': [1,2,3],
                 'Color': ['#FF0000','#00FF00','#0000FF']
                },

                {'Duration': [8,9,12],
                 'Color': ['#FF0000','#00FF00','#0000FF']
                }
                ]
    return jsonify({'labels': ['Red','Green','Blue'], 'datasets': datasets})

These should render like this:

enter image description here

Hopefully this is of some use to you. I suggest checking out that previous answer, and the flask-chartjs repo for more info.

v25
  • 7,096
  • 2
  • 20
  • 36
  • Thank you so much @v25 for your comprehensive and well-detailed response! This is definitely a much more elegant way of calling the function between flask and JS. Really appreciate your support, I'm certain it would work. –  Nov 29 '20 at 04:05