Mathew K Analytics

Lesson 36 · Supply Chain Operations Analytics

Building Supply Chain Dashboards with Streamlit

In this lesson, we solve operational supply chain problems by building interactive dashboards. These dashboards turn raw data about demand, inventory,…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Building Supply Chain Dashboards with Streamlit#

  • In this lesson, we solve operational supply chain problems by building interactive dashboards.
  • These dashboards turn raw data about demand, inventory, fulfillment, and supplier performance into actionable business insights.
  • Building dashboards matters because managers and analysts need quick, clear overviews to support key decisions.
  • You will learn to clean real supply chain data, analyze operations, and build a real-time dashboard using Streamlit.
  • Simple examples will help you start, followed by more advanced and realistic business analytics cases.
import pandas as pd
import numpy as np
import streamlit as st
import openml
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

Understanding Core Supply Chain Data#

  • Supply chain analytics relies on data about demand, inventory, suppliers, and order fulfillment.
  • Demand data shows what customers bought and when.
  • Inventory data records what is available to sell or use in production.
  • Supplier performance data reveals lead times, deliveries, and issues.
  • Order fulfillment data lets us see how quickly customers get their purchases.
  • Beginners often forget to check for missing, duplicated, or incorrectly typed values.
# Beginner Example 1: Load Retail Demand Data
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00502/online_retail_II.xlsx'
retail_df = pd.read_excel(url, sheet_name='Year 2010-2011')
retail_df['InvoiceDate'] = pd.to_datetime(retail_df['InvoiceDate'])
print(retail_df.shape)
print(retail_df.head(3))
(541910, 8)
  Invoice StockCode                         Description  Quantity  \
0  536365    85123A  WHITE HANGING HEART T-LIGHT HOLDER         6   
1  536365     71053                 WHITE METAL LANTERN         6   
2  536365    84406B      CREAM CUPID HEARTS COAT HANGER         8   

          InvoiceDate  Price  Customer ID         Country  
0 2010-12-01 08:26:00   2.55      17850.0  United Kingdom  
1 2010-12-01 08:26:00   3.39      17850.0  United Kingdom  
2 2010-12-01 08:26:00   2.75      17850.0  United Kingdom  
# Beginner Example 2: Load Order Fulfillment Data
olist_url = 'https://raw.githubusercontent.com/olist/work-at-olist-data/master/datasets/olist_orders_dataset.csv'
orders_df = pd.read_csv(olist_url)
orders_df['order_purchase_timestamp'] = pd.to_datetime(orders_df['order_purchase_timestamp'])
orders_df['order_delivered_customer_date'] = pd.to_datetime(orders_df['order_delivered_customer_date'])
print(orders_df.shape)
print(orders_df[['order_id','order_purchase_timestamp','order_delivered_customer_date']].head(3))
(99441, 8)
                           order_id order_purchase_timestamp  \
0  e481f51cbdc54678b7cc49136f2d6af7      2017-10-02 10:56:33   
1  53cdb2fc8bc7dce0b6741e2150273451      2018-07-24 20:41:37   
2  47770eb9100c2d0c44946d9cf07ec65d      2018-08-08 08:38:49   

  order_delivered_customer_date  
0           2017-10-10 21:25:13  
1           2018-08-07 15:27:45  
2           2018-08-17 18:06:29  
# Beginner Example 3: Load Supplier Performance Data
dataset = openml.datasets.get_dataset(42125)
supplier_df, _, _, _ = dataset.get_data(dataset_format='dataframe')
print(supplier_df.shape)
print(supplier_df.head(3))
(9228, 13)
          full_name gender  current_annual_salary  2016_gross_pay_received  \
0    Aarhus, Pam J.      F               69222.18                 71225.98   
1   Aaron, David J.      M               97392.47                103088.48   
2  Aaron, Marsha M.      F              104717.28                107000.24   

   2016_overtime_pay department                          department_name  \
0             416.10        POL                     Department of Police   
1            3326.19        POL                     Department of Police   
2            1353.32        HHS  Department of Health and Human Services   

                                            division assignment_category  \
