| 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 |