# How to create interactive charts in Django with Plotly

> Build interactive Gantt charts in Django using Plotly and pandas. Step-by-step tutorial covering models, views, templates, and data visualization setup.
> 
> 

**Source:** https://hackmamba.io/engineering/quickly-create-interactive-charts-in-django/
**Published:** 22 Mar 2022
**Author:** Asjad Khan
**Category:** Engineering

---
[Plotly](https://plotly.com/python/) is an open-source Python library for rendering interactive charts in the browser. It supports over 40 chart types covering statistical, financial, geographic, scientific, and 3D use cases, and it integrates cleanly with Django through its offline rendering mode.

This tutorial covers integrating Plotly into a Django application by building a project tracker that visualizes task timelines as an interactive [Gantt chart](https://en.wikipedia.org/wiki/Gantt_chart).

The full source code is on [GitHub](https://github.com/shosenwales/Gantt-Chart).

## Prerequisites

- [Python 3](https://www.python.org/downloads/) installed
- A basic understanding of Django

## Set up the project

Create a virtual environment to isolate dependencies from your global Python installation.

```bash
python -m venv env
```

Activate it:

```bash
source env/bin/activate
```

Install Django:

```bash
pip install django
```

Create a new Django project:

```bash
django-admin startproject django_plotly
```

Navigate into the project directory and create a Django app:

```bash
cd django_plotly
django-admin startapp charts
```

Add the app to `INSTALLED_APPS` in `settings.py`:

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'charts',
]
```

Install Plotly and [pandas](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html):

```bash
pip install plotly pandas
```

## Create the model

The model tracks project tasks with a name, start date, finish date, assigned user, and week number.

In `charts/models.py`:

```python
from django.db import models
from django.contrib.auth.models import User

class Chart(models.Model):
    name = models.CharField(max_length=200)
    start_date = models.DateField()
    responsible = models.ForeignKey(User, on_delete=models.CASCADE)
    week_number = models.CharField(max_length=2, blank=True)
    finish_date = models.DateField()

    def __str__(self):
        return str(self.name)

    def save(self, *args, **kwargs):
        if self.week_number == "":
            self.week_number = self.start_date.isocalendar()[1]
        super().save(*args, **kwargs)
```

The `save` override automatically calculates the ISO week number from `start_date` if none is provided.

Register the model in `charts/admin.py`:

```python
from django.contrib import admin
from .models import Chart

admin.site.register(Chart)
```

Run migrations:

```bash
python manage.py makemigrations
python manage.py migrate
```

Create a superuser to access the Django admin:

```bash
python manage.py createsuperuser
```

Start the server and log in at `http://localhost:8000/admin`:

```bash
python manage.py runserver
```

![Django admin dashboard](https://paper-attachments.dropbox.com/s_ADE9AAAB92E4CD5C41BF8866FC8A4F886894F722B4056ADBA4E1ABF4BEC2F8DA_1645696348672_admin.png)

## Create the view

The view queries all chart entries, formats them as a pandas DataFrame, and passes a rendered Plotly timeline to the template.

Create `django_plotly/views.py`:

```python
from django.shortcuts import render
from charts.models import Chart
import pandas as pd
from plotly.offline import plot
import plotly.express as px

def index(request):
    qs = Chart.objects.all()
    projects_data = [
        {
            'Project': x.name,
            'Start': x.start_date,
            'Finish': x.finish_date,
            'Responsible': x.responsible.username
        } for x in qs
    ]
    df = pd.DataFrame(projects_data)
    fig = px.timeline(
        df, x_start="Start", x_end="Finish", y="Project", color="Responsible"
    )
    fig.update_yaxes(autorange="reversed")
    gantt_plot = plot(fig, output_type="div")
    context = {'plot_div': gantt_plot}
    return render(request, 'index.html', context)
```

What each part does:

- `Chart.objects.all()` retrieves every project entry from the database
- The list comprehension shapes the queryset into a format pandas can consume
- `px.timeline` generates the Gantt chart — `x_start` and `x_end` define the horizontal axis, `y` sets the row labels, and `color` assigns distinct colors per responsible user
- `plot(fig, output_type="div")` renders the chart as an HTML `<div>` string, which the template injects directly into the page

## Create the templates

Create a `templates` directory in the project root. Inside it, add two files: `base.html` and `index.html`.

`base.html` provides the page skeleton with Bootstrap for basic styling:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <title>Plotly Chart</title>
</head>
<body>
    <div class="container mt-3">
        {% block content %}
        {% endblock content %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
```

`index.html` renders the Plotly chart div:

```html
{% extends "base.html" %}
{% block content %}
    {% autoescape off %}
        {{ plot_div }}
    {% endautoescape %}
{% endblock content %}
```

Update `TEMPLATES` in `settings.py` to point to the templates directory:

```python
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [ BASE_DIR / 'templates' ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
```

## Configure URLs

Update `django_plotly/urls.py`:

```python
from django.contrib import admin
from django.urls import path
from .views import index

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', index)
]
```

## Add data and test

In the Django admin, add a few project entries with different users, start dates, and finish dates.

![Web project entry in Django admin](https://paper-attachments.dropbox.com/s_ADE9AAAB92E4CD5C41BF8866FC8A4F886894F722B4056ADBA4E1ABF4BEC2F8DA_1645700067630_web.png)

![Django project entry in Django admin](https://paper-attachments.dropbox.com/s_ADE9AAAB92E4CD5C41BF8866FC8A4F886894F722B4056ADBA4E1ABF4BEC2F8DA_1645700117562_django.png)

Start the server:

```bash
python manage.py runserver
```

Visit `http://localhost:8000` to see the interactive Gantt chart with each project plotted as a timeline bar, color-coded by the responsible user.

![Completed interactive Gantt chart rendered with Plotly](https://paper-attachments.dropbox.com/s_ADE9AAAB92E4CD5C41BF8866FC8A4F886894F722B4056ADBA4E1ABF4BEC2F8DA_1645700636640_full-chart.png)

## Where to go next

This tutorial covers the core integration pattern. From here you can extend the project with date range filters, user authentication for the chart view, or additional Plotly chart types. The [Plotly Python documentation](https://plotly.com/python/getting-started/) covers all 40+ chart types with examples.

## FAQs

1, **What is Plotly and how does it work with Django?**

Plotly is a Python library that generates interactive, browser-based charts. In Django, you generate a chart figure using Plotly's Python API, render it as an HTML `<div>` string using `plotly.offline.plot` with `output_type="div"`, and pass that string to a Django template. The template injects it directly into the page with `{% autoescape off %}`.

2, **What is a Gantt chart used for?**

A Gantt chart visualizes a project schedule by plotting tasks as horizontal bars along a timeline. Each bar shows a task's start and end date. They are commonly used in project management to track task progress and resource assignment across time.

3, **What does `output_type="div"` do in Plotly?**

Setting `output_type="div"` in `plotly.offline.plot` returns the chart as a self-contained HTML string instead of opening it as a file. This string includes the chart's JavaScript and can be injected directly into a Django template, which is what makes offline Plotly rendering work in server-side web frameworks.

4, **Why do I need pandas to use Plotly in Django?**

Plotly's high-level `plotly.express` functions like `px.timeline` expect data as a pandas DataFrame. Pandas handles the data structuring so Plotly can map columns directly to chart axes and attributes. For simple datasets you can also pass dictionaries or lists directly to lower-level Plotly graph objects without pandas.

5, **Can I use Plotly with Django REST Framework?**

Yes. You can generate Plotly figures server-side and return the chart JSON using `fig.to_json()`, then render it on the frontend using [Plotly.js](https://plotly.com/javascript/). This approach works well when your frontend is a JavaScript SPA consuming a DRF API.
