How To Add Charts To Your Python Application

Charts are a great way to communicate information visually. When used in user interfaces, they can help users understand data more easily and make better decisions. In this article, we will show you how to easily add charts to your python application using echarts.

Pyecharts is a Python library that allows you to create various types of charts and graphs without using javascript. It is a wrapper around the beautiful echarts library. It is easy to use and has a wide range of features. It is also open source and free to use. In this article, we will show you how to easily add charts to your python application using the pyecharts.

Prerequisites

  • A Django  Project - You can find the codebase for this project here. In this example, we are using Django, but you can also use Flask or FastAPI.

Getting started

Install the pyecharts library or add it to your dependencies.

pip install pyecharts

Chart module

Pyecharts is a library for configuring echarts options in python. For convenience, we will create a chart module where we will define standard charts that can be reused across the application.

charts/echarts.py

from pyecharts.charts import Bar, Line
from pyecharts.options import (
    AreaStyleOpts,
    AxisLineOpts,
    AxisOpts,
    AxisTickOpts,
    InitOpts,
    LabelOpts,
    LegendOpts,
    LineStyleOpts,
    TextStyleOpts,
    TitleOpts,
)

class Colors:
   default = "#818cf8"   
   yellow = "#ffe5cb"
   green = "#d3fce7"
  

TITLE_TEXT_STYLE_OPTIONS = TextStyleOpts(
    color="#4b5562", font_size=16, font_weight="600"
)
TITLE_OPTS = {
    "pos_top": "0px",
    "pos_left": "2px",
    "item_gap": 10,
    "title_textstyle_opts": TITLE_TEXT_STYLE_OPTIONS,
}

AXIS_LINE_OPTS = AxisLineOpts(
    linestyle_opts=LineStyleOpts(color="#9ca3af")
)


def line_chart(data: dict, color = None):
    """Line chart"""
    
    color = color or Colors.default
    
    # create chart instance
    line = Line(init_opts=InitOpts(width="105%", height="300px"))
    
    # add y,x axis data
    line.add_xaxis(data["x"])
    line.add_yaxis(
            "",
        data["y"],
        is_smooth=False,
        areastyle_opts=AreaStyleOpts(opacity=0.1, color=color),
        label_opts=LabelOpts(is_show=False),
    )
    
    # add chart options
    line.set_colors([color])
    line.set_global_opts(
        title_opts=TitleOpts(title=data["chart_title"], **TITLE_OPTS),
        legend_opts=LegendOpts(is_show=False),
        yaxis_opts=AxisOpts(
            position="bottom",
            name_location="end",
            axisline_opts=AXIS_LINE_OPTS,
            axistick_opts=AxisTickOpts(is_show=False),
        ),
        xaxis_opts=AxisOpts(
            axisline_opts=AXIS_LINE_OPTS, axistick_opts=AxisTickOpts(is_show=False)
        ),
    )

    # finally prepare chart options for rendering.
    line._prepare_render()
    return line

