Codementor Events

Django Charts - Simple Bar Chart displayed in three ways

Published Nov 24, 2020Last updated May 26, 2021
Django Charts - Simple Bar Chart displayed in three ways

Hello Coders,

This article presents an open-source Django project that provides Bar Chart widgets coded in three different ways using MorisJS library:

The code can be downloaded from Github and used in hobby & commercial products based on the permissive license.

Resources

For more resources and support please access:


Django Dashboard - Simple Charts built with MorisJS.


Django Charts - From JSON

The starter provides a controller that loads a JSON file and simply injected into the view.

chart_morris.json

{
    "element": "morris-bar-chart",
    "data": [
        { "y": "2017", "a": "150", "b": "90", "c": "80" },
        { "y": "2018", "a": "220", "b": "350", "c": "50" },
        { "y": "2019", "a": "80", "b": "300", "c": "240" },
        { "y": "2020", "a": "180", "b": "30", "c": "10" }
    ],
    "xkey": "y",
    "barSizeRatio": 0.70,
    "barGap": 3,
    "resize": true,
    "responsive": true,
    "ykeys": ["a", "b", "c"],
    "labels": ["Product A", "Product B", "Product C"],
    "barColors": ["0-#1de9b6-#1dc4e9", "0-#899FD4-#A389D4", "#04a9f5"]
}

Controller Code

Source: app/views.py - charts_file():

# Partial content from file: app/views.py

def charts_file(request):
    context = {'segment': 'charts_from_file'}
    html_template = loader.get_template('charts-from-file.html')

    with open('sample_data/chart_morris.json', 'r') as f:
        context['chart_data'] = json.dumps(json.load(f))

    return HttpResponse(html_template.render(context, request))

Chart Output in View

Django Charts - MorisJS from JSON


Django Charts - From input

This time the information is loaded from STATS table where the information is saved.

Charts Render flow

The STATS model comes with an inner method that selects all rows: get_report(). Once the STATS rows are selected, the controller reads the page template and injects the information in view.

Source: app/views.py - charts_input():

# Partial content from file: app/views.py
def charts_input(request):
    context = {'segment': 'charts_from_input'}
    html_template = loader.get_template('charts-from-input.html')

    stats, labels = Stats.get_report()
    data = [
        {
            'y': year,
            'a': '{:.2f}'.format( stats[year].get('prod1_sales') ), 
            'b': '{:.2f}'.format( stats[year].get('prod2_sales') ), 
            'c': '{:.2f}'.format( stats[year].get('prod3_sales') )  
        } for year in stats
    ]

    context['chart_data'] = json.dumps({
        'element': 'morris-bar-chart',
        'data': data,
        'xkey': 'y',
        'barSizeRatio': 0.70,
        'barGap': 3,
        'resize': True,
        'responsive': True,
        'ykeys': ['a', 'b', 'c'],  # it can be custom
        'labels': labels,
        'barColors': ['0-#1de9b6-#1dc4e9', '0-#899FD4-#A389D4', '#04a9f5']  # it can be custom
    })

    return HttpResponse(html_template.render(context, request))

Database Model - STATS

The model comes with an inner method that selects all rows and exposes the relevant information: get_report().

class Stats(models.Model):
    
    year        = models.IntegerField(_('year')           , db_index=True)
    prod1_sales = models.IntegerField(_('product 1 sales'), db_index=True)
    prod2_sales = models.IntegerField(_('product 2 sales'), db_index=True)
    prod3_sales = models.IntegerField(_('product 3 sales'), db_index=True)

    class Meta:
        verbose_name = _('statistic')
        verbose_name_plural = _('stats')

    @classmethod
    def get_report(cls):

        data   = {}
        labels = ['prod1_sales', 'prod2_sales', 'prod3_sales']

        stats = Stats.objects.order_by('year').values()

        for line in stats:

            if line['year'] not in data:
                data[line['year']] = {}

            data[ line['year'] ]['prod1_sales'] = line['prod1_sales']
            data[ line['year'] ]['prod2_sales'] = line['prod2_sales']
            data[ line['year'] ]['prod3_sales'] = line['prod3_sales']

        return data, labels

Chart Output in View

Django Charts - MorisJS from Input


Django Charts - Load from CSV file

This time we have a new model called SALES provisioned from a CSV file. To upload the information we need to use django-import-export Python package and a superuser to execute the import.

The SALES model

class Sale(models.Model):
    amount = models.FloatField(_('amount'), db_index=True)
    product_name = models.CharField(_('product name'), max_length=40, db_index=True)
    created_time = models.DateTimeField(verbose_name=_('creation On'), db_index=True)
    updated_time = models.DateTimeField(verbose_name=_('modified On'), auto_now=True)

    class Meta:
        verbose_name = _('sale')
        verbose_name_plural = _('sales')

    @classmethod
    def get_sales_report(cls):
        annotates = {'total_amount': Sum('amount')}

        sales = cls.objects.annotate(
            year=TruncYear('created_time')
        ).values('product_name', 'year').order_by().annotate(**annotates)

        data = {}
        for sale in sales:

            if sale['year'].year not in data:
                data[sale['year'].year] = {}

            data[sale['year'].year][sale['product_name']] = sale['total_amount']

        labels = list(sales.values_list('product_name', flat=True).distinct())
        return data, labels

Inner method get_sales_report() scan the information and return a dictionary with formatted data.


Controller method

# Partial content from file: app/views.py
def charts_load(request):
    context = {'segment': 'charts_from_load'}
    html_template = loader.get_template('charts-from-load.html')

    # -----------------------------------------------
    # Extract data from Sale table 
    # -----------------------------------------------

    sales, labels = Sale.get_sales_report()
    data = [
        {
            'y': year,
            'a': '{:.2f}'.format(sales[year].get('A')),
            'b': '{:.2f}'.format(sales[year].get('B')),
            'c': '{:.2f}'.format(sales[year].get('C'))
        } for year in sales
    ]

    context['chart_data'] = json.dumps({
        'element': 'morris-bar-chart',
        'data': data,
        'xkey': 'y',
        'barSizeRatio': 0.70,
        'barGap': 3,
        'resize': True,
        'responsive': True,
        'ykeys': ['a', 'b', 'c'],  # it can be custom
        'labels': labels,
        'barColors': ['0-#1de9b6-#1dc4e9', '0-#899FD4-#A389D4', '#04a9f5']  # it can be custom
    })

    return HttpResponse(html_template.render(context, request))

Chart Output in View

Django Charts - MorisJS from CSV dataset

Discover and read more posts from Adi Chirilov - Sm0ke
get started
post commentsBe the first to share your opinion
K A SUMUKH
2 years ago

Adi Chirilov rascal

K A SUMUKH
2 years ago

whats the import statement

Sumukh KA
2 years ago

yes even i had the same doubt

Sumukh KA
2 years ago

++

Show more replies