2025-12-12

Create an Interactive Data Dashboard with Python: From Zero to Deployed in Minutes

Python, Flask, Pandas, Data Dashboards · Dorian Sotpyrc

Sometimes you just want a quick way to explore real data with a small team: a few KPI cards, a couple of charts, and a table you can filter without opening Excel for the 14th time today. You don’t need a full BI suite or a new framework – you just need a tiny, honest dashboard you can understand end to end.

This project shows how to build exactly that: a minimal Flask + Pandas dashboard that turns a CSV file into an interactive web UI, then lets you swap datasets and reconfigure metrics in minutes. By the end, you’ll know how to clone the repo, run it locally, plug in your own data, and ship a small dashboard that feels surprisingly “production-flavoured”.

Python-powered dashboard showing KPI cards and charts for a marketing dataset
A minimal Flask + Pandas dashboard: CSV in, JSON out, interactive charts in the browser.

What this small Flask dashboard gives you out of the box

The repo is intentionally simple: there’s no Plotly, no Streamlit, and no front-end framework. Instead, you get a clear chain from data to pixels:

  • CSV in – a single input file loaded with Pandas.
  • Config-driven KPIs – cards defined in config/dashboard.yml, not hard-coded Python.
  • JSON API – Flask routes expose metrics and chart data as JSON.
  • Vanilla JS + SVG – charts rendered directly in the browser, so you can see exactly how they work.
  • Neat, responsive UI – a clean layout that feels like a real product, not a throwaway demo.

Because the dashboard is controlled by a YAML config and a CSV path, you can point it at a different dataset (for example, marketing performance instead of sales data) and get a new view without rewriting the backend.

First launch of the Python dashboard using the default sample sales dataset
First launch: the default dashboard running against the bundled sample sales dataset.
Get the code on GitHub

The complete project used in this walkthrough lives here:
https://github.com/dorian-sotpyrc/create-an-interactive-data-dashboard-with-python
Clone it and follow along with the steps below on your own machine.

Run your first dashboard in a few shell commands

Let’s start from zero and get the default dashboard running locally. You only need Python, Git, and a terminal.

  1. Clone the repo and create a virtual environment

    From a working folder, clone the project and create a fresh environment so you don’t pollute your global Python install:

    BASH
    git clone https://github.com/dorian-sotpyrc/create-an-interactive-data-dashboard-with-python.git
    cd create-an-interactive-data-dashboard-with-python
    
    python -m venv .venv
    source .venv/bin/activate  # On Windows: .venv\Scripts\activate
  2. Install dependencies and start Flask

    Install the minimal dependency set, then run the app entrypoint:

    BASH
    pip install -r requirements.txt
    python app.py

    By default the server binds to 0.0.0.0:8509, so you can visit http://127.0.0.1:8509 in your browser. You should see KPI cards, a couple of charts, and a “Recent rows” table backed by the sample dataset.

  3. Click around and watch the API in action

    Open your browser’s network tab: as you change the date filters, you’ll see calls to /api/metrics, /api/charts/<chart_id>, and /api/table. These endpoints are driven entirely by the YAML config, not hard-coded for a single project.

Why a tiny dashboard beats another spreadsheet

Once a question crops up more than a couple of times, it deserves a small dashboard. A lightweight Flask app like this gives you a single, repeatable view of the truth instead of half a dozen “final_v3.xlsx” files floating around.

Swap in your own CSV without touching the backend

The dashboard doesn’t care what your data represents – sales, marketing, lab measurements, IoT telemetry – as long as it’s tabular and has a date column. To plug in a new dataset, you update two things:

  • The CSV file itself, stored under data/.
  • The data_source and metric/chart definitions in config/dashboard.yml.

For example, the repo now ships with a small marketing performance dataset:

TEXT
data/marketing_campaign_performance.csv

date,campaign,channel,spend,clicks,signups,revenue
2025-01-01,Launch A,Search,420,950,120,3100
2025-01-01,Launch A,Social,260,780,90,2100
...

To make the dashboard use this data instead of the original sales sample, point data_source at the new file and ensure date_column reflects your date field:

YAML
# config/dashboard.yml

data_source: data/marketing_campaign_performance.csv
date_column: date
Updated dashboard configuration and CSV file for a marketing dataset
Swapping in a marketing CSV and updating config/dashboard.yml to point at the new source.

Define KPI cards and charts with a few YAML lines