Notes

  • TitleOpts, InitOpts - these are classes for defining configuration variables for the charts. For a full list of the options in echarts see this page.
  • def line_chart(..) - this method expects dataand color as parameters. The color must be a hex string, the data should be a dictionary with values for x & y axis and a chart title. We will see an example in the view below.
  • line = Line(init_opts=InitOpts(width="105%...) - this line declares an instance of the Line chart class with some initial options.
  • the next few lines we add y and x axis data and set chart options
  • line._prepare_render() - finally we prepare the chart for rendering. This method formats the chart options and theme into JSON for rendering on the frontend.

Add the view and urls

charts/views.py

from django.shortcuts import render
from charts.echarts import line_chart, Colors


def dashboard_view(request):

  
  total_page_views = {
    "x":["mon", "tue", "wed", "thur", "fri", "sat","sun"],
    "y":[8,20,15,20,50,30, 35],
    "chart_title": "Total Page Views",
  }

  unique_visitors = {
    "x":["mon", "tue", "wed", "thur", "fri", "sat","sun"],
    "y":[3,4,10,12,30,20,33],
    "chart_title": "Unique Visitors",
  }
  signups = {
    "x":["mon", "tue", "wed", "thur", "fri", "sat","sun"],
    "y":[3,4,10,12,30,20,33],
    "chart_title": "Signups",
  }
  charts = [
    line_chart(total_page_views),
    line_chart(unique_visitors, Colors.yellow),
    line_chart(signups, Colors.green)
  ]

  context = {
    "charts": charts
  }

  return render(request, "dashboard.html", context)
  

Notes

  • def dashboard_view - in this view, we create 3 line charts for our dashboard. Notice that we used custom colors for two of the charts.

django_project/urls.py

urlpatterns = [
  ... 
  path("", dashboard_view, name='stats')
]

View Templates

charts/dashboard.html(continued)


<html id="id-html" lang="{{ language_code }}" >

<head>
  <title> Dashboard</title>
  <meta charset="UTF-8">
  <meta name="msapplication-TileColor" content="#da532c">
  <meta name="theme-color" content="#ffffff">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

   <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="bg-slate-100">
  <div class="w-full max-w-5xl mx-auto flex flex-col space-y-5 p-4">
    <div class="flex px-4 py-2 justify-between mt-10">
      <span class="text-gray-600 font-semibold">📊 analytics.io</span>
      <div class="bg-white rounded shadow p-2 text-sm text-gray-600 flex items-center font-semibold mr-2 cursor-pointer">Last Week
          <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
      <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
    </svg>
      </div>
    </div>
    <div class="w-full grid grid-cols-2 gap-6">
     {# loop through the list of charts and add placeholder divs to grid #}
      {% for c in charts %}
        <div class="bg-white shadow rounded-lg p-4 {% if forloop.counter0 == 0 %}col-span-2 {% endif %}">
          <div id="{{ c.chart_id }}" class="chart-container" style="width:{{ c.width }}; height:{{ c.height }};">  
          </div>
        </div>
      {% endfor %}
    </div>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.3/echarts.min.js" integrity="sha512-2L0h0GhoIHQEjti/1KwfjcbyaTHy+hPPhE1o5wTCmviYcPO/TD9oZvUxFQtWvBkCSTIpt+fjsx1CCx6ekb51gw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script>

   // todo below
    
  </script>
</body>
</html>

Notes

  • <script src="https://cdn.tailwindcss.com"></script> - we are using tailwindcss for styling. In production, make sure you minify your files. You can see our tutorial on using Django and tailwind if you need help with setting this up for your project.
  • <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts...- we are loading echarts from a CDN, you should consider adding it to your staticfiles.
  • {% for c in charts %} .. - here we loop through the list of charts and add them to a grid.
  • {% if forloop.counter0 == 0 %}col-span-2 {% endif %} - we added a bit of custom styling here to ensure that the first chart spans two columns.

Almost there, let's add some javascript for rendering the charts.

charts/dashboard.html(continued)

 ...

    <script>
    document.addEventListener("DOMContentLoaded", function(){
      {% for c in charts %}
      
        var chart_{{ c.chart_id }} = echarts.init(
          document.getElementById('{{ c.chart_id }}'), 
                                   '{{ c.theme }}', 
                                    { renderer: '{{ c.renderer }}'}
                                 );
        {% for js in c.js_functions.items %}
          {{ js|safe }}
        {% endfor %}
        
        var option_{{ c.chart_id }} = {{ c.json_contents|safe }};
        chart_{{ c.chart_id }}.setOption(option_{{ c.chart_id }});
        
  
        {% if c.width|slice:"-1:" == '%' %}
          window.addEventListener('resize', function(){
            chart_{{ c.chart_id }}.resize();
          })
        {% endif %}
        
      {% endfor %}
    })
  </script>

Notes

Let's walk through it together.

  • {% for c in charts %} - we loop through the charts context variable
    • var chart_{{ c.chart_id }} = echarts.init(..) - select each chart placeholder and initialize the chart.
    • var option_{{ c.chart_id }} = {{ c.json_contents|safe }}; - this renders the chart options and sets them on the chart
    • {% if c.width|slice:"-1:" == '%' %} - for charts where we have set the width type as a percentage, we need to call the resize method to ensure that the chart fills up the right amount of space.

Conclusion

The pyecharts library provides a clean python interface for configuring chart options from your python code. You can now easily add charts to display revenue data that your SaaS business is generating or the number of new users that are signing up for your SaaS service. In future articles, we will show you how to make the charts more interactive with HTMX.

Additional reading

A good starting point for using the python library is to have a look at the available configuration options in the core echarts javascript library docs and then use the equivalent in your python code.

Frequently asked questions

  • Question - Does this apply to other python frameworks like flask/fast api?
    • Yes, you can use the library with Flask or Fast API. There is nothing unique to Django in the tutorial.

If you want to build a SaaS product quickly and efficiently, without wasting time on core features such as Payments, Authentication, CRM, Teams, and more, check out the Vanty Starter Kit.

Last Updated 25 Sep 2022