0

I have an array in Django views.py and I want to send it to HTML and display a piechart, but failed, I've tried many other methods and read many tutorials, in most of the case, they have a field in models that store some number, and they display those number. In my case, I need to calculate the subtotal of tasks that are in different states. I'm not sure how to output those data to chart.js with proper labels or any other piechart if there's any recommendation? pie chart became rectangles

views.py

def visualisation(request, project_id):
    
    project = Project.objects.get(id=project_id)
   
    counts_data = Todo.objects.aggregate(
        to_do_count=Count('id', filter=Q(status='to_do')),
        in_progress_count=Count('id', filter=Q(status='in_progress')),
        done_count=Count('id', filter=Q(status='done'))
        )

    
    return render(request, 'todo_lists/progress.html', {"counts_data": counts_data})

html


<script>
 
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
    labels: [1,2,3],
    
    datasets: [{
        label: '# of Votes',

        data:{{counts_data}},
        
        backgroundColor: [
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)',
            'rgba(255, 206, 86, 0.2)'
        ],
        borderColor: [
            'rgba(255, 99, 132, 1)',
            'rgba(54, 162, 235, 1)',
            'rgba(255, 206, 86, 1)'
        ],
        borderWidth: 1
    }]
},
options: {
    responsive:false
    
}
});
});
</script>

pie chart not show up properly

3
  • just create an object to store the array in javascript: var obj = {{counts_data}};. And using that object's value create the pie chart. Commented Oct 24, 2021 at 3:33
  • @AjayLingayat Thanks for your help, I tried, but still not work, any other idea? Commented Oct 24, 2021 at 4:06
  • @NikiGrey please show the rendered data in line data:{{counts_data}}. Commented Oct 24, 2021 at 6:03

2 Answers 2

1

You need to have the data in a structured manner for chart.js
Chart JS Data Structures https://www.chartjs.org/docs/latest/general/data-structures.html
Simply you could follow the Primitive structure as shown below or you could follow the Object structure with custom properties (need to do further data formatting and parsing).

    $(document).ready(function() {
        var ctx = document.getElementById('myChart').getContext('2d');
        var myChart = new Chart(ctx, {
            type: 'doughnut',
            data: {
                // labels format ['label1', 'label2', 'label3', ]
                // you can choose to have a static labels if you are sure that 
                // there is always a specific number of labels
                labels: [{% for label in counts_data %} '{{ label }}', {% endfor %}],

                datasets: [{
                    label: '# of Votes',

                    // data format [value1, value2, value3, ]
                    data: [{% for label, value in counts_data.items() %} {{ value }}, {% endfor %}],

                    backgroundColor: [
                        'rgba(255, 99, 132, 0.2)',
                        'rgba(54, 162, 235, 0.2)',
                        'rgba(255, 206, 86, 0.2)'
                    ],
                    borderColor: [
                        'rgba(255, 99, 132, 1)',
                        'rgba(54, 162, 235, 1)',
                        'rgba(255, 206, 86, 1)'
                    ],
                    borderWidth: 1
                }]
            },
            options: {
                responsive: false

            }
        });
    }); 

enter image description here

In your views, Todo.objects.aggregate(...) should return something like this (Values are provided as an example):

{'to_do_count': 3, 'in_progress_count': 6, 'done_count': 1}

    counts_data = Todo.objects.aggregate(
        to_do_count=Count('id', filter=Q(status='to_do')),
        in_progress_count=Count('id', filter=Q(status='in_progress')),
        done_count=Count('id', filter=Q(status='done'))
        )
    # counts_data = {'to_do_count': 3, 'in_progress_count': 6, 'done_count': 1}

This dictionary is then passed to the context with the key named as counts_data. Using this key name loop through the dictionary to create labels and data

labels: [{% for label in counts_data %} '{{ label }}', {% endfor %}], rendered as labels: [ 'to_do_count', 'in_progress_count', 'done_count', ],

data: [{% for label, value in counts_data.items() %} {{ value }}, {% endfor %}], rendered as data: [ 3, 6, 1, ],

Sign up to request clarification or add additional context in comments.

6 Comments

Hi Achuth, looks good, could u show me how to make change to views.py, please? I'm stuck in ouput the format required
I still don't know how I can ouput some thing like[value1, value2, value3], in my understanding, the counts_data=...agregate(..., ..., ...) is a list similar to value list (value1, value2, value3), but then when I return it need to be a dict, so I turn it context = {"counts_data", counts_data}, which is similar to {counts_data1: (value1, value2, value3), counts_data2:(value1, value, value3),...}, so I'm not sure how I can output data like [value1, value2,value3]
I tried to put them into one queryset, but a queryset can only get or filter one status, I have 3 status, so I'm confused, it would be great if u could explain a little bit? Cheers
in your views, when you call the aggregate() you would get value in counts_data which would be in format of a dictionary as {'to_do_count': 1, 'in_progress_count': 1, 'done_count': 1} (please don't mind the values). This is assigned to the context with key as counts_data which is then used in html to access the dictionary. With looping you are actually accessing the keys and values in the dictionary to create the data in the format as specified. Hope this helps. (to make sure, you can inspect the code using browser dev tools and see how it is rendered)
about having 3 status in a queryset: please check the last example in this section from the documentation docs.djangoproject.com/en/3.2/topics/db/aggregation/… You can see that a dictionary is returned. So, in the code provided you should get a return value something like {'to_do_count': 1, 'in_progress_count': 1, 'done_count': 1} and not like {counts_data1: (value1, value2, value3), counts_data2:(value1, value, value3),...}
|
0
<script>
 
$(document).ready(function() {
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
    labels: [1,2,3],
    
    datasets: [{
        label: '# of Votes',

        data:counts_data,

        success: function (data){
        $('#todocount').html(counts_data.to_do_count);
        $('#progress_count').html(counts_data.in_progress_count);

        $('#progress_done').html(counts_data.done_count);

    }
        
        backgroundColor: [
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)',
            'rgba(255, 206, 86, 0.2)'
        ],
        borderColor: [
            'rgba(255, 99, 132, 1)',
            'rgba(54, 162, 235, 1)',
            'rgba(255, 206, 86, 1)'
        ],
        borderWidth: 1
    }]
},
options: {
    responsive:false
    
}
});
});
</script>

1 Comment

Hi Rahul, thanks for your help, I tried your method, but not working, do you have any other idea?

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.