Once your data is wired in, you decide what to show on the dashboard. The project treats metrics and charts as configuration, not code, which keeps the Flask layer small and predictable.

For example, here’s the marketing metrics section for total spend, revenue, signups, and two ratios:

YAML
metrics:
  - id: total_spend
    label: Total Spend
    column: spend
    aggregation: sum
    format: "$,.2f"

  - id: total_revenue
    label: Total Revenue
    column: revenue
    aggregation: sum
    format: "$,.2f"

  - id: total_signups
    label: Total Signups
    column: signups
    aggregation: sum
    format: "0.0"

  - id: roas
    label: ROAS (Revenue / Spend)
    numerator: revenue
    denominator: spend
    aggregation: ratio
    format: "0.00"

  - id: conversion_rate
    label: Conversion Rate (Signups / Clicks)
    numerator: signups
    denominator: clicks
    aggregation: ratio
    format: "0.0%"

Each metric declares:

  • Which column(s) to aggregate.
  • How to aggregate (sum, mean, ratio, etc.).
  • How to format the result for display.

Charts follow the same pattern. Here’s the block that defines revenue and spend over time, plus breakdowns by channel and campaign:

YAML
charts:
  - id: revenue_over_time
    label: Revenue Over Time
    type: line
    x: date
    y: revenue
    aggregation: sum

  - id: spend_over_time
    label: Spend Over Time
    type: line
    x: date
    y: spend
    aggregation: sum

  - id: revenue_by_channel
    label: Revenue by Channel
    type: bar
    x: channel
    y: revenue
    aggregation: sum

  - id: signups_by_campaign
    label: Signups by Campaign
    type: bar
    x: campaign
    y: signups
    aggregation: sum

When you restart the app, the frontend reads this config, requests chart data from Flask, and draws SVG visuals in a consistent PLEX style. To add a new chart later – for example, click-through rate by campaign – you just add another block to charts.

Updated dashboard view showing marketing KPIs and charts
Updated dashboard: new KPI cards and charts driven entirely by the marketing configuration.

Understand the JSON API powering the browser

The reason this dashboard is easy to extend is that everything flows through a small JSON API. Three endpoints do most of the work:

  • /api/metrics – runs aggregations defined in metrics and returns card values.
  • /api/charts/<chart_id> – returns a simple { id, label, type, points } payload for each chart.
  • /api/table – returns up to 50 recent rows for a quick “what’s really in this dataset?” view.

Filters like start_date and end_date are passed as query parameters, then applied in Pandas via a small helper in app/data.py. Because the response shapes are stable, the front-end code in static/js/dashboard.js barely changes as you add new metrics and charts.

Deploy the dashboard so your team can explore data together

Once you’re happy with the layout and metrics, you can promote this from a local experiment to a shared internal tool. The repo includes a Dockerfile and a Gunicorn command so you can host it alongside other PLEX-style tools.

BASH
# Run with Gunicorn
gunicorn "app:create_app()" --bind 0.0.0.0:8000

On a small VPS or internal server, that’s enough to give your team a stable URL where they can slice the data, change date ranges, and discuss results using the same source of truth.

Where to take this dashboard pattern next

The version in this repo is deliberately small. It’s meant to be copied, forked, and modified, not treated as a sealed product. From here you can:

  • Point it at a live database instead of a static CSV.
  • Add authentication so only your team can see sensitive metrics.
  • Introduce more advanced charts (stacked bars, rolling averages) while keeping the JSON contract simple.
  • Turn it into a template for all your “quick question” dashboards so you never start from a blank Flask app again.

Most importantly, you now have a pattern: data → config → JSON API → lightweight UI. That’s a foundation you can re-use across projects, whether you’re building internal tools at work or experimenting on your own time.

Related PLEX reading

References & further reading

  • Flask documentation
    Official documentation for the microframework that powers the dashboard’s routing and JSON API.
  • Pandas user guide
    Deep dive into the DataFrame operations you’ll use to aggregate metrics and prepare chart data.
  • MDN SVG tutorial
    A practical introduction to drawing lines, shapes, and text with SVG – exactly what this dashboard’s charts rely on.
  • YAML specification and overview
    Background on the configuration format used by config/dashboard.yml to describe metrics and charts.
  • The Twelve-Factor App
    A set of principles for packaging and deploying small services; useful when you start running this dashboard in production-like environments.