Build a dashboard for monitoring e-commerce shipping orders
To upload files, please first save the app
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime, timedelta
from st_aggrid import AgGrid, GridOptionsBuilder, JsCode
import random
# Set page config
st.set_page_config(
page_title="E-commerce Shipping Dashboard",
page_icon="📦",
layout="wide",
initial_sidebar_state="expanded"
)
# Title and header
st.title("📦 E-commerce Shipping Dashboard")
st.markdown("Monitor and track shipping orders in real-time")
# Generate sample data
@st.cache_data
def generate_shipping_data():
np.random.seed(42)
# Generate data for the last 30 days
end_date = datetime.now()
start_date = end_date - timedelta(days=30)
# Order statuses and their weights
statuses = ['Pending', 'Processing', 'Shipped', 'In Transit', 'Out for Delivery', 'Delivered', 'Delayed', 'Cancelled']
status_weights = [0.05, 0.10, 0.15, 0.25, 0.10, 0.30, 0.03, 0.02]
# Shipping carriers
carriers = ['FedEx', 'UPS', 'USPS', 'DHL', 'Amazon Logistics']
# Regions
regions = ['North America', 'Europe', 'Asia', 'South America', 'Australia']
# Generate 1000 sample orders
n_orders = 1000
data = []
for i in range(n_orders):
order_date = start_date + timedelta(
days=random.randint(0, 30),
hours=random.randint(0, 23),
minutes=random.randint(0, 59)
)
status = np.random.choice(statuses, p=status_weights)
carrier = np.random.choice(carriers)
region = np.random.choice(regions)
# Calculate estimated delivery based on status
if status in ['Delivered']:
delivery_date = order_date + timedelta(days=random.randint(1, 7))
elif status in ['Cancelled']:
delivery_date = None
else:
delivery_date = order_date + timedelta(days=random.randint(1, 10))
# Calculate shipping cost
base_cost = random.uniform(5, 50)
if region in ['Asia', 'Australia']:
base_cost *= 1.5
data.append({
'Order ID': f'ORD-{10000 + i}',
'Order Date': order_date,
'Status': status,
'Carrier': carrier,
'Region': region,
'Shipping Cost': round(base_cost, 2),
'Estimated Delivery': delivery_date,
'Customer': f'Customer {i + 1}',
'Tracking Number': f'TRK{random.randint(100000000, 999999999)}'
})
return pd.DataFrame(data)
# Load data
df = generate_shipping_data()
# Sidebar filters
st.sidebar.header("Filters")
# Date range filter
date_range = st.sidebar.date_input(
"Select Date Range",
value=(df['Order Date'].min().date(), df['Order Date'].max().date()),
min_value=df['Order Date'].min().date(),
max_value=df['Order Date'].max().date()
)
# Status filter
status_filter = st.sidebar.multiselect(
"Order Status",
options=df['Status'].unique(),
default=df['Status'].unique()
)
# Carrier filter
carrier_filter = st.sidebar.multiselect(
"Shipping Carrier",
options=df['Carrier'].unique(),
default=df['Carrier'].unique()
)
# Region filter
region_filter = st.sidebar.multiselect(
"Region",
options=df['Region'].unique(),
default=df['Region'].unique()
)
# Apply filters
filtered_df = df[
(df['Order Date'].dt.date >= date_range[0]) &
(df['Order Date'].dt.date <= date_range[1]) &
(df['Status'].isin(status_filter)) &
(df['Carrier'].isin(carrier_filter)) &
(df['Region'].isin(region_filter))
].copy()
# Main dashboard metrics
col1, col2, col3, col4 = st.columns(4)
with col1:
total_orders = len(filtered_df)
st.metric("Total Orders", f"{total_orders:,}")
with col2:
delivered_orders = len(filtered_df[filtered_df['Status'] == 'Delivered'])
delivery_rate = (delivered_orders / total_orders * 100) if total_orders > 0 else 0
st.metric("Delivery Rate", f"{delivery_rate:.1f}%")
with col3:
delayed_orders = len(filtered_df[filtered_df['Status'] == 'Delayed'])
st.metric("Delayed Orders", f"{delayed_orders:,}")
with col4:
avg_shipping_cost = filtered_df['Shipping Cost'].mean()
st.metric("Avg Shipping Cost", f"${avg_shipping_cost:.2f}")
# Charts section
st.markdown("---")
# Row 1: Status distribution and carrier performance
col1, col2 = st.columns(2)
with col1:
st.subheader("Order Status Distribution")
status_counts = filtered_df['Status'].value_counts()
fig_status = px.pie(
values=status_counts.values,
names=status_counts.index,
title="Orders by Status"
)
fig_status.update_traces(textposition='inside', textinfo='percent+label')
st.plotly_chart(fig_status, use_container_width=True)
with col2:
st.subheader("Carrier Performance")
carrier_performance = filtered_df.groupby('Carrier').agg({
'Order ID': 'count',
'Shipping Cost': 'mean'
}).round(2)
carrier_performance.columns = ['Total Orders', 'Avg Cost']
fig_carrier = px.bar(
carrier_performance.reset_index(),
x='Carrier',
y='Total Orders',
title="Orders by Carrier",
color='Avg Cost',
color_continuous_scale='Blues'
)
st.plotly_chart(fig_carrier, use_container_width=True)
# Row 2: Timeline and regional analysis
col1, col2 = st.columns(2)
with col1:
st.subheader("Order Timeline")
# Group by date and status
timeline_data = filtered_df.groupby([filtered_df['Order Date'].dt.date, 'Status']).size().reset_index()
timeline_data.columns = ['Date', 'Status', 'Count']
fig_timeline = px.line(
timeline_data,
x='Date',
y='Count',
color='Status',
title="Daily Order Trends by Status"
)
st.plotly_chart(fig_timeline, use_container_width=True)
with col2:
st.subheader("Regional Analysis")
regional_data = filtered_df.groupby('Region').agg({
'Order ID': 'count',
'Shipping Cost': 'sum'
}).round(2)
regional_data.columns = ['Orders', 'Total Shipping Cost']
fig_region = px.bar(
regional_data.reset_index(),
x='Region',
y='Orders',
title="Orders by Region",
color='Total Shipping Cost',
color_continuous_scale='Greens'
)
st.plotly_chart(fig_region, use_container_width=True)
# Detailed orders table
st.markdown("---")
st.subheader("Order Details")
# Configure AgGrid
gb = GridOptionsBuilder.from_dataframe(filtered_df)
# Configure columns
gb.configure_default_column(
groupable=True,
value=True,
enableRowGroup=True,
editable=False,
filterable=True,
sortable=True
)
# Configure specific columns
gb.configure_column("Order ID", pinned="left", width=120)
gb.configure_column("Order Date", type=["dateColumnFilter", "customDateTimeFormat"],
custom_format_string="yyyy-MM-dd HH:mm")
gb.configure_column("Shipping Cost", type=["numericColumn", "numberColumnFilter", "customCurrencyFormat"],
custom_currency_symbol="$")
# Status column with custom styling
status_style = JsCode("""
function(params) {
if (params.value == 'Delivered') {
return {'color': 'white', 'backgroundColor': 'green'}
} else if (params.value == 'Delayed') {
return {'color': 'white', 'backgroundColor': 'red'}
} else if (params.value == 'Cancelled') {
return {'color': 'white', 'backgroundColor': 'darkred'}
} else if (params.value == 'Shipped' || params.value == 'In Transit') {
return {'color': 'white', 'backgroundColor': 'blue'}
} else {
return {'color': 'black', 'backgroundColor': 'lightgray'}
}
}
""")
gb.configure_column("Status", cellStyle=status_style)
# Configure selection and pagination
gb.configure_selection("multiple", use_checkbox=True)
gb.configure_pagination(paginationAutoPageSize=True)
gridOptions = gb.build()
# Display the grid
grid_response = AgGrid(
filtered_df,
gridOptions=gridOptions,
data_return_mode='AS_INPUT',
update_mode='MODEL_CHANGED',
fit_columns_on_grid_load=True,
enable_enterprise_modules=False,
height=400,
allow_unsafe_jscode=True
)
# Selected orders summary
if grid_response['selected_rows']:
st.subheader("Selected Orders Summary")
selected_df = pd.DataFrame(grid_response['selected_rows'])
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Selected Orders", len(selected_df))
with col2:
selected_cost = selected_df['Shipping Cost'].sum()
st.metric("Total Shipping Cost", f"${selected_cost:.2f}")
with col3:
selected_delivered = len(selected_df[selected_df['Status'] == 'Delivered'])
selected_rate = (selected_delivered / len(selected_df) * 100) if len(selected_df) > 0 else 0
st.metric("Delivery Rate", f"{selected_rate:.1f}%")
# Footer
st.markdown("---")
st.markdown("*Dashboard updates in real-time. Use filters to customize your view.*")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?