Skip to content

A comprehensive guide and codebase for building interactive storytelling dashboards with Python, Streamlit, and Plotly. Learn how to transform static analytics into dynamic, user-driven data experiences that engage and inspire, featuring RFM segmentation, cohort analysis, and real-world insights.

License

Notifications You must be signed in to change notification settings

AmirhosseinHonardoust/Beyond-Charts-Interactive-Storytelling

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

Beyond Charts: Interactive Storytelling with Streamlit & Plotly

Introduction, Why Data Storytelling Needs to Evolve

Data storytelling is no longer about showing a few colorful charts, it’s about creating experiences.
Modern audiences don’t just want to see numbers; they want to explore, filter, and understand them interactively.

Static dashboards or PowerPoint slides can show metrics, but they fail to answer the question every stakeholder cares about:

“What does this data mean for me?”

That’s where tools like Streamlit and Plotly redefine what data storytelling can be. They turn passive data presentations into interactive narratives, allowing users to ask their own questions, explore relationships, and uncover insights dynamically.

In this article, I’ll walk you through how I built a data storytelling dashboard, a full-scale interactive app that transforms a simple e-commerce dataset into a living, explorable story.


The Foundation, Why Streamlit + Plotly?

Streamlit and Plotly are a dream combination for data analysts and data scientists.

Tool Role in the Storytelling Stack
Streamlit Frontend & interaction layer: creates web apps directly from Python scripts.
Plotly Visualization engine: renders fully interactive charts (hover, zoom, filter).
Pandas / NumPy Data processing, cleaning, feature engineering.
Scikit-learn / Statsmodels (optional) Advanced analytics: clustering, forecasting.

Together, they form a narrative pipeline:

Data → Transformation → Visualization → Interaction → Insight → Action

Unlike Power BI or Tableau, you control the logic end-to-end.
It’s not just a dashboard, it’s an intelligent interface that grows with your story.


The Dataset, A Story of E-Commerce

To demonstrate, I created a synthetic e-commerce dataset containing:

  • 4,000+ orders
  • 1,600+ unique customers
  • 10 countries and 5 product categories
  • Multiple sales channels: Web, Mobile App, Retail Store, Marketplace

Each record includes variables like:

order_id, order_date, customer_id, country, city,
channel, category, subcategory, quantity, unit_price, discount, revenue, cost

From this, we can derive core business KPIs:

  • Revenue = unit_price × quantity × (1 - discount)
  • Profit = revenue - cost
  • Margin% = profit ÷ revenue
  • AOV (Average Order Value) = revenue per order

The goal was simple:
Create a dashboard where users could see the big picture but also drill down into specifics, by time, country, category, or channel.


Structuring the Data Story

A good dashboard has a narrative flow, just like a story:

  1. Overview | What’s happening overall?
  2. Trends | How is performance changing over time?
  3. Breakdowns | Where do results differ by category, product, or region?
  4. Behavior | Who are the customers driving those numbers?
  5. Takeaway | What actions or patterns emerge?

Each section uses a different combination of Plotly visualizations to tell that part of the story.


Step 1: Setting Up the Environment

Install dependencies:

pip install streamlit plotly pandas numpy

Create the basic project structure:

data_storytelling_dashboard/
├── data/
│   └── orders.csv
├── app/
│   ├── app.py
│   └── utils/
│       └── data_utils.py
└── requirements.txt

Step 2: Designing Interactivity, Filters as Story Chapters

A storytelling dashboard isn’t about dumping all data, it’s about guiding users through controlled exploration.

In Streamlit, we add sidebar filters like this:

import streamlit as st
import pandas as pd

df = pd.read_csv("data/orders.csv", parse_dates=["order_date"])

st.sidebar.header("Filters")
countries = st.sidebar.multiselect("Country", sorted(df["country"].unique()))
channels = st.sidebar.multiselect("Channel", sorted(df["channel"].unique()))
categories = st.sidebar.multiselect("Category", sorted(df["category"].unique()))

mask = (df["country"].isin(countries) if countries else True) &        (df["channel"].isin(channels) if channels else True) &        (df["category"].isin(categories) if categories else True)

filtered_df = df[mask]

Each user interaction redefines the context, they become the storyteller.


Step 3: Visualizing KPIs, The Executive Snapshot

Dashboards must start with quick-glance insights, the numbers that tell the story upfront:

total_revenue = filtered_df["revenue"].sum()
total_profit = filtered_df["profit"].sum()
total_orders = filtered_df["order_id"].nunique()
aov = filtered_df.groupby("order_id")["revenue"].sum().mean()
margin = (total_profit / total_revenue) * 100

col1, col2, col3 = st.columns(3)
col1.metric("Revenue", f"${total_revenue:,.0f}")
col2.metric("Profit", f"${total_profit:,.0f}")
col3.metric("AOV", f"${aov:,.2f}")
st.metric("Margin", f"{margin:.2f}%")

This acts like the headline of a news article, a summary before the deep dive.


Step 4: Time Series Storytelling, Revenue Over Time

Trends reveal change, and change drives stories.

import plotly.express as px

filtered_df["month"] = filtered_df["order_date"].dt.to_period("M").dt.to_timestamp()
monthly = filtered_df.groupby("month")[["revenue", "profit"]].sum().reset_index()

fig = px.line(monthly, x="month", y=["revenue", "profit"],
              labels={"value": "Amount ($)", "month": "Month"},
              title="Monthly Revenue and Profit Trends")
