entropy25's picture
Update analytics.py
463287e verified
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import streamlit as st
from typing import Dict, Optional, List
from config import get_chart_theme, DESIGN_SYSTEM, get_translation
@st.cache_data
def get_material_stats(df: pd.DataFrame) -> Dict:
stats = {}
total = df['weight_kg'].sum()
total_work_days = df['date'].nunique()
for material in df['material_type'].unique():
data = df[df['material_type'] == material]
work_days = data['date'].nunique()
daily_avg = data.groupby('date')['weight_kg'].sum().mean()
stats[material] = {
'total': data['weight_kg'].sum(),
'percentage': (data['weight_kg'].sum() / total) * 100,
'daily_avg': daily_avg,
'work_days': work_days,
'records': len(data)
}
stats['_total_'] = {
'total': total,
'percentage': 100.0,
'daily_avg': df.groupby('date')['weight_kg'].sum().mean(),
'work_days': total_work_days,
'records': len(df)
}
return stats
@st.cache_data
def detect_outliers(df: pd.DataFrame) -> Dict:
outliers = {}
for material in df['material_type'].unique():
material_data = df[df['material_type'] == material]
data = material_data['weight_kg']
Q1, Q3 = data.quantile(0.25), data.quantile(0.75)
IQR = Q3 - Q1
lower, upper = Q1 - 1.5 * IQR, Q3 + 1.5 * IQR
outlier_mask = (data < lower) | (data > upper)
outlier_dates = material_data[outlier_mask]['date'].dt.strftime('%Y-%m-%d').tolist()
outliers[material] = {
'count': len(outlier_dates),
'range': f"{lower:.0f} - {upper:.0f} kg",
'dates': outlier_dates
}
return outliers
def create_total_production_chart(df: pd.DataFrame, time_period: str = 'daily', lang: str = 'English'):
t = get_translation(lang)
if time_period == 'daily':
grouped = df.groupby('date')['weight_kg'].sum().reset_index()
fig = px.line(grouped, x='date', y='weight_kg',
title=t.get('chart_total_production', 'Total Production Trend'),
labels={'weight_kg': t.get('label_weight', 'Weight (kg)'), 'date': t.get('label_date', 'Date')})
elif time_period == 'weekly':
df_copy = df.copy()
df_copy['week'] = df_copy['date'].dt.isocalendar().week
df_copy['year'] = df_copy['date'].dt.year
grouped = df_copy.groupby(['year', 'week'])['weight_kg'].sum().reset_index()
grouped['week_label'] = grouped['year'].astype(str) + '-W' + grouped['week'].astype(str)
fig = px.bar(grouped, x='week_label', y='weight_kg',
title=t.get('chart_total_production_weekly', 'Total Production Trend (Weekly)'),
labels={'weight_kg': t.get('label_weight', 'Weight (kg)'), 'week_label': t.get('label_week', 'Week')})
else:
df_copy = df.copy()
df_copy['month'] = df_copy['date'].dt.to_period('M')
grouped = df_copy.groupby('month')['weight_kg'].sum().reset_index()
grouped['month'] = grouped['month'].astype(str)
fig = px.bar(grouped, x='month', y='weight_kg',
title=t.get('chart_total_production_monthly', 'Total Production Trend (Monthly)'),
labels={'weight_kg': t.get('label_weight', 'Weight (kg)'), 'month': t.get('label_month', 'Month')})
fig.update_layout(**get_chart_theme()['layout'], height=400, showlegend=False)
return fig
def create_materials_trend_chart(df: pd.DataFrame, time_period: str = 'daily',
selected_materials: Optional[List[str]] = None, lang: str = 'English'):
df_copy = df.copy()
t = get_translation(lang)
if selected_materials:
df_copy = df_copy[df_copy['material_type'].isin(selected_materials)]
if time_period == 'daily':
grouped = df_copy.groupby(['date', 'material_type'])['weight_kg'].sum().reset_index()
fig = px.line(grouped, x='date', y='weight_kg', color='material_type',
title=t.get('chart_materials_trends', 'Materials Production Trends'),
labels={'weight_kg': t.get('label_weight', 'Weight (kg)'),
'date': t.get('label_date', 'Date'),
'material_type': t.get('label_material', 'Material')})
elif time_period == 'weekly':
df_copy['week'] = df_copy['date'].dt.isocalendar().week
df_copy['year'] = df_copy['date'].dt.year
grouped = df_copy.groupby(['year', 'week', 'material_type'])['weight_kg'].sum().reset_index()
grouped['week_label'] = grouped['year'].astype(str) + '-W' + grouped['week'].astype(str)
fig = px.bar(grouped, x='week_label', y='weight_kg', color='material_type',
title=t.get('chart_materials_trends_weekly', 'Materials Production Trends (Weekly)'),
labels={'weight_kg': t.get('label_weight', 'Weight (kg)'),
'week_label': t.get('label_week', 'Week'),
'material_type': t.get('label_material', 'Material')})
else:
df_copy['month'] = df_copy['date'].dt.to_period('M')
grouped = df_copy.groupby(['month', 'material_type'])['weight_kg'].sum().reset_index()
grouped['month'] = grouped['month'].astype(str)
fig = px.bar(grouped, x='month', y='weight_kg', color='material_type',
title=t.get('chart_materials_trends_monthly', 'Materials Production Trends (Monthly)'),
labels={'weight_kg': t.get('label_weight', 'Weight (kg)'),
'month': t.get('label_month', 'Month'),
'material_type': t.get('label_material', 'Material')})
fig.update_layout(**get_chart_theme()['layout'], height=400)
return fig
def create_shift_trend_chart(df: pd.DataFrame, time_period: str = 'daily', lang: str = 'English'):
theme = get_chart_theme()
t = get_translation(lang)
if time_period == 'daily':
grouped = df.groupby(['date', 'shift'])['weight_kg'].sum().reset_index()
pivot_data = grouped.pivot(index='date', columns='shift', values='weight_kg').fillna(0)
fig = go.Figure()
if 'day' in pivot_data.columns:
fig.add_trace(go.Bar(
x=pivot_data.index,
y=pivot_data['day'],
name=t.get('label_day_shift', 'Day Shift'),
marker_color=DESIGN_SYSTEM['colors']['warning'],
text=pivot_data['day'].round(0),
textposition='inside'
))
if 'night' in pivot_data.columns:
fig.add_trace(go.Bar(
x=pivot_data.index,
y=pivot_data['night'],
name=t.get('label_night_shift', 'Night Shift'),
marker_color=DESIGN_SYSTEM['colors']['primary'],
base=pivot_data['day'] if 'day' in pivot_data.columns else 0,
text=pivot_data['night'].round(0),
textposition='inside'
))
fig.update_layout(
**theme['layout'],
title=t.get('chart_shift_trends', 'Daily Shift Production Trends (Stacked)'),
xaxis_title=t.get('label_date', 'Date'),
yaxis_title=t.get('label_weight', 'Weight (kg)'),
barmode='stack',
height=400,
showlegend=True
)
else:
grouped = df.groupby(['date', 'shift'])['weight_kg'].sum().reset_index()
fig = px.bar(grouped, x='date', y='weight_kg', color='shift',
title=t.get('chart_shift_trends_period', f'{time_period.title()} Shift Production Trends'),
barmode='stack')
fig.update_layout(**theme['layout'], height=400)
return fig