├── tempCodeRunnerFile.py ├── BlinkIT Grocery Data Excel.xlsx ├── README.md ├── blinkit.py └── dashboard.py /tempCodeRunnerFile.py: -------------------------------------------------------------------------------- 1 | pd -------------------------------------------------------------------------------- /BlinkIT Grocery Data Excel.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arj525/BlinkIT-grocery-dashboard/HEAD/BlinkIT Grocery Data Excel.xlsx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BlinkIT-grocery-dashboard 2 | 3 | # 🛒 Blinkit Grocery Data Analysis Dashboard 4 | 5 | An interactive data visualization dashboard built using Python and Dash, inspired by Blinkit's UI. It allows users to explore grocery sales and inventory data from an Excel dataset in a clean and insightful way. 6 | 7 | --- 8 | 9 | ## 📁 Project Structure 10 | 11 | | File | Description | 12 | |------|-------------| 13 | | `BlinkIT Grocery Data Excel.xlsx` | The source dataset containing grocery product sales, inventory, and other details. | 14 | | `blinkit.py` | Python script for loading, cleaning, and preprocessing the dataset using Pandas. | 15 | | `dashboard.py` | Main dashboard application built using Dash and Plotly for interactive visualizations. | 16 | | `tempCodeRunnerFile.py` | Temporary file used during code testing/debugging (can be ignored or deleted). | 17 | 18 | 19 | Dashboard.py 20 | ![Screenshot 2025-04-13 230152](https://github.com/user-attachments/assets/ad2a1bbe-4c8b-46dc-aa33-216958373b35) 21 | 22 | 23 | --- 24 | 25 | ## 📊 Features 26 | 27 | - 📈 Multiple chart types: bar, pie, line, scatter, etc. 28 | - 🧠 Smart data filtering and category analysis 29 | - 🖼️ Blinkit-inspired UI with clean layout and modern visualizations 30 | - 🔄 Real-time interactivity with dropdowns, sliders, and tabs 31 | 32 | --- 33 | 34 | ## 🚀 Getting Started 35 | 36 | ### 🔧 Prerequisites 37 | 38 | Make sure you have the following installed: 39 | 40 | ```bash 41 | pip install pandas dash plotly openpyxl 42 | 43 | 44 | git clone https://github.com/your-username/blinkit-dashboard.git 45 | cd blinkit-dashboard 46 | 47 | 48 | python dashboard.py 49 | http://127.0.0.1:8050/ 50 | -------------------------------------------------------------------------------- /blinkit.py: -------------------------------------------------------------------------------- 1 | # import pandas as pd 2 | # import plotly.express as px 3 | # import plotly.graph_objects as go 4 | # import seaborn as sns 5 | # import matplotlib.pyplot as plt 6 | # import os 7 | 8 | # # Load Excel 9 | # df = pd.read_excel("BlinkIT Grocery Data Excel.xlsx") 10 | 11 | # # Prepare output directory 12 | # output_dir = "all_graphs_output" 13 | # os.makedirs(output_dir, exist_ok=True) 14 | 15 | # # Rename for consistency 16 | # df = df.rename(columns={ 17 | # "Item Type": "Category", 18 | # "Total Sales": "Sales", 19 | # "Rating": "Orders", # Temporary mapping for demo 20 | # "Item Identifier": "Product", 21 | # "Outlet Location Type": "Region" 22 | # }) 23 | 24 | # # Drop NA 25 | # df = df.dropna() 26 | 27 | # # Define color palette 28 | # COLOR_PALETTE = px.colors.qualitative.Set2 29 | 30 | # # 1. Bar Chart – Total Sales per Product Category 31 | # fig = px.bar( 32 | # df.groupby("Category")["Sales"].sum().reset_index(), 33 | # x="Category", y="Sales", title="Total Sales per Product Category", 34 | # color_discrete_sequence=COLOR_PALETTE 35 | # ) 36 | # fig.update_layout( 37 | # xaxis_tickangle=-45, 38 | # title_font=dict(size=20, family="Arial", color="black"), 39 | # xaxis_title="Category", 40 | # yaxis_title="Total Sales", 41 | # paper_bgcolor="#F9F9F9", 42 | # plot_bgcolor="#F9F9F9" 43 | # ) 44 | # fig.write_image(f"{output_dir}/bar_sales_per_category.png") 45 | 46 | # # 2. Pie Chart – Order Share by Category 47 | # fig = px.pie( 48 | # df.groupby("Category")["Orders"].sum().reset_index(), 49 | # names="Category", values="Orders", title="Order Share by Category", 50 | # color_discrete_sequence=COLOR_PALETTE 51 | # ) 52 | # fig.update_layout( 53 | # title_font=dict(size=20, family="Arial", color="black"), 54 | # paper_bgcolor="#F9F9F9" 55 | # ) 56 | # fig.write_image(f"{output_dir}/pie_orders_by_category.png") 57 | 58 | # # 3. Line Chart – Average Sales Over Category (simulated time trend) 59 | # fig = px.line( 60 | # df.groupby("Category")["Sales"].mean().reset_index(), 61 | # x="Category", y="Sales", title="Average Sales by Category", 62 | # color_discrete_sequence=COLOR_PALETTE 63 | # ) 64 | # fig.update_layout( 65 | # title_font=dict(size=20, family="Arial", color="black"), 66 | # xaxis_title="Category", 67 | # yaxis_title="Average Sales", 68 | # paper_bgcolor="#F9F9F9", 69 | # plot_bgcolor="#F9F9F9" 70 | # ) 71 | # fig.write_image(f"{output_dir}/line_sales_category.png") 72 | 73 | # # 4. Scatter Plot – Orders vs. Sales 74 | # fig = px.scatter( 75 | # df, x="Orders", y="Sales", color="Category", 76 | # title="Orders vs. Sales", color_discrete_sequence=COLOR_PALETTE, 77 | # size="Sales", hover_data=["Category"] 78 | # ) 79 | # fig.update_layout( 80 | # title_font=dict(size=20, family="Arial", color="black"), 81 | # xaxis_title="Orders", 82 | # yaxis_title="Sales", 83 | # paper_bgcolor="#F9F9F9", 84 | # plot_bgcolor="#F9F9F9" 85 | # ) 86 | # fig.write_image(f"{output_dir}/scatter_orders_vs_sales.png") 87 | 88 | # # 5. Histogram – Sales per Product 89 | # fig = px.histogram( 90 | # df, x="Sales", nbins=30, title="Distribution of Sales per Product", 91 | # color_discrete_sequence=COLOR_PALETTE 92 | # ) 93 | # fig.update_layout( 94 | # title_font=dict(size=20, family="Arial", color="black"), 95 | # xaxis_title="Sales", 96 | # yaxis_title="Frequency", 97 | # paper_bgcolor="#F9F9F9", 98 | # plot_bgcolor="#F9F9F9" 99 | # ) 100 | # fig.write_image(f"{output_dir}/histogram_sales.png") 101 | 102 | # # 6. Box Plot – Sales by Category 103 | # fig = px.box( 104 | # df, x="Category", y="Sales", title="Sales Distribution by Category", 105 | # color="Category", color_discrete_sequence=COLOR_PALETTE 106 | # ) 107 | # fig.update_layout( 108 | # title_font=dict(size=20, family="Arial", color="black"), 109 | # xaxis_title="Category", 110 | # yaxis_title="Sales", 111 | # paper_bgcolor="#F9F9F9", 112 | # plot_bgcolor="#F9F9F9" 113 | # ) 114 | # fig.write_image(f"{output_dir}/boxplot_sales_category.png") 115 | 116 | # # 7. Stacked Bar – Orders by Region and Category 117 | # pivot_df = df.groupby(["Region", "Category"])["Orders"].sum().reset_index() 118 | # fig = px.bar( 119 | # pivot_df, x="Region", y="Orders", color="Category", 120 | # title="Orders by Region and Category", barmode="stack", 121 | # color_discrete_sequence=COLOR_PALETTE 122 | # ) 123 | # fig.update_layout( 124 | # title_font=dict(size=20, family="Arial", color="black"), 125 | # xaxis_title="Region", 126 | # yaxis_title="Orders", 127 | # paper_bgcolor="#F9F9F9", 128 | # plot_bgcolor="#F9F9F9" 129 | # ) 130 | # fig.write_image(f"{output_dir}/stackedbar_orders_region_category.png") 131 | 132 | # # 8. Heatmap – Correlation 133 | # corr = df[["Sales", "Orders", "Item Weight", "Item Visibility"]].corr() 134 | # sns.heatmap(corr, annot=True, cmap="coolwarm") 135 | # plt.title("Heatmap – Correlation", fontsize=16) 136 | # plt.savefig(f"{output_dir}/heatmap_correlation.png") 137 | # plt.clf() 138 | 139 | # # 9. Donut Chart – Top 5 Best-Selling Products 140 | # top_products = df.groupby("Product")["Sales"].sum().nlargest(5).reset_index() 141 | # fig = px.pie( 142 | # top_products, names="Product", values="Sales", hole=0.4, 143 | # title="Top 5 Best-Selling Products", color_discrete_sequence=COLOR_PALETTE 144 | # ) 145 | # fig.update_layout( 146 | # title_font=dict(size=20, family="Arial", color="black"), 147 | # paper_bgcolor="#F9F9F9" 148 | # ) 149 | # fig.write_image(f"{output_dir}/donut_top5_products.png") 150 | 151 | # # 10. Area Chart – Simulated Time Series using Rating 152 | # fig = px.area( 153 | # df.sort_values("Orders"), x="Orders", y="Sales", 154 | # title="Area Chart – Sales over Orders (Simulated)", 155 | # color_discrete_sequence=COLOR_PALETTE 156 | # ) 157 | # fig.update_layout( 158 | # title_font=dict(size=20, family="Arial", color="black"), 159 | # xaxis_title="Orders", 160 | # yaxis_title="Sales", 161 | # paper_bgcolor="#F9F9F9", 162 | # plot_bgcolor="#F9F9F9" 163 | # ) 164 | # fig.write_image(f"{output_dir}/area_sales_orders.png") 165 | 166 | # print("✅ All graphs have been generated and saved in the 'all_graphs_output' folder!") 167 | import pandas as pd 168 | import plotly.express as px 169 | import plotly.graph_objects as go 170 | import seaborn as sns 171 | import matplotlib.pyplot as plt 172 | import os 173 | 174 | # Load Excel 175 | df = pd.read_excel("BlinkIT Grocery Data Excel.xlsx") 176 | 177 | # Prepare output directory 178 | output_dir = "all_graphs_output" 179 | os.makedirs(output_dir, exist_ok=True) 180 | 181 | # Rename for consistency 182 | df = df.rename(columns={ 183 | "Item Type": "Category", 184 | "Total Sales": "Sales", 185 | "Rating": "Orders", # Temporary mapping for demo 186 | "Item Identifier": "Product", 187 | "Outlet Location Type": "Region" 188 | }) 189 | 190 | # Drop NA 191 | df = df.dropna() 192 | 193 | # Define a dark theme color palette 194 | COLOR_PALETTE = px.colors.qualitative.Dark24 195 | 196 | # 1. Bar Chart – Total Sales per Product Category 197 | fig = px.bar( 198 | df.groupby("Category")["Sales"].sum().reset_index(), 199 | x="Category", y="Sales", title="Total Sales per Product Category", 200 | color_discrete_sequence=COLOR_PALETTE 201 | ) 202 | fig.update_layout( 203 | xaxis_tickangle=-45, 204 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 205 | xaxis_title="Category", 206 | yaxis_title="Total Sales", 207 | paper_bgcolor="#1E1E2F", 208 | plot_bgcolor="#2A2A3D", 209 | font=dict(color="#FFFFFF") 210 | ) 211 | fig.write_image(f"{output_dir}/bar_sales_per_category.png") 212 | 213 | # 2. Pie Chart – Order Share by Category 214 | fig = px.pie( 215 | df.groupby("Category")["Orders"].sum().reset_index(), 216 | names="Category", values="Orders", title="Order Share by Category", 217 | color_discrete_sequence=COLOR_PALETTE 218 | ) 219 | fig.update_layout( 220 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 221 | paper_bgcolor="#1E1E2F", 222 | font=dict(color="#FFFFFF") 223 | ) 224 | fig.write_image(f"{output_dir}/pie_orders_by_category.png") 225 | 226 | # 3. Line Chart – Average Sales Over Category (simulated time trend) 227 | fig = px.line( 228 | df.groupby("Category")["Sales"].mean().reset_index(), 229 | x="Category", y="Sales", title="Average Sales by Category", 230 | color_discrete_sequence=COLOR_PALETTE 231 | ) 232 | fig.update_layout( 233 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 234 | xaxis_title="Category", 235 | yaxis_title="Average Sales", 236 | paper_bgcolor="#1E1E2F", 237 | plot_bgcolor="#2A2A3D", 238 | font=dict(color="#FFFFFF") 239 | ) 240 | fig.write_image(f"{output_dir}/line_sales_category.png") 241 | 242 | # 4. Scatter Plot – Orders vs. Sales 243 | fig = px.scatter( 244 | df, x="Orders", y="Sales", color="Category", 245 | title="Orders vs. Sales", color_discrete_sequence=COLOR_PALETTE, 246 | size="Sales", hover_data=["Category"] 247 | ) 248 | fig.update_layout( 249 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 250 | xaxis_title="Orders", 251 | yaxis_title="Sales", 252 | paper_bgcolor="#1E1E2F", 253 | plot_bgcolor="#2A2A3D", 254 | font=dict(color="#FFFFFF") 255 | ) 256 | fig.write_image(f"{output_dir}/scatter_orders_vs_sales.png") 257 | 258 | # 5. Histogram – Sales per Product 259 | fig = px.histogram( 260 | df, x="Sales", nbins=30, title="Distribution of Sales per Product", 261 | color_discrete_sequence=COLOR_PALETTE 262 | ) 263 | fig.update_layout( 264 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 265 | xaxis_title="Sales", 266 | yaxis_title="Frequency", 267 | paper_bgcolor="#1E1E2F", 268 | plot_bgcolor="#2A2A3D", 269 | font=dict(color="#FFFFFF") 270 | ) 271 | fig.write_image(f"{output_dir}/histogram_sales.png") 272 | 273 | # 6. Box Plot – Sales by Category 274 | fig = px.box( 275 | df, x="Category", y="Sales", title="Sales Distribution by Category", 276 | color="Category", color_discrete_sequence=COLOR_PALETTE 277 | ) 278 | fig.update_layout( 279 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 280 | xaxis_title="Category", 281 | yaxis_title="Sales", 282 | paper_bgcolor="#1E1E2F", 283 | plot_bgcolor="#2A2A3D", 284 | font=dict(color="#FFFFFF") 285 | ) 286 | fig.write_image(f"{output_dir}/boxplot_sales_category.png") 287 | 288 | # 7. Stacked Bar – Orders by Region and Category 289 | pivot_df = df.groupby(["Region", "Category"])["Orders"].sum().reset_index() 290 | fig = px.bar( 291 | pivot_df, x="Region", y="Orders", color="Category", 292 | title="Orders by Region and Category", barmode="stack", 293 | color_discrete_sequence=COLOR_PALETTE 294 | ) 295 | fig.update_layout( 296 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 297 | xaxis_title="Region", 298 | yaxis_title="Orders", 299 | paper_bgcolor="#1E1E2F", 300 | plot_bgcolor="#2A2A3D", 301 | font=dict(color="#FFFFFF") 302 | ) 303 | fig.write_image(f"{output_dir}/stackedbar_orders_region_category.png") 304 | 305 | # 8. Heatmap – Correlation 306 | corr = df[["Sales", "Orders"]].corr() 307 | sns.heatmap(corr, annot=True, cmap="coolwarm") 308 | plt.title("Heatmap – Correlation", fontsize=16, color="#FFFFFF") 309 | plt.savefig(f"{output_dir}/heatmap_correlation.png", facecolor="#1E1E2F") 310 | plt.clf() 311 | 312 | # 9. Donut Chart – Top 5 Best-Selling Products 313 | top_products = df.groupby("Product")["Sales"].sum().nlargest(5).reset_index() 314 | fig = px.pie( 315 | top_products, names="Product", values="Sales", hole=0.4, 316 | title="Top 5 Best-Selling Products", color_discrete_sequence=COLOR_PALETTE 317 | ) 318 | fig.update_layout( 319 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 320 | paper_bgcolor="#1E1E2F", 321 | font=dict(color="#FFFFFF") 322 | ) 323 | fig.write_image(f"{output_dir}/donut_top5_products.png") 324 | 325 | # 10. Area Chart – Simulated Time Series using Rating 326 | fig = px.area( 327 | df.sort_values("Orders"), x="Orders", y="Sales", 328 | title="Area Chart – Sales over Orders (Simulated)", 329 | color_discrete_sequence=COLOR_PALETTE 330 | ) 331 | fig.update_layout( 332 | title_font=dict(size=20, family="Arial", color="#FFFFFF"), 333 | xaxis_title="Orders", 334 | yaxis_title="Sales", 335 | paper_bgcolor="#1E1E2F", 336 | plot_bgcolor="#2A2A3D", 337 | font=dict(color="#FFFFFF") 338 | ) 339 | fig.write_image(f"{output_dir}/area_sales_orders.png") 340 | 341 | print("✅ All graphs have been generated and saved in the 'all_graphs_output' folder!") -------------------------------------------------------------------------------- /dashboard.py: -------------------------------------------------------------------------------- 1 | # import pandas as pd 2 | # import plotly.express as px 3 | # import dash 4 | # from dash import html, dcc, Input, Output 5 | # import dash_bootstrap_components as dbc 6 | 7 | # # Load and clean the data 8 | # df = pd.read_excel("BlinkIT Grocery Data Excel.xlsx") 9 | # df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") 10 | # df = df.rename(columns={ 11 | # 'sales': 'total_sales', 12 | # 'rating': 'avg_ratings', 13 | # 'item_visibility': 'item_visibility', 14 | # 'item_type': 'item_type', 15 | # 'outlet_size': 'outlet_size', 16 | # 'outlet_location_type': 'outlet_location', 17 | # 'outlet_type': 'outlet_type', 18 | # 'outlet_establishment_year': 'year_established', 19 | # 'item_fat_content': 'fat_content' 20 | # }) 21 | 22 | # # Add derived columns 23 | # df['avg_sales'] = df['total_sales'] 24 | # df['no_of_items'] = 1 25 | 26 | # # Initialize the app 27 | # app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) 28 | 29 | # # Helper to create KPI card 30 | # def generate_kpi_card(title, value, color="#ffc107"): 31 | # return dbc.Card([ 32 | # dbc.CardBody([ 33 | # html.H5(title, className="card-title text-muted"), 34 | # html.H3(value, className="card-text") 35 | # ]) 36 | # ], className="m-2 text-center shadow-sm rounded", style={ 37 | # "backgroundColor": "#f9f9f9", "borderLeft": f"6px solid {color}" 38 | # }) 39 | 40 | 41 | # # Layout structure 42 | # app.layout = dbc.Container([ 43 | # dbc.Row([ 44 | # dbc.Col([ 45 | # html.Div([ 46 | # html.H2("blink it", style={"color": "#84C225", "fontWeight": "bold", "fontSize": "40px"}), 47 | # html.H6("India's Last Minute App", className="mb-4 text-muted"), 48 | 49 | # html.Label("Outlet Location Type"), 50 | # dcc.Dropdown(['All'] + sorted(df['outlet_location'].unique()), 'All', id='location-filter'), 51 | 52 | # html.Label("Outlet Size", className="mt-3"), 53 | # dcc.Dropdown(['All'] + sorted(df['outlet_size'].unique()), 'All', id='size-filter'), 54 | 55 | # html.Label("Outlet Type", className="mt-3"), 56 | # dcc.Dropdown(['All'] + sorted(df['outlet_type'].unique()), 'All', id='type-filter'), 57 | 58 | # html.Button("Reset", id='reset-button', style={'marginTop': '20px'}) 59 | # ], style={"backgroundColor": "#ffeb3b", "padding": "20px", "borderRadius": "10px", "height": "100vh"}) 60 | # ], width=2), 61 | 62 | # dbc.Col([ 63 | # # KPI Cards 64 | # dbc.Row([ 65 | # dbc.Col(generate_kpi_card("Total Sales", f"${df['total_sales'].sum() / 1e6:.2f}M"), width=3), 66 | # dbc.Col(generate_kpi_card("Avg Sales", f"${df['avg_sales'].mean():.0f}"), width=3), 67 | # dbc.Col(generate_kpi_card("No. of Items", f"{df['no_of_items'].sum()}"), width=3), 68 | # dbc.Col(generate_kpi_card("Avg Ratings", f"{df['avg_ratings'].mean():.1f}"), width=3), 69 | # ], className="mb-4"), 70 | 71 | # # Tabs for dynamic bar chart 72 | # dbc.Row([ 73 | # dcc.Tabs(id="tabs", value='avg_sales', children=[ 74 | # dcc.Tab(label='Avg Sales', value='avg_sales'), 75 | # dcc.Tab(label='Avg Ratings', value='avg_ratings'), 76 | # dcc.Tab(label='No. of Items', value='no_of_items'), 77 | # dcc.Tab(label='Total Sales', value='total_sales'), 78 | # ]), 79 | # dcc.Graph(id='bar-chart'), 80 | # ]), 81 | 82 | 83 | 84 | # # Charts Section 85 | # dbc.Row([ 86 | # dbc.Col(dcc.Graph(id='fat-pie'), width=6), 87 | # dbc.Col(dcc.Graph(id='size-pie'), width=6), 88 | # ]), 89 | 90 | # dbc.Row([ 91 | # dbc.Col(dcc.Graph(id='sales-by-item'), width=6), 92 | # dbc.Col(dcc.Graph(id='establishment-trend'), width=6), 93 | # ]), 94 | 95 | # dbc.Row([ 96 | # dbc.Col(dcc.Graph(id='location-bar'), width=6), 97 | # dbc.Col(dcc.Graph(id='outlet-type-table'), width=6), 98 | # ]) 99 | # ], width=10) 100 | # ]) 101 | # ], fluid=True) 102 | 103 | # # Callback to update all charts 104 | # @app.callback( 105 | # [Output('fat-pie', 'figure'), 106 | # Output('size-pie', 'figure'), 107 | # Output('sales-by-item', 'figure'), 108 | # Output('establishment-trend', 'figure'), 109 | # Output('location-bar', 'figure'), 110 | # Output('outlet-type-table', 'figure'), 111 | # Output('bar-chart', 'figure')], 112 | # [Input('location-filter', 'value'), 113 | # Input('size-filter', 'value'), 114 | # Input('type-filter', 'value'), 115 | # Input('tabs', 'value')] 116 | # ) 117 | # def update_charts(location, size, otype, tab): 118 | # dff = df.copy() 119 | # if location != 'All': 120 | # dff = dff[dff['outlet_location'] == location] 121 | # if size != 'All': 122 | # dff = dff[dff['outlet_size'] == size] 123 | # if otype != 'All': 124 | # dff = dff[dff['outlet_type'] == otype] 125 | 126 | # # Pie Charts 127 | # fat_fig = px.pie(dff, values='total_sales', names='fat_content', hole=0.4, title="Fat Content") 128 | # size_fig = px.pie(dff, values='total_sales', names='outlet_size', hole=0.4, title="Outlet Size") 129 | 130 | # # Bar Charts 131 | # item_fig = px.bar(dff.groupby('item_type')['total_sales'].sum().nlargest(10).reset_index(), 132 | # x='total_sales', y='item_type', orientation='h', title="Top Item Types") 133 | 134 | # est_fig = px.line(dff.groupby('year_established')['total_sales'].sum().reset_index(), 135 | # x='year_established', y='total_sales', title="Outlet Establishment Trend") 136 | 137 | # loc_fig = px.bar(dff.groupby('outlet_location')['total_sales'].sum().reset_index(), 138 | # x='outlet_location', y='total_sales', title="Sales by Location") 139 | 140 | # outlet_summary = dff.groupby('outlet_type').agg({ 141 | # 'total_sales': 'sum', 142 | # 'no_of_items': 'sum', 143 | # 'avg_sales': 'mean', 144 | # 'avg_ratings': 'mean', 145 | # 'item_visibility': 'mean' 146 | # }).reset_index() 147 | 148 | # outlet_fig = px.bar(outlet_summary, x='total_sales', y='outlet_type', orientation='h', 149 | # color='avg_ratings', title="Outlet Type Performance") 150 | 151 | # # Tab-based Bar Chart 152 | # y_col = tab if tab in dff.columns else 'total_sales' 153 | # color = '#e53935' if tab in ['avg_sales', 'avg_ratings', 'no_of_items'] else '#90caf9' 154 | # bar_fig = px.bar(dff, x='outlet_type', y=y_col, color_discrete_sequence=[color], title=f"{tab.replace('_', ' ').title()} by Outlet Type") 155 | 156 | # return fat_fig, size_fig, item_fig, est_fig, loc_fig, outlet_fig, bar_fig 157 | 158 | # # Run server 159 | # if __name__ == '__main__': 160 | # # app.run_server(debug=True) 161 | # app.run(debug=True) 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | # import pandas as pd 185 | # import plotly.express as px 186 | # import dash 187 | # from dash import html, dcc, Input, Output 188 | # import dash_bootstrap_components as dbc 189 | # import plotly.graph_objects as go 190 | 191 | # # Load and clean the data 192 | # df = pd.read_excel("BlinkIT Grocery Data Excel.xlsx") 193 | # df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") 194 | # df = df.rename(columns={ 195 | # 'sales': 'total_sales', 196 | # 'rating': 'avg_ratings', 197 | # 'item_visibility': 'item_visibility', 198 | # 'item_type': 'item_type', 199 | # 'outlet_size': 'outlet_size', 200 | # 'outlet_location_type': 'outlet_location', 201 | # 'outlet_type': 'outlet_type', 202 | # 'outlet_establishment_year': 'year_established', 203 | # 'item_fat_content': 'fat_content' 204 | # }) 205 | 206 | # # Add derived columns 207 | # df['avg_sales'] = df['total_sales'] 208 | # df['no_of_items'] = 1 209 | 210 | # # Initialize the app with a modern theme (LUX for a clean, professional look) 211 | # app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LUX, "https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap"]) 212 | 213 | # # Define custom color palette 214 | # COLORS = { 215 | # 'primary': '#84C225', # BlinkIT Green 216 | # 'secondary': '#FFEB3B', # BlinkIT Yellow 217 | # 'accent1': '#26A69A', # Teal 218 | # 'accent2': '#FF7043', # Coral 219 | # 'background': '#F5F7FA', # Light Gray 220 | # 'text': '#2D3748', # Dark Gray 221 | # } 222 | 223 | # # Helper to create KPI card with icons and animations 224 | # def generate_kpi_card(title, value, color=COLORS['accent1'], icon="fas fa-dollar-sign"): 225 | # return dbc.Card( 226 | # [ 227 | # dbc.CardBody( 228 | # [ 229 | # html.Div( 230 | # [ 231 | # html.I(className=icon, style={"fontSize": "24px", "color": color}), 232 | # html.H5(title, className="card-title text-muted mt-2"), 233 | # html.H3(value, className="card-text", style={"color": COLORS['text'], "fontWeight": "600"}), 234 | # ], 235 | # className="d-flex align-items-center justify-content-center" 236 | # ) 237 | # ], 238 | # style={"transition": "transform 0.3s ease-in-out"} 239 | # ) 240 | # ], 241 | # className="m-2 text-center shadow-lg rounded-lg", 242 | # style={ 243 | # "background": f"linear-gradient(135deg, {COLORS['background']} 0%, #FFFFFF 100%)", 244 | # "borderLeft": f"6px solid {color}", 245 | # ":hover": {"transform": "scale(1.05)"} 246 | # } 247 | # ) 248 | 249 | # # Layout structure with enhanced styling 250 | # app.layout = dbc.Container( 251 | # [ 252 | # # Header 253 | # html.Div( 254 | # [ 255 | # html.H1( 256 | # "BlinkIT Dashboard", 257 | # style={ 258 | # "color": COLORS['primary'], 259 | # "fontWeight": "600", 260 | # "fontSize": "48px", 261 | # "textAlign": "center", 262 | # "marginBottom": "10px", 263 | # "fontFamily": "'Poppins', sans-serif" 264 | # } 265 | # ), 266 | # html.H6( 267 | # "India's Last Minute App - Powered by xAI", 268 | # style={ 269 | # "color": COLORS['text'], 270 | # "textAlign": "center", 271 | # "marginBottom": "30px", 272 | # "fontFamily": "'Poppins', sans-serif" 273 | # } 274 | # ), 275 | # ] 276 | # ), 277 | 278 | # dbc.Row( 279 | # [ 280 | # # Sidebar 281 | # dbc.Col( 282 | # [ 283 | # html.Div( 284 | # [ 285 | # html.Label("Outlet Location Type", style={"fontWeight": "500", "color": COLORS['text']}), 286 | # dcc.Dropdown( 287 | # ['All'] + sorted(df['outlet_location'].unique()), 288 | # 'All', 289 | # id='location-filter', 290 | # style={ 291 | # "borderRadius": "8px", 292 | # "border": f"1px solid {COLORS['primary']}", 293 | # "fontFamily": "'Poppins', sans-serif" 294 | # } 295 | # ), 296 | 297 | # html.Label("Outlet Size", style={"fontWeight": "500", "color": COLORS['text'], "marginTop": "20px"}), 298 | # dcc.Dropdown( 299 | # ['All'] + sorted(df['outlet_size'].unique()), 300 | # 'All', 301 | # id='size-filter', 302 | # style={ 303 | # "borderRadius": "8px", 304 | # "border": f"1px solid {COLORS['primary']}", 305 | # "fontFamily": "'Poppins', sans-serif" 306 | # } 307 | # ), 308 | 309 | # html.Label("Outlet Type", style={"fontWeight": "500", "color": COLORS['text'], "marginTop": "20px"}), 310 | # dcc.Dropdown( 311 | # ['All'] + sorted(df['outlet_type'].unique()), 312 | # 'All', 313 | # id='type-filter', 314 | # style={ 315 | # "borderRadius": "8px", 316 | # "border": f"1px solid {COLORS['primary']}", 317 | # "fontFamily": "'Poppins', sans-serif" 318 | # } 319 | # ), 320 | 321 | # html.Button( 322 | # "Reset Filters", 323 | # id='reset-button', 324 | # className="btn btn-outline-primary mt-4 w-100", 325 | # style={ 326 | # "borderRadius": "8px", 327 | # "border": f"2px solid {COLORS['accent2']}", 328 | # "color": COLORS['accent2'], 329 | # "fontFamily": "'Poppins', sans-serif", 330 | # "transition": "all 0.3s ease-in-out", 331 | # ":hover": {"backgroundColor": COLORS['accent2'], "color": "#FFFFFF"} 332 | # } 333 | # ), 334 | # ], 335 | # style={ 336 | # "background": f"linear-gradient(180deg, {COLORS['secondary']} 0%, {COLORS['primary']} 100%)", 337 | # "padding": "30px", 338 | # "borderRadius": "15px", 339 | # "boxShadow": "0 4px 15px rgba(0,0,0,0.1)", 340 | # "position": "sticky", 341 | # "top": "20px", 342 | # "height": "fit-content" 343 | # } 344 | # ) 345 | # ], 346 | # width=2, 347 | # style={"padding": "20px"} 348 | # ), 349 | 350 | # # Main Content 351 | # dbc.Col( 352 | # [ 353 | # # KPI Cards 354 | # dbc.Row( 355 | # [ 356 | # dbc.Col( 357 | # generate_kpi_card("Total Sales", f"${df['total_sales'].sum() / 1e6:.2f}M", COLORS['primary'], "fas fa-dollar-sign"), 358 | # width=3 359 | # ), 360 | # dbc.Col( 361 | # generate_kpi_card("Avg Sales", f"${df['avg_sales'].mean():.0f}", COLORS['accent1'], "fas fa-chart-line"), 362 | # width=3 363 | # ), 364 | # dbc.Col( 365 | # generate_kpi_card("No. of Items", f"{df['no_of_items'].sum()}", COLORS['accent2'], "fas fa-boxes"), 366 | # width=3 367 | # ), 368 | # dbc.Col( 369 | # generate_kpi_card("Avg Ratings", f"{df['avg_ratings'].mean():.1f}", COLORS['secondary'], "fas fa-star"), 370 | # width=3 371 | # ), 372 | # ], 373 | # className="mb-4" 374 | # ), 375 | 376 | # # Tabs for dynamic bar chart 377 | # dbc.Row( 378 | # [ 379 | # dcc.Tabs( 380 | # id="tabs", 381 | # value='avg_sales', 382 | # children=[ 383 | # dcc.Tab( 384 | # label='Avg Sales', 385 | # value='avg_sales', 386 | # style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 387 | # selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 388 | # ), 389 | # dcc.Tab( 390 | # label='Avg Ratings', 391 | # value='avg_ratings', 392 | # style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 393 | # selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 394 | # ), 395 | # dcc.Tab( 396 | # label='No. of Items', 397 | # value='no_of_items', 398 | # style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 399 | # selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 400 | # ), 401 | # dcc.Tab( 402 | # label='Total Sales', 403 | # value='total_sales', 404 | # style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 405 | # selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 406 | # ), 407 | # ], 408 | # style={"fontFamily": "'Poppins', sans-serif"} 409 | # ), 410 | # dcc.Graph(id='bar-chart', style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"}), 411 | # ], 412 | # className="mb-4" 413 | # ), 414 | 415 | # # Charts Section 416 | # dbc.Row( 417 | # [ 418 | # dbc.Col( 419 | # dcc.Graph(id='fat-pie'), 420 | # width=6, 421 | # style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"} 422 | # ), 423 | # dbc.Col( 424 | # dcc.Graph(id='size-pie'), 425 | # width=6, 426 | # style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"} 427 | # ), 428 | # ], 429 | # className="mb-4" 430 | # ), 431 | 432 | # dbc.Row( 433 | # [ 434 | # dbc.Col( 435 | # dcc.Graph(id='sales-by-item'), 436 | # width=6, 437 | # style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"} 438 | # ), 439 | # dbc.Col( 440 | # dcc.Graph(id='establishment-trend'), 441 | # width=6, 442 | # style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"} 443 | # ), 444 | # ], 445 | # className="mb-4" 446 | # ), 447 | 448 | # dbc.Row( 449 | # [ 450 | # dbc.Col( 451 | # dcc.Graph(id='location-bar'), 452 | # width=6, 453 | # style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"} 454 | # ), 455 | # dbc.Col( 456 | # dcc.Graph(id='outlet-type-table'), 457 | # width=6, 458 | # style={"backgroundColor": "#FFFFFF", "borderRadius": "10px", "padding": "10px"} 459 | # ), 460 | # ] 461 | # ) 462 | # ], 463 | # width=10 464 | # ) 465 | # ] 466 | # ) 467 | # ], 468 | # fluid=True, 469 | # style={ 470 | # "backgroundColor": COLORS['background'], 471 | # "padding": "40px", 472 | # "fontFamily": "'Poppins', sans-serif" 473 | # } 474 | # ) 475 | 476 | # # Callback to reset filters 477 | # @app.callback( 478 | # [Output('location-filter', 'value'), 479 | # Output('size-filter', 'value'), 480 | # Output('type-filter', 'value')], 481 | # Input('reset-button', 'n_clicks') 482 | # ) 483 | # def reset_filters(n_clicks): 484 | # return 'All', 'All', 'All' 485 | 486 | # # Callback to update all charts 487 | # @app.callback( 488 | # [Output('fat-pie', 'figure'), 489 | # Output('size-pie', 'figure'), 490 | # Output('sales-by-item', 'figure'), 491 | # Output('establishment-trend', 'figure'), 492 | # Output('location-bar', 'figure'), 493 | # Output('outlet-type-table', 'figure'), 494 | # Output('bar-chart', 'figure')], 495 | # [Input('location-filter', 'value'), 496 | # Input('size-filter', 'value'), 497 | # Input('type-filter', 'value'), 498 | # Input('tabs', 'value')] 499 | # ) 500 | # def update_charts(location, size, otype, tab): 501 | # dff = df.copy() 502 | # if location != 'All': 503 | # dff = dff[dff['outlet_location'] == location] 504 | # if size != 'All': 505 | # dff = dff[dff['outlet_size'] == size] 506 | # if otype != 'All': 507 | # dff = dff[dff['outlet_type'] == otype] 508 | 509 | # # Define custom color sequence 510 | # color_sequence = [COLORS['primary'], COLORS['secondary'], COLORS['accent1'], COLORS['accent2']] 511 | 512 | # # Pie Charts 513 | # fat_fig = px.pie( 514 | # dff, 515 | # values='total_sales', 516 | # names='fat_content', 517 | # hole=0.5, 518 | # title="Sales by Fat Content", 519 | # color_discrete_sequence=color_sequence 520 | # ).update_traces( 521 | # textinfo='percent+label', 522 | # hovertemplate='%{label}: %{value:,.0f} (%{percent})', 523 | # marker=dict(line=dict(color='#FFFFFF', width=2)) 524 | # ).update_layout( 525 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 526 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 527 | # paper_bgcolor='rgba(0,0,0,0)', 528 | # plot_bgcolor='rgba(0,0,0,0)', 529 | # showlegend=True, 530 | # margin=dict(t=50, b=50, l=50, r=50) 531 | # ) 532 | 533 | # size_fig = px.pie( 534 | # dff, 535 | # values='total_sales', 536 | # names='outlet_size', 537 | # hole=0.5, 538 | # title="Sales by Outlet Size", 539 | # color_discrete_sequence=color_sequence 540 | # ).update_traces( 541 | # textinfo='percent+label', 542 | # hovertemplate='%{label}: %{value:,.0f} (%{percent})', 543 | # marker=dict(line=dict(color='#FFFFFF', width=2)) 544 | # ).update_layout( 545 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 546 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 547 | # paper_bgcolor='rgba(0,0,0,0)', 548 | # plot_bgcolor='rgba(0,0,0,0)', 549 | # showlegend=True, 550 | # margin=dict(t=50, b=50, l=50, r=50) 551 | # ) 552 | 553 | # # Bar Charts 554 | # item_fig = px.bar( 555 | # dff.groupby('item_type')['total_sales'].sum().nlargest(10).reset_index(), 556 | # x='total_sales', 557 | # y='item_type', 558 | # orientation='h', 559 | # title="Top 10 Item Types by Sales", 560 | # color_discrete_sequence=[COLORS['accent1']] 561 | # ).update_traces( 562 | # hovertemplate='%{y}: %{x:,.0f}', 563 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 564 | # ).update_layout( 565 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 566 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 567 | # xaxis_title="Total Sales", 568 | # yaxis_title="Item Type", 569 | # paper_bgcolor='rgba(0,0,0,0)', 570 | # plot_bgcolor='rgba(0,0,0,0)', 571 | # margin=dict(t=50, b=50, l=50, r=50) 572 | # ) 573 | 574 | # est_fig = px.line( 575 | # dff.groupby('year_established')['total_sales'].sum().reset_index(), 576 | # x='year_established', 577 | # y='total_sales', 578 | # title="Sales Trend by Establishment Year", 579 | # color_discrete_sequence=[COLORS['primary']], 580 | # markers=True 581 | # ).update_traces( 582 | # hovertemplate='Year: %{x}
Sales: %{y:,.0f}', 583 | # line=dict(width=3), 584 | # marker=dict(size=8) 585 | # ).update_layout( 586 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 587 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 588 | # xaxis_title="Year Established", 589 | # yaxis_title="Total Sales", 590 | # paper_bgcolor='rgba(0,0,0,0)', 591 | # plot_bgcolor='rgba(0,0,0,0)', 592 | # margin=dict(t=50, b=50, l=50, r=50) 593 | # ) 594 | 595 | # loc_fig = px.bar( 596 | # dff.groupby('outlet_location')['total_sales'].sum().reset_index(), 597 | # x='outlet_location', 598 | # y='total_sales', 599 | # title="Sales by Outlet Location", 600 | # color_discrete_sequence=[COLORS['accent2']] 601 | # ).update_traces( 602 | # hovertemplate='%{x}: %{y:,.0f}', 603 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 604 | # ).update_layout( 605 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 606 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 607 | # xaxis_title="Outlet Location", 608 | # yaxis_title="Total Sales", 609 | # paper_bgcolor='rgba(0,0,0,0)', 610 | # plot_bgcolor='rgba(0,0,0,0)', 611 | # margin=dict(t=50, b=50, l=50, r=50) 612 | # ) 613 | 614 | # outlet_summary = dff.groupby('outlet_type').agg({ 615 | # 'total_sales': 'sum', 616 | # 'no_of_items': 'sum', 617 | # 'avg_sales': 'mean', 618 | # 'avg_ratings': 'mean', 619 | # 'item_visibility': 'mean' 620 | # }).reset_index() 621 | 622 | # outlet_fig = px.bar( 623 | # outlet_summary, 624 | # x='total_sales', 625 | # y='outlet_type', 626 | # orientation='h', 627 | # title="Outlet Type Performance", 628 | # color='avg_ratings', 629 | # color_continuous_scale=[COLORS['secondary'], COLORS['primary']] 630 | # ).update_traces( 631 | # hovertemplate='%{y}: Sales=%{x:,.0f}
Avg Rating=%{marker.color:.1f}', 632 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 633 | # ).update_layout( 634 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 635 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 636 | # xaxis_title="Total Sales", 637 | # yaxis_title="Outlet Type", 638 | # coloraxis_colorbar_title="Avg Ratings", 639 | # paper_bgcolor='rgba(0,0,0,0)', 640 | # plot_bgcolor='rgba(0,0,0,0)', 641 | # margin=dict(t=50, b=50, l=50, r=50) 642 | # ) 643 | 644 | # # Tab-based Bar Chart 645 | # y_col = tab if tab in dff.columns else 'total_sales' 646 | # color = COLORS['accent1'] if tab in ['avg_sales', 'avg_ratings', 'no_of_items'] else COLORS['primary'] 647 | # bar_fig = px.bar( 648 | # dff, 649 | # x='outlet_type', 650 | # y=y_col, 651 | # title=f"{tab.replace('_', ' ').title()} by Outlet Type", 652 | # color_discrete_sequence=[color] 653 | # ).update_traces( 654 | # hovertemplate='%{x}: %{y:,.2f}', 655 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 656 | # ).update_layout( 657 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 658 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 659 | # xaxis_title="Outlet Type", 660 | # yaxis_title=tab.replace('_', ' ').title(), 661 | # paper_bgcolor='rgba(0,0,0,0)', 662 | # plot_bgcolor='rgba(0,0,0,0)', 663 | # margin=dict(t=50, b=50, l=50, r=50) 664 | # ) 665 | 666 | # return fat_fig, size_fig, item_fig, est_fig, loc_fig, outlet_fig, bar_fig 667 | 668 | # # Run server 669 | # if __name__ == '__main__': 670 | # app.run(debug=True) 671 | # @app.callback( 672 | # [Output('fat-pie', 'figure'), 673 | # Output('size-pie', 'figure'), 674 | # Output('sales-by-item', 'figure'), 675 | # Output('establishment-trend', 'figure'), 676 | # Output('location-bar', 'figure'), 677 | # Output('outlet-type-table', 'figure'), 678 | # Output('bar-chart', 'figure')], 679 | # [Input('location-filter', 'value'), 680 | # Input('size-filter', 'value'), 681 | # Input('type-filter', 'value'), 682 | # Input('tabs', 'value')] 683 | # ) 684 | # def update_charts(location, size, otype, tab): 685 | # dff = df.copy() 686 | # if location != 'All': 687 | # dff = dff[dff['outlet_location'] == location] 688 | # if size != 'All': 689 | # dff = dff[dff['outlet_size'] == size] 690 | # if otype != 'All': 691 | # dff = dff[dff['outlet_type'] == otype] 692 | 693 | # # Handle empty dataframe 694 | # if dff.empty: 695 | # empty_fig = go.Figure().update_layout( 696 | # title="No Data Available", 697 | # annotations=[dict(text="No data matches the selected filters.", x=0.5, y=0.5, showarrow=False)], 698 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 699 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 700 | # paper_bgcolor='rgba(0,0,0,0)', 701 | # plot_bgcolor='rgba(0,0,0,0)' 702 | # ) 703 | # return (empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig) 704 | 705 | # # Define custom color sequence 706 | # color_sequence = [COLORS['primary'], COLORS['secondary'], COLORS['accent1'], COLORS['accent2']] 707 | 708 | # # Pie Charts (unchanged) 709 | # fat_fig = px.pie( 710 | # dff, 711 | # values='total_sales', 712 | # names='fat_content', 713 | # hole=0.5, 714 | # title="Sales by Fat Content", 715 | # color_discrete_sequence=color_sequence 716 | # ).update_traces( 717 | # textinfo='percent+label', 718 | # hovertemplate='%{label}: %{value:,.0f} (%{percent})', 719 | # marker=dict(line=dict(color='#FFFFFF', width=2)) 720 | # ).update_layout( 721 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 722 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 723 | # paper_bgcolor='rgba(0,0,0,0)', 724 | # plot_bgcolor='rgba(0,0,0,0)', 725 | # showlegend=True, 726 | # margin=dict(t=50, b=50, l=50, r=50) 727 | # ) 728 | 729 | # size_fig = px.pie( 730 | # dff, 731 | # values='total_sales', 732 | # names='outlet_size', 733 | # hole=0.5, 734 | # title="Sales by Outlet Size", 735 | # color_discrete_sequence=color_sequence 736 | # ).update_traces( 737 | # textinfo='percent+label', 738 | # hovertemplate='%{label}: %{value:,.0f} (%{percent})', 739 | # marker=dict(line=dict(color='#FFFFFF', width=2)) 740 | # ).update_layout( 741 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 742 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 743 | # paper_bgcolor='rgba(0,0,0,0)', 744 | # plot_bgcolor='rgba(0,0,0,0)', 745 | # showlegend=True, 746 | # margin=dict(t=50, b=50, l=50, r=50) 747 | # ) 748 | 749 | # # Other charts (unchanged for brevity) 750 | # item_fig = px.bar( 751 | # dff.groupby('item_type')['total_sales'].sum().nlargest(10).reset_index(), 752 | # x='total_sales', 753 | # y='item_type', 754 | # orientation='h', 755 | # title="Top 10 Item Types by Sales", 756 | # color_discrete_sequence=[COLORS['accent1']] 757 | # ).update_traces( 758 | # hovertemplate='%{y}: %{x:,.0f}', 759 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 760 | # ).update_layout( 761 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 762 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 763 | # xaxis_title="Total Sales", 764 | # yaxis_title="Item Type", 765 | # paper_bgcolor='rgba(0,0,0,0)', 766 | # plot_bgcolor='rgba(0,0,0,0)', 767 | # margin=dict(t=50, b=50, l=50, r=50) 768 | # ) 769 | 770 | # est_fig = px.line( 771 | # dff.groupby('year_established')['total_sales'].sum().reset_index(), 772 | # x='year_established', 773 | # y='total_sales', 774 | # title="Sales Trend by Establishment Year", 775 | # color_discrete_sequence=[COLORS['primary']], 776 | # markers=True 777 | # ).update_traces( 778 | # hovertemplate='Year: %{x}
Sales: %{y:,.0f}', 779 | # line=dict(width=3), 780 | # marker=dict(size=8) 781 | # ).update_layout( 782 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 783 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 784 | # xaxis_title="Year Established", 785 | # yaxis_title="Total Sales", 786 | # paper_bgcolor='rgba(0,0,0,0)', 787 | # plot_bgcolor='rgba(0,0,0,0)', 788 | # margin=dict(t=50, b=50, l=50, r=50) 789 | # ) 790 | 791 | # loc_fig = px.bar( 792 | # dff.groupby('outlet_location')['total_sales'].sum().reset_index(), 793 | # x='outlet_location', 794 | # y='total_sales', 795 | # title="Sales by Outlet Location", 796 | # color_discrete_sequence=[COLORS['accent2']] 797 | # ).update_traces( 798 | # hovertemplate='%{x}: %{y:,.0f}', 799 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 800 | # ).update_layout( 801 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 802 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 803 | # xaxis_title="Outlet Location", 804 | # yaxis_title="Total Sales", 805 | # paper_bgcolor='rgba(0,0,0,0)', 806 | # plot_bgcolor='rgba(0,0,0,0)', 807 | # margin=dict(t=50, b=50, l=50, r=50) 808 | # ) 809 | 810 | # outlet_summary = dff.groupby('outlet_type').agg({ 811 | # 'total_sales': 'sum', 812 | # 'no_of_items': 'sum', 813 | # 'avg_sales': 'mean', 814 | # 'avg_ratings': 'mean', 815 | # 'item_visibility': 'mean' 816 | # }).reset_index() 817 | 818 | # outlet_fig = px.bar( 819 | # outlet_summary, 820 | # x='total_sales', 821 | # y='outlet_type', 822 | # orientation='h', 823 | # title="Outlet Type Performance", 824 | # color='avg_ratings', 825 | # color_continuous_scale=[COLORS['secondary'], COLORS['primary']] 826 | # ).update_traces( 827 | # hovertemplate='%{y}: Sales=%{x:,.0f}
Avg Rating=%{marker.color:.1f}', 828 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 829 | # ).update_layout( 830 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 831 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 832 | # xaxis_title="Total Sales", 833 | # yaxis_title="Outlet Type", 834 | # coloraxis_colorbar_title="Avg Ratings", 835 | # paper_bgcolor='rgba(0,0,0,0)', 836 | # plot_bgcolor='rgba(0,0,0,0)', 837 | # margin=dict(t=50, b=50, l=50, r=50) 838 | # ) 839 | 840 | # # Updated Bar Chart Logic 841 | # y_col = tab if tab in dff.columns else 'total_sales' 842 | # color = COLORS['accent1'] if tab in ['avg_sales', 'avg_ratings', 'no_of_items'] else COLORS['primary'] 843 | 844 | # # Aggregate data for bar chart to avoid rendering issues 845 | # agg_dict = { 846 | # 'total_sales': 'sum', 847 | # 'avg_sales': 'mean', 848 | # 'avg_ratings': 'mean', 849 | # 'no_of_items': 'sum' 850 | # } 851 | # bar_data = dff.groupby('outlet_type')[y_col].agg(agg_dict.get(y_col, 'sum')).reset_index() 852 | 853 | # bar_fig = px.bar( 854 | # bar_data, 855 | # x='outlet_type', 856 | # y=y_col, 857 | # title=f"{y_col.replace('_', ' ').title()} by Outlet Type", 858 | # color_discrete_sequence=[color] 859 | # ).update_traces( 860 | # hovertemplate='%{x}: %{y:,.2f}', 861 | # marker=dict(line=dict(color='#FFFFFF', width=1)) 862 | # ).update_layout( 863 | # title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 864 | # font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 865 | # xaxis_title="Outlet Type", 866 | # yaxis_title=y_col.replace('_', ' ').title(), 867 | # paper_bgcolor='rgba(0,0,0,0)', 868 | # plot_bgcolor='rgba(0,0,0,0)', 869 | # margin=dict(t=50, b=50, l=50, r=50), 870 | # height=400, # Explicitly set height for better visibility 871 | # xaxis_tickangle=45 # Rotate x-axis labels for readability 872 | # ) 873 | 874 | # return fat_fig, size_fig, item_fig, est_fig, loc_fig, outlet_fig, bar_fig 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | import pandas as pd 883 | import plotly.express as px 884 | import dash 885 | from dash import html, dcc, Input, Output 886 | import dash_bootstrap_components as dbc 887 | import plotly.graph_objects as go 888 | 889 | # Load and clean the data (unchanged) 890 | df = pd.read_excel("BlinkIT Grocery Data Excel.xlsx") 891 | df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") 892 | df = df.rename(columns={ 893 | 'sales': 'total_sales', 894 | 'rating': 'avg_ratings', 895 | 'item_visibility': 'item_visibility', 896 | 'item_type': 'item_type', 897 | 'outlet_size': 'outlet_size', 898 | 'outlet_location_type': 'outlet_location', 899 | 'outlet_type': 'outlet_type', 900 | 'outlet_establishment_year': 'year_established', 901 | 'item_fat_content': 'fat_content' 902 | }) 903 | 904 | df['avg_sales'] = df['total_sales'] 905 | df['no_of_items'] = 1 906 | 907 | # Initialize the app 908 | app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LUX, "https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap"]) 909 | 910 | # Define custom color palette (unchanged) 911 | COLORS = { 912 | 'primary': '#84C225', # BlinkIT Green 913 | 'secondary': '#FFEB3B', # BlinkIT Yellow 914 | 'accent1': '#26A69A', # Teal 915 | 'accent2': '#FF7043', # Coral 916 | 'background': '#F5F7FA', # Light Gray 917 | 'text': '#2D3748', # Dark Gray 918 | } 919 | 920 | # Helper to create KPI card 921 | def generate_kpi_card(title, value, color=COLORS['accent1'], icon="fas fa-dollar-sign"): 922 | return dbc.Card( 923 | [ 924 | dbc.CardBody( 925 | [ 926 | html.Div( 927 | [ 928 | html.I(className=icon, style={"fontSize": "24px", "color": color}), 929 | html.H5(title, className="card-title text-muted mt-2"), 930 | html.H3(value, className="card-text", style={"color": COLORS['text'], "fontWeight": "600"}), 931 | ], 932 | className="d-flex align-items-center justify-content-center" 933 | ) 934 | ], 935 | style={"transition": "transform 0.3s ease-in-out, background 0.3s ease-in-out"} 936 | ) 937 | ], 938 | className="m-2 text-center shadow-lg rounded-lg", 939 | style={ 940 | "background": f"linear-gradient(145deg, {COLORS['background']} 30%, #E8ECEF 100%)", # Softer gradient 941 | "borderLeft": f"6px solid {color}", 942 | ":hover": { 943 | "transform": "scale(1.05)", 944 | "background": f"linear-gradient(145deg, {color}20 30%, #FFFFFF 100%)" # Dynamic hover 945 | } 946 | } 947 | ) 948 | 949 | # Layout structure 950 | app.layout = dbc.Container( 951 | [ 952 | # Header (unchanged) 953 | html.Div( 954 | [ 955 | html.H1( 956 | "BlinkIT Dashboard", 957 | style={ 958 | "color": COLORS['primary'], 959 | "fontWeight": "600", 960 | "fontSize": "48px", 961 | "textAlign": "center", 962 | "marginBottom": "10px", 963 | "fontFamily": "'Poppins', sans-serif" 964 | } 965 | ), 966 | html.H6( 967 | "India's Last Minute App - Powered by xAI", 968 | style={ 969 | "color": COLORS['text'], 970 | "textAlign": "center", 971 | "marginBottom": "30px", 972 | "fontFamily": "'Poppins', sans-serif" 973 | } 974 | ), 975 | ] 976 | ), 977 | 978 | dbc.Row( 979 | [ 980 | # Sidebar 981 | dbc.Col( 982 | [ 983 | html.Div( 984 | [ 985 | html.Label("Outlet Location Type", style={"fontWeight": "500", "color": COLORS['text']}), 986 | dcc.Dropdown( 987 | ['All'] + sorted(df['outlet_location'].unique()), 988 | 'All', 989 | id='location-filter', 990 | style={ 991 | "borderRadius": "8px", 992 | "border": f"1px solid {COLORS['primary']}", 993 | "fontFamily": "'Poppins', sans-serif" 994 | } 995 | ), 996 | 997 | html.Label("Outlet Size", style={"fontWeight": "500", "color": COLORS['text'], "marginTop": "20px"}), 998 | dcc.Dropdown( 999 | ['All'] + sorted(df['outlet_size'].unique()), 1000 | 'All', 1001 | id='size-filter', 1002 | style={ 1003 | "borderRadius": "8px", 1004 | "border": f"1px solid {COLORS['primary']}", 1005 | "fontFamily": "'Poppins', sans-serif" 1006 | } 1007 | ), 1008 | 1009 | html.Label("Outlet Type", style={"fontWeight": "500", "color": COLORS['text'], "marginTop": "20px"}), 1010 | dcc.Dropdown( 1011 | ['All'] + sorted(df['outlet_type'].unique()), 1012 | 'All', 1013 | id='type-filter', 1014 | style={ 1015 | "borderRadius": "8px", 1016 | "border": f"1px solid {COLORS['primary']}", 1017 | "fontFamily": "'Poppins', sans-serif" 1018 | } 1019 | ), 1020 | 1021 | html.Button( 1022 | "Reset Filters", 1023 | id='reset-button', 1024 | className="btn btn-outline-primary mt-4 w-100", 1025 | style={ 1026 | "borderRadius": "8px", 1027 | "border": f"2px solid {COLORS['accent2']}", 1028 | "color": COLORS['accent2'], 1029 | "fontFamily": "'Poppins', sans-serif", 1030 | "transition": "all 0.3s ease-in-out", 1031 | ":hover": {"backgroundColor": COLORS['accent2'], "color": "#FFFFFF"} 1032 | } 1033 | ), 1034 | ], 1035 | style={ 1036 | "background": f"linear-gradient(180deg, {COLORS['secondary']}20 0%, {COLORS['primary']}20 100%)", # Softer gradient 1037 | "padding": "30px", 1038 | "borderRadius": "15px", 1039 | "boxShadow": "0 4px 15px rgba(0,0,0,0.1)", 1040 | "position": "sticky", 1041 | "top": "20px", 1042 | "height": "fit-content" 1043 | } 1044 | ) 1045 | ], 1046 | width=2, 1047 | style={"padding": "20px"} 1048 | ), 1049 | 1050 | # Main Content 1051 | dbc.Col( 1052 | [ 1053 | # KPI Cards 1054 | dbc.Row( 1055 | [ 1056 | dbc.Col( 1057 | generate_kpi_card("Total Sales", f"${df['total_sales'].sum() / 1e6:.2f}M", COLORS['primary'], "fas fa-dollar-sign"), 1058 | width=3 1059 | ), 1060 | dbc.Col( 1061 | generate_kpi_card("Avg Sales", f"${df['avg_sales'].mean():.0f}", COLORS['accent1'], "fas fa-chart-line"), 1062 | width=3 1063 | ), 1064 | dbc.Col( 1065 | generate_kpi_card("No. of Items", f"{df['no_of_items'].sum()}", COLORS['accent2'], "fas fa-boxes"), 1066 | width=3 1067 | ), 1068 | dbc.Col( 1069 | generate_kpi_card("Avg Ratings", f"{df['avg_ratings'].mean():.1f}", COLORS['secondary'], "fas fa-star"), 1070 | width=3 1071 | ), 1072 | ], 1073 | className="mb-4" 1074 | ), 1075 | 1076 | # Tabs for dynamic bar chart (unchanged) 1077 | dbc.Row( 1078 | [ 1079 | dcc.Tabs( 1080 | id="tabs", 1081 | value='avg_sales', 1082 | children=[ 1083 | dcc.Tab( 1084 | label='Avg Sales', 1085 | value='avg_sales', 1086 | style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 1087 | selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 1088 | ), 1089 | dcc.Tab( 1090 | label='Avg Ratings', 1091 | value='avg_ratings', 1092 | style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 1093 | selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 1094 | ), 1095 | dcc.Tab( 1096 | label='No. of Items', 1097 | value='no_of_items', 1098 | style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 1099 | selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 1100 | ), 1101 | dcc.Tab( 1102 | label='Total Sales', 1103 | value='total_sales', 1104 | style={"fontFamily": "'Poppins', sans-serif", "color": COLORS['text']}, 1105 | selected_style={"backgroundColor": COLORS['primary'], "color": "#FFFFFF"} 1106 | ), 1107 | ], 1108 | style={"fontFamily": "'Poppins', sans-serif"} 1109 | ), 1110 | dcc.Graph(id='bar-chart', style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"}), 1111 | ], 1112 | className="mb-4" 1113 | ), 1114 | 1115 | # Charts Section 1116 | dbc.Row( 1117 | [ 1118 | dbc.Col( 1119 | dcc.Graph(id='fat-pie'), 1120 | width=6, 1121 | style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"} 1122 | ), 1123 | dbc.Col( 1124 | dcc.Graph(id='size-pie'), 1125 | width=6, 1126 | style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"} 1127 | ), 1128 | ], 1129 | className="mb-4" 1130 | ), 1131 | 1132 | dbc.Row( 1133 | [ 1134 | dbc.Col( 1135 | dcc.Graph(id='sales-by-item'), 1136 | width=6, 1137 | style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"} 1138 | ), 1139 | dbc.Col( 1140 | dcc.Graph(id='establishment-trend'), 1141 | width=6, 1142 | style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"} 1143 | ), 1144 | ], 1145 | className="mb-4" 1146 | ), 1147 | 1148 | dbc.Row( 1149 | [ 1150 | dbc.Col( 1151 | dcc.Graph(id='location-bar'), 1152 | width=6, 1153 | style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"} 1154 | ), 1155 | dbc.Col( 1156 | dcc.Graph(id='outlet-type-table'), 1157 | width=6, 1158 | style={"backgroundColor": "#F9FAFB", "borderRadius": "10px", "padding": "10px"} 1159 | ), 1160 | ] 1161 | ) 1162 | ], 1163 | width=10 1164 | ) 1165 | ] 1166 | ) 1167 | ], 1168 | fluid=True, 1169 | style={ 1170 | "background": f"linear-gradient(180deg, {COLORS['background']} 0%, #E8ECEF 100%)", # Subtle gradient 1171 | "padding": "40px", 1172 | "fontFamily": "'Poppins', sans-serif" 1173 | } 1174 | ) 1175 | 1176 | # Callback to reset filters (unchanged) 1177 | @app.callback( 1178 | [Output('location-filter', 'value'), 1179 | Output('size-filter', 'value'), 1180 | Output('type-filter', 'value')], 1181 | Input('reset-button', 'n_clicks') 1182 | ) 1183 | def reset_filters(n_clicks): 1184 | return 'All', 'All', 'All' 1185 | 1186 | # Callback to update all charts 1187 | @app.callback( 1188 | [Output('fat-pie', 'figure'), 1189 | Output('size-pie', 'figure'), 1190 | Output('sales-by-item', 'figure'), 1191 | Output('establishment-trend', 'figure'), 1192 | Output('location-bar', 'figure'), 1193 | Output('outlet-type-table', 'figure'), 1194 | Output('bar-chart', 'figure')], 1195 | [Input('location-filter', 'value'), 1196 | Input('size-filter', 'value'), 1197 | Input('type-filter', 'value'), 1198 | Input('tabs', 'value')] 1199 | ) 1200 | def update_charts(location, size, otype, tab): 1201 | dff = df.copy() 1202 | if location != 'All': 1203 | dff = dff[dff['outlet_location'] == location] 1204 | if size != 'All': 1205 | dff = dff[dff['outlet_size'] == size] 1206 | if otype != 'All': 1207 | dff = dff[dff['outlet_type'] == otype] 1208 | 1209 | # Handle empty dataframe 1210 | if dff.empty: 1211 | empty_fig = go.Figure().update_layout( 1212 | title="No Data Available", 1213 | annotations=[dict(text="No data matches the selected filters.", x=0.5, y=0.5, showarrow=False)], 1214 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1215 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1216 | paper_bgcolor='#F9FAFB', # Match chart background 1217 | plot_bgcolor='#F9FAFB' 1218 | ) 1219 | return (empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig) 1220 | 1221 | # Define custom color sequence 1222 | color_sequence = [COLORS['primary'], COLORS['secondary'], COLORS['accent1'], COLORS['accent2']] 1223 | 1224 | # Pie Charts 1225 | fat_fig = px.pie( 1226 | dff, 1227 | values='total_sales', 1228 | names='fat_content', 1229 | hole=0.5, 1230 | title="Sales by Fat Content", 1231 | color_discrete_sequence=color_sequence 1232 | ).update_traces( 1233 | textinfo='percent+label', 1234 | hovertemplate='%{label}: %{value:,.0f} (%{percent})', 1235 | marker=dict(line=dict(color='#FFFFFF', width=2)) 1236 | ).update_layout( 1237 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1238 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1239 | paper_bgcolor='#F9FAFB', 1240 | plot_bgcolor='#F9FAFB', 1241 | showlegend=True, 1242 | margin=dict(t=50, b=50, l=50, r=50) 1243 | ) 1244 | 1245 | size_fig = px.pie( 1246 | dff, 1247 | values='total_sales', 1248 | names='outlet_size', 1249 | hole=0.5, 1250 | title="Sales by Outlet Size", 1251 | color_discrete_sequence=color_sequence 1252 | ).update_traces( 1253 | textinfo='percent+label', 1254 | hovertemplate='%{label}: %{value:,.0f} (%{percent})', 1255 | marker=dict(line=dict(color='#FFFFFF', width=2)) 1256 | ).update_layout( 1257 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1258 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1259 | paper_bgcolor='#F9FAFB', 1260 | plot_bgcolor='#F9FAFB', 1261 | showlegend=True, 1262 | margin=dict(t=50, b=50, l=50, r=50) 1263 | ) 1264 | 1265 | # Bar Charts 1266 | item_fig = px.bar( 1267 | dff.groupby('item_type')['total_sales'].sum().nlargest(10).reset_index(), 1268 | x='total_sales', 1269 | y='item_type', 1270 | orientation='h', 1271 | title="Top 10 Item Types by Sales", 1272 | color_discrete_sequence=[COLORS['accent1']] 1273 | ).update_traces( 1274 | hovertemplate='%{y}: %{x:,.0f}', 1275 | marker=dict(line=dict(color='#FFFFFF', width=1)) 1276 | ).update_layout( 1277 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1278 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1279 | xaxis_title="Total Sales", 1280 | yaxis_title="Item Type", 1281 | paper_bgcolor='#F9FAFB', 1282 | plot_bgcolor='#F9FAFB', 1283 | margin=dict(t=50, b=50, l=50, r=50) 1284 | ) 1285 | 1286 | est_fig = px.line( 1287 | dff.groupby('year_established')['total_sales'].sum().reset_index(), 1288 | x='year_established', 1289 | y='total_sales', 1290 | title="Sales Trend by Establishment Year", 1291 | color_discrete_sequence=[COLORS['primary']], 1292 | markers=True 1293 | ).update_traces( 1294 | hovertemplate='Year: %{x}
Sales: %{y:,.0f}', 1295 | line=dict(width=3), 1296 | marker=dict(size=8) 1297 | ).update_layout( 1298 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1299 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1300 | xaxis_title="Year Established", 1301 | yaxis_title="Total Sales", 1302 | paper_bgcolor='#F9FAFB', 1303 | plot_bgcolor='#F9FAFB', 1304 | margin=dict(t=50, b=50, l=50, r=50) 1305 | ) 1306 | 1307 | loc_fig = px.bar( 1308 | dff.groupby('outlet_location')['total_sales'].sum().reset_index(), 1309 | x='outlet_location', 1310 | y='total_sales', 1311 | title="Sales by Outlet Location", 1312 | color_discrete_sequence=[COLORS['accent2']] 1313 | ).update_traces( 1314 | hovertemplate='%{x}: %{y:,.0f}', 1315 | marker=dict(line=dict(color='#FFFFFF', width=1)) 1316 | ).update_layout( 1317 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1318 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1319 | xaxis_title="Outlet Location", 1320 | yaxis_title="Total Sales", 1321 | paper_bgcolor='#F9FAFB', 1322 | plot_bgcolor='#F9FAFB', 1323 | margin=dict(t=50, b=50, l=50, r=50) 1324 | ) 1325 | 1326 | outlet_summary = dff.groupby('outlet_type').agg({ 1327 | 'total_sales': 'sum', 1328 | 'no_of_items': 'sum', 1329 | 'avg_sales': 'mean', 1330 | 'avg_ratings': 'mean', 1331 | 'item_visibility': 'mean' 1332 | }).reset_index() 1333 | 1334 | outlet_fig = px.bar( 1335 | outlet_summary, 1336 | x='total_sales', 1337 | y='outlet_type', 1338 | orientation='h', 1339 | title="Outlet Type Performance", 1340 | color='avg_ratings', 1341 | color_continuous_scale=[COLORS['secondary'], COLORS['primary']] 1342 | ).update_traces( 1343 | hovertemplate='%{y}: Sales=%{x:,.0f}
Avg Rating=%{marker.color:.1f}', 1344 | marker=dict(line=dict(color='#FFFFFF', width=1)) 1345 | ).update_layout( 1346 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1347 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1348 | xaxis_title="Total Sales", 1349 | yaxis_title="Outlet Type", 1350 | coloraxis_colorbar_title="Avg Ratings", 1351 | paper_bgcolor='#F9FAFB', 1352 | plot_bgcolor='#F9FAFB', 1353 | margin=dict(t=50, b=50, l=50, r=50) 1354 | ) 1355 | 1356 | # Tab-based Bar Chart 1357 | y_col = tab if tab in dff.columns else 'total_sales' 1358 | color = COLORS['accent1'] if tab in ['avg_sales', 'avg_ratings', 'no_of_items'] else COLORS['primary'] 1359 | agg_dict = { 1360 | 'total_sales': 'sum', 1361 | 'avg_sales': 'mean', 1362 | 'avg_ratings': 'mean', 1363 | 'no_of_items': 'sum' 1364 | } 1365 | bar_data = dff.groupby('outlet_type')[y_col].agg(agg_dict.get(y_col, 'sum')).reset_index() 1366 | 1367 | bar_fig = px.bar( 1368 | bar_data, 1369 | x='outlet_type', 1370 | y=y_col, 1371 | title=f"{y_col.replace('_', ' ').title()} by Outlet Type", 1372 | color_discrete_sequence=[color] 1373 | ).update_traces( 1374 | hovertemplate='%{x}: %{y:,.2f}', 1375 | marker=dict(line=dict(color='#FFFFFF', width=1)) 1376 | ).update_layout( 1377 | title_font=dict(size=20, family="'Poppins', sans-serif", color=COLORS['text']), 1378 | font=dict(family="'Poppins', sans-serif", color=COLORS['text']), 1379 | xaxis_title="Outlet Type", 1380 | yaxis_title=y_col.replace('_', ' ').title(), 1381 | paper_bgcolor='#F9FAFB', 1382 | plot_bgcolor='#F9FAFB', 1383 | margin=dict(t=50, b=50, l=50, r=50), 1384 | height=400, 1385 | xaxis_tickangle=45 1386 | ) 1387 | 1388 | return fat_fig, size_fig, item_fig, est_fig, loc_fig, outlet_fig, bar_fig 1389 | 1390 | 1391 | # Run server 1392 | if __name__ == '__main__': 1393 | app.run(debug=True) --------------------------------------------------------------------------------