├── 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 | 
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)
--------------------------------------------------------------------------------