0  MSB Information Mgmt and Tech Division Records...    Fulltime-Regular   
1         ISB Major Crimes Division Fugitive Section    Fulltime-Regular   
2      Adult Protective and Case Management Services    Fulltime-Regular   

       employee_position_title underfilled_job_title date_first_hired  \
0  Office Services Coordinator                  None       09/22/1986   
1        Master Police Officer                  None       09/12/1988   
2             Social Worker IV                  None       11/19/1989   

   year_first_hired  
0              1986  
1              1988  
2              1989  
# Intermediate Example 1: Summarize Weekly Retail Demand
retail_df['week'] = retail_df['InvoiceDate'].dt.isocalendar().week
weekly_sales = retail_df.groupby('week')['Quantity'].sum()
print(weekly_sales.head())
week
1    73491
2    85626
3    67969
4    69312
5    67613
Name: Quantity, dtype: int64
# Intermediate Example 2: Calculate Order Delivery Lead Time
orders_df['delivery_lead_time'] = (orders_df['order_delivered_customer_date'] - orders_df['order_purchase_timestamp']).dt.days
print(orders_df[['order_id','delivery_lead_time']].head())
                           order_id  delivery_lead_time
0  e481f51cbdc54678b7cc49136f2d6af7                 8.0
1  53cdb2fc8bc7dce0b6741e2150273451                13.0
2  47770eb9100c2d0c44946d9cf07ec65d                 9.0
3  949d5b44dbf5de918fe9c16f97b45f8a                13.0
4  ad21c59c0840e6cb83a9ceb5573f8159                 2.0
# Intermediate Example 3: Supplier Fill Rate Calculation
if 'Fill Rate' in supplier_df.columns:
    avg_fill = supplier_df['Fill Rate'].mean()
    print(f'Average supplier fill rate: {avg_fill:.2%}')
else:
    print('No Fill Rate column found in the supplier data.')
No Fill Rate column found in the supplier data.
# Intermediate Example 4: Filter Orders Missing Delivery Dates
missing_delivery = orders_df[orders_df['order_delivered_customer_date'].isnull()]
print(f'Missing delivery dates: {len(missing_delivery)} records')
Missing delivery dates: 2965 records
# Intermediate Example 5: Top 5 Most Popular Products
if 'Description' in retail_df.columns:
    top_products = retail_df.groupby('Description')['Quantity'].sum().nlargest(5)
    print(top_products)
else:
    print('Description column not found in the retail data.')
Description
WORLD WAR 2 GLIDERS ASSTD DESIGNS    53847
JUMBO BAG RED RETROSPOT              47363
ASSORTED COLOUR BIRD ORNAMENT        36381
POPCORN HOLDER                       36334
PACK OF 72 RETROSPOT CAKE CASES      36039
Name: Quantity, dtype: int64
# Advanced Example 1: Demand Time Series Chart with Matplotlib
plt.figure(figsize=(12,4))
weekly_sales.plot()
plt.title('Weekly Retail Demand')
plt.xlabel('Week number')
plt.ylabel('Total Quantity Sold')
plt.tight_layout()
plt.savefig('weekly_retail_demand.png')
plt.close()
# Advanced Example 2: Build a Minimal Streamlit Dashboard Script
dashboard_script = '''
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
retail_df = pd.read_excel('https://archive.ics.uci.edu/ml/machine-learning-databases/00502/online_retail_II.xlsx', sheet_name='Year 2010-2011')
retail_df['InvoiceDate'] = pd.to_datetime(retail_df['InvoiceDate'])
retail_df['week'] = retail_df['InvoiceDate'].dt.isocalendar().week
weekly_sales = retail_df.groupby('week')['Quantity'].sum()
st.title('Weekly Retail Demand Dashboard')
fig, ax = plt.subplots()
weekly_sales.plot(ax=ax)
ax.set_xlabel('Week number')
ax.set_ylabel('Total Quantity Sold')
st.pyplot(fig)
'''
with open('mini_dashboard.py', 'w') as f:
    f.write(dashboard_script)
 

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.