st.plotly_chart(fig, use_container_width=True)

Users can hover over any month to see exact values or zoom in to investigate seasonal peaks.
That zooming in moment, when a manager discovers why Q3 revenue jumped, is storytelling in motion.


Step 5: Category Breakdown, Where Is the Money?

Understanding which products drive performance adds texture to the story.

cat_rev = filtered_df.groupby("category")["revenue"].sum().reset_index()
fig_cat = px.bar(cat_rev, x="category", y="revenue", title="Revenue by Category")
st.plotly_chart(fig_cat, use_container_width=True)

Users might then ask:

“Why did Electronics outperform Home last quarter?”
They filter by quarter or country and the narrative deepens.


Step 6: Geography, Mapping Global Performance

geo = filtered_df.groupby(["country","city"])["revenue"].sum().reset_index()
fig_geo = px.treemap(geo, path=["country","city"], values="revenue",
                     title="Revenue by Geography (Country → City)")
st.plotly_chart(fig_geo, use_container_width=True)

The treemap visually tells a hierarchy, countries as chapters, cities as paragraphs.
It’s a spatial story, turning geography into insight.


Step 7: Customer Segmentation, Behavior as a Storyline

Use RFM segmentation (Recency, Frequency, Monetary value) to classify customers:

from datetime import datetime

snapshot_date = filtered_df["order_date"].max() + pd.Timedelta(days=1)
rfm = filtered_df.groupby("customer_id").agg({
    "order_date": lambda x: (snapshot_date - x.max()).days,
    "order_id": "nunique",
    "revenue": "sum"
}).rename(columns={"order_date": "Recency", "order_id": "Frequency", "revenue": "Monetary"})

rfm["Segment"] = pd.qcut(rfm["Monetary"], q=3, labels=["Low", "Mid", "High"])
fig_rfm = px.bar(rfm["Segment"].value_counts().reset_index(),
                 x="index", y="Segment", title="Customers by Value Segment")
st.plotly_chart(fig_rfm, use_container_width=True)

This shows who drives your business.
It’s not just about data, it’s about characters in your story: loyal customers, new buyers, and inactive ones.


Step 8: Cohort Retention, The Story of Loyalty

Cohort analysis visualizes how long customers stay engaged.

filtered_df["order_month"] = filtered_df["order_date"].dt.to_period("M")
first_purchase = filtered_df.groupby("customer_id")["order_month"].min()
filtered_df["CohortMonth"] = filtered_df["customer_id"].map(first_purchase)
filtered_df["CohortIndex"] = (filtered_df["order_month"].dt.year - filtered_df["CohortMonth"].dt.year) * 12 +                              (filtered_df["order_month"].dt.month - filtered_df["CohortMonth"].dt.month) + 1

cohort = filtered_df.groupby(["CohortMonth", "CohortIndex"])["customer_id"].nunique().reset_index()
cohort_pivot = cohort.pivot(index="CohortMonth", columns="CohortIndex", values="customer_id")

fig_cohort = px.imshow(cohort_pivot, color_continuous_scale="Greens", aspect="auto",
                       title="Customer Retention by Cohort")
st.plotly_chart(fig_cohort, use_container_width=True)

Each cohort row becomes a chapter in the customer story you can literally see how long users stay active after their first purchase.


The Design Philosophy, Storytelling Through Structure

A well-designed dashboard is not a wall of charts, it’s a guided tour.

Hierarchy

Show the most important story first (KPIs), then move to supporting details.

Flow

Arrange visuals in a sequence: Overview → Trends → Segments → Details.

Interactivity

Filters, sliders, and dropdowns invite curiosity, they make users think.

Emotion

Design with empathy: colors, spacing, and icons all affect readability and mood.


Extending the Story

Once you have a working interactive dashboard, the possibilities expand:

  • Forecasting: Add a Prophet model to predict future revenue.
  • Anomaly Detection: Flag sudden drops in KPIs automatically.
  • Natural Language Narratives: Use LLMs to auto-generate summaries like:

    “Revenue grew by 18% MoM, led by Electronics and India.”

  • Custom Exports: Allow users to download filtered datasets as CSV or PDF.

These transform your dashboard into a decision assistant, not just a report.


Deployment, Sharing Your Story

You can host your dashboard easily:

Platform Description
Streamlit Cloud One-click deployment from GitHub
Render / Hugging Face Spaces Free-tier hosting options
Docker + AWS / GCP For enterprise-grade performance

Add authentication (streamlit-authenticator) if you want private dashboards for internal teams.


Lessons Learned

  1. Interactivity drives insight. People engage more when they can explore.
  2. Context beats complexity. Always show comparisons, not isolated metrics.
  3. Every chart should answer a question. If it doesn’t, it’s noise.
  4. Storytelling = design + psychology + analytics.
  5. Build for clarity, not for impressiveness. Less is often more.

Key Takeaway

“Charts inform, but interactions enlighten.”

With Streamlit and Plotly, data storytelling evolves from passive reporting to active exploration.
Users don’t just see the data, they feel it, question it, and remember it.

That’s the essence of interactive storytelling, beyond charts.

About

A comprehensive guide and codebase for building interactive storytelling dashboards with Python, Streamlit, and Plotly. Learn how to transform static analytics into dynamic, user-driven data experiences that engage and inspire, featuring RFM segmentation, cohort analysis, and real-world insights.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published