Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -50,7 +50,7 @@ def load_data(active_card):
|
|
50 |
|
51 |
# Columns specific to cards
|
52 |
card_specific_cols = {
|
53 |
-
'card1': ['FyWeek', '
|
54 |
'card2': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'],
|
55 |
'card3': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'] # Added for PE calculation card
|
56 |
}
|
@@ -82,7 +82,7 @@ def load_data(active_card):
|
|
82 |
|
83 |
# st.write("+++++++++++++++++++++++")
|
84 |
|
85 |
-
if active_card in ['card2', 'card3',
|
86 |
df = df.groupby(['FyWeek', 'Fy', 'Chaincode', 'Store', 'Address', 'Zipcode', 'City', 'State', 'Containercode', 'Itemtype'], observed=True).agg({
|
87 |
'SalesVolume': 'sum',
|
88 |
'UnitPrice': 'mean',
|
@@ -96,19 +96,13 @@ def load_data(active_card):
|
|
96 |
df['Region'] = df['State'].map(state_to_region)
|
97 |
|
98 |
return df
|
99 |
-
|
100 |
-
# st.image("bonnie.png", width=200)
|
101 |
-
# # Main interactive section
|
102 |
-
# st.title('Bonnnie Plants Price vs Sales Volume Trcaker')
|
103 |
-
|
104 |
# Display logo
|
105 |
st.image("bonnie.png", width=150) # Adjust width as needed
|
106 |
|
107 |
# Display title
|
108 |
st.title("Bonnie Plants Pricing & Sales Analytics Dashboard")
|
109 |
|
110 |
-
# Close the div for logo and title
|
111 |
-
# st.markdown('</div>', unsafe_allow_html=True)
|
112 |
|
113 |
# Initialize session state for storing which card was clicked and item type
|
114 |
if 'active_card' not in st.session_state:
|
@@ -119,60 +113,221 @@ if 'selected_item_type' not in st.session_state:
|
|
119 |
if 'selected_feature' not in st.session_state:
|
120 |
st.session_state['selected_feature'] = 'Chaincode' # Default to 'Chain Code'
|
121 |
|
122 |
-
# Card selection buttons
|
123 |
-
col1, col2, col3= st.columns(3)
|
124 |
-
# Define buttons for plot categories, update session state when clicked
|
125 |
with col1:
|
126 |
if st.button("Sales Volume Trend for Item Category"):
|
127 |
st.session_state['active_card'] = 'card1'
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
with col2:
|
130 |
if st.button("Sales Volume & Unit Price Correlation for Item Category and Container Code"):
|
131 |
st.session_state['active_card'] = 'card2'
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
with col3:
|
133 |
if st.button("PE Coefficient Calculation for Regions & Item Categories"):
|
134 |
st.session_state['active_card'] = 'card3'
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
|
|
|
|
|
|
|
|
139 |
df = load_data(st.session_state['active_card'])
|
140 |
time_taken = time.time() - start_time
|
141 |
st.write(f"Data loaded in {time_taken:.2f} seconds")
|
142 |
|
143 |
|
144 |
-
# Initialize session state for storing the selected state and feature
|
145 |
-
if 'selected_state' not in st.session_state:
|
146 |
-
st.session_state['selected_state'] = df['State'].unique()[0] # Default to the first state
|
147 |
-
|
148 |
############################################ CARD #1 ####################################################
|
149 |
if st.session_state['active_card'] == 'card1':
|
150 |
-
#
|
151 |
-
|
152 |
-
|
153 |
-
#
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
st.
|
170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
##########################################################################################################
|
172 |
|
173 |
-
##########################################################################################################
|
174 |
|
|
|
175 |
if st.session_state['active_card'] == 'card2':
|
|
|
|
|
|
|
|
|
|
|
176 |
# Dropdown to select item type (using session_state)
|
177 |
st.session_state['selected_item_type'] = st.selectbox(
|
178 |
'Select Item Type', df['Itemtype'].unique(),
|
@@ -279,7 +434,7 @@ if st.session_state['active_card'] == 'card3':
|
|
279 |
selected_item_type = st.selectbox("Select Item Type", item_type_options)
|
280 |
|
281 |
# Dropdown for selecting the region (multiple selection allowed)
|
282 |
-
region_options = df['Region'].unique()
|
283 |
selected_regions = st.multiselect("Select Region(s)", region_options, default=region_options)
|
284 |
|
285 |
# Filter data based on selected item type and selected regions
|
|
|
50 |
|
51 |
# Columns specific to cards
|
52 |
card_specific_cols = {
|
53 |
+
'card1': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'],
|
54 |
'card2': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'],
|
55 |
'card3': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'] # Added for PE calculation card
|
56 |
}
|
|
|
82 |
|
83 |
# st.write("+++++++++++++++++++++++")
|
84 |
|
85 |
+
if active_card in ['card1','card2', 'card3',]:
|
86 |
df = df.groupby(['FyWeek', 'Fy', 'Chaincode', 'Store', 'Address', 'Zipcode', 'City', 'State', 'Containercode', 'Itemtype'], observed=True).agg({
|
87 |
'SalesVolume': 'sum',
|
88 |
'UnitPrice': 'mean',
|
|
|
96 |
df['Region'] = df['State'].map(state_to_region)
|
97 |
|
98 |
return df
|
99 |
+
|
|
|
|
|
|
|
|
|
100 |
# Display logo
|
101 |
st.image("bonnie.png", width=150) # Adjust width as needed
|
102 |
|
103 |
# Display title
|
104 |
st.title("Bonnie Plants Pricing & Sales Analytics Dashboard")
|
105 |
|
|
|
|
|
106 |
|
107 |
# Initialize session state for storing which card was clicked and item type
|
108 |
if 'active_card' not in st.session_state:
|
|
|
113 |
if 'selected_feature' not in st.session_state:
|
114 |
st.session_state['selected_feature'] = 'Chaincode' # Default to 'Chain Code'
|
115 |
|
116 |
+
# Card selection buttons with logic to reset session state on switch
|
117 |
+
col1, col2, col3 = st.columns(3)
|
|
|
118 |
with col1:
|
119 |
if st.button("Sales Volume Trend for Item Category"):
|
120 |
st.session_state['active_card'] = 'card1'
|
121 |
+
# Reset other selections when switching cards
|
122 |
+
st.session_state['selected_state'] = None
|
123 |
+
st.session_state['selected_chaincode'] = None
|
124 |
+
st.session_state['selected_itemtype'] = None
|
125 |
+
st.session_state['selected_containercode'] = None
|
126 |
|
127 |
with col2:
|
128 |
if st.button("Sales Volume & Unit Price Correlation for Item Category and Container Code"):
|
129 |
st.session_state['active_card'] = 'card2'
|
130 |
+
# Reset selections when switching cards
|
131 |
+
st.session_state['selected_state'] = None
|
132 |
+
st.session_state['selected_chaincode'] = None
|
133 |
+
st.session_state['selected_itemtype'] = None
|
134 |
+
st.session_state['selected_containercode'] = None
|
135 |
+
|
136 |
with col3:
|
137 |
if st.button("PE Coefficient Calculation for Regions & Item Categories"):
|
138 |
st.session_state['active_card'] = 'card3'
|
139 |
+
# Reset selections when switching cards
|
140 |
+
st.session_state['selected_state'] = None
|
141 |
+
st.session_state['selected_chaincode'] = None
|
142 |
+
st.session_state['selected_itemtype'] = None
|
143 |
+
st.session_state['selected_containercode'] = None
|
144 |
+
|
145 |
+
# Load data for the current card
|
146 |
+
start_time = time.time()
|
147 |
df = load_data(st.session_state['active_card'])
|
148 |
time_taken = time.time() - start_time
|
149 |
st.write(f"Data loaded in {time_taken:.2f} seconds")
|
150 |
|
151 |
|
|
|
|
|
|
|
|
|
152 |
############################################ CARD #1 ####################################################
|
153 |
if st.session_state['active_card'] == 'card1':
|
154 |
+
# Step 1: Sales Volume vs FyWeek for the whole dataset (no filter)
|
155 |
+
st.subheader("Total Sales Volume vs Fiscal Week")
|
156 |
+
df['FY_Week'] = df['FY'].astype(str) + '_' + df['Week'].astype(str)
|
157 |
+
# Split FY_Week again for correct sorting
|
158 |
+
if not df.empty and 'FY_Week' in df.columns:
|
159 |
+
total_sales_df = df.groupby('FY_Week', observed=True)['SalesVolume'].sum().reset_index()
|
160 |
+
total_sales_df[['FY', 'Week']] = total_sales_df['FY_Week'].str.split('_', expand=True)
|
161 |
+
total_sales_df['Week'] = total_sales_df['Week'].astype(int)
|
162 |
+
total_sales_df = total_sales_df.sort_values(by=['FY', 'Week'])
|
163 |
+
|
164 |
+
# Create a line chart using Plotly
|
165 |
+
fig = px.line(total_sales_df, x='FY_Week', y='SalesVolume',
|
166 |
+
title='Total Sales Volume vs Fiscal Week',
|
167 |
+
labels={'SalesVolume': 'Sales Volume', 'FY_Week': 'Fiscal Week'})
|
168 |
+
st.plotly_chart(fig)
|
169 |
+
|
170 |
+
# Step 2: Top 3 states based on sales volume as buttons/cards
|
171 |
+
top_states = df.groupby('State', observed=True)['SalesVolume'].sum().nlargest(3).index
|
172 |
+
st.write("### Top 3 Selling States :")
|
173 |
+
col1, col2, col3 = st.columns(3)
|
174 |
+
if len(top_states) > 0 and col1.button(top_states[0]):
|
175 |
+
st.session_state['selected_state'] = top_states[0]
|
176 |
+
if len(top_states) > 1 and col2.button(top_states[1]):
|
177 |
+
st.session_state['selected_state'] = top_states[1]
|
178 |
+
if len(top_states) > 2 and col3.button(top_states[2]):
|
179 |
+
st.session_state['selected_state'] = top_states[2]
|
180 |
+
|
181 |
+
# If a state is selected, show the corresponding plot
|
182 |
+
if 'selected_state' in st.session_state and st.session_state['selected_state']:
|
183 |
+
selected_state = st.session_state['selected_state']
|
184 |
+
|
185 |
+
# Step 3: Sales volume vs FyWeek for the selected state
|
186 |
+
st.subheader(f"Sales Volume vs Fiscal Week for {selected_state}")
|
187 |
+
state_sales_df = df[df['State'] == selected_state].groupby('FY_Week', observed=True)['SalesVolume'].sum().reset_index()
|
188 |
+
|
189 |
+
if not state_sales_df.empty and 'FY_Week' in state_sales_df.columns:
|
190 |
+
state_sales_df[['FY', 'Week']] = state_sales_df['FY_Week'].str.split('_', expand=True)
|
191 |
+
state_sales_df['Week'] = state_sales_df['Week'].astype(int)
|
192 |
+
state_sales_df = state_sales_df.sort_values(by=['FY', 'Week'])
|
193 |
+
|
194 |
+
fig = px.line(state_sales_df, x='FY_Week', y='SalesVolume',
|
195 |
+
title=f'Sales Volume vs Fiscal Week in {selected_state}',
|
196 |
+
labels={'SalesVolume': 'Sales Volume', 'FY_Week': 'Fiscal Week'})
|
197 |
+
st.plotly_chart(fig)
|
198 |
+
|
199 |
+
# Step 4: Top 3 chaincodes based on sales volume as buttons/cards
|
200 |
+
top_chaincodes = df[df['State'] == selected_state].groupby('Chaincode', observed=True)['SalesVolume'].sum().nlargest(3).index
|
201 |
+
st.write(f"### Top 3 selling Chaincode in {selected_state}:")
|
202 |
+
|
203 |
+
# Add a check to ensure top_chaincodes has values before accessing
|
204 |
+
col1, col2, col3 = st.columns(3)
|
205 |
+
if len(top_chaincodes) > 0 and col1.button(top_chaincodes[0]):
|
206 |
+
st.session_state['selected_chaincode'] = top_chaincodes[0]
|
207 |
+
if len(top_chaincodes) > 1 and col2.button(top_chaincodes[1]):
|
208 |
+
st.session_state['selected_chaincode'] = top_chaincodes[1]
|
209 |
+
if len(top_chaincodes) > 2 and col3.button(top_chaincodes[2]):
|
210 |
+
st.session_state['selected_chaincode'] = top_chaincodes[2]
|
211 |
+
|
212 |
+
# If a chaincode is selected, show the corresponding plot
|
213 |
+
if 'selected_chaincode' in st.session_state:
|
214 |
+
selected_chaincode = st.session_state['selected_chaincode']
|
215 |
+
|
216 |
+
# Step 5: Sales volume vs FyWeek for the selected chaincode in the selected state
|
217 |
+
st.subheader(f"Sales Volume vs Fiscal Week for {selected_chaincode} in {selected_state}")
|
218 |
+
chain_sales_df = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode)].groupby('FY_Week', observed=True)['SalesVolume'].sum().reset_index()
|
219 |
+
|
220 |
+
if not chain_sales_df.empty and 'FY_Week' in chain_sales_df.columns:
|
221 |
+
chain_sales_df[['FY', 'Week']] = chain_sales_df['FY_Week'].str.split('_', expand=True)
|
222 |
+
chain_sales_df['Week'] = chain_sales_df['Week'].astype(int)
|
223 |
+
chain_sales_df = chain_sales_df.sort_values(by=['FY', 'Week'])
|
224 |
+
|
225 |
+
fig = px.line(chain_sales_df, x='FY_Week', y='SalesVolume',
|
226 |
+
title=f'Sales Volume vs Fiscal Week in {selected_chaincode}, {selected_state}',
|
227 |
+
labels={'SalesVolume': 'Sales Volume', 'FY_Week': 'Fiscal Week'})
|
228 |
+
st.plotly_chart(fig)
|
229 |
+
|
230 |
+
# Step 6: Top 3 itemtypes based on sales volume as buttons/cards
|
231 |
+
top_itemtypes = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode)].groupby('Itemtype', observed=True)['SalesVolume'].sum().nlargest(3).index
|
232 |
+
st.write(f"### Top Itemtype in {selected_chaincode}, {selected_state}:")
|
233 |
+
|
234 |
+
col1, col2, col3 = st.columns(3)
|
235 |
+
if len(top_itemtypes) > 0 and col1.button(top_itemtypes[0]):
|
236 |
+
st.session_state['selected_itemtype'] = top_itemtypes[0]
|
237 |
+
if len(top_itemtypes) > 1 and col2.button(top_itemtypes[1]):
|
238 |
+
st.session_state['selected_itemtype'] = top_itemtypes[1]
|
239 |
+
if len(top_itemtypes) > 2 and col3.button(top_itemtypes[2]):
|
240 |
+
st.session_state['selected_itemtype'] = top_itemtypes[2]
|
241 |
+
|
242 |
+
# If an itemtype is selected, show the corresponding dual-axis plot for Sales Volume & Unit Price
|
243 |
+
if 'selected_itemtype' in st.session_state:
|
244 |
+
selected_itemtype = st.session_state['selected_itemtype']
|
245 |
+
|
246 |
+
# Step 7: Dual-axis plot for Sales volume and UnitPrice vs FyWeek for the selected itemtype
|
247 |
+
st.subheader(f"Sales Volume & Unit Price vs Fiscal Week for {selected_itemtype} in {selected_chaincode}, {selected_state}")
|
248 |
+
item_sales_df = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode) & (df['Itemtype'] == selected_itemtype)].groupby('FY_Week', observed=True).agg({
|
249 |
+
'SalesVolume': 'sum',
|
250 |
+
'UnitPrice': 'mean'
|
251 |
+
}).reset_index()
|
252 |
+
if not item_sales_df.empty and 'FY_Week' in item_sales_df.columns:
|
253 |
+
item_sales_df[['FY', 'Week']] = item_sales_df['FY_Week'].str.split('_', expand=True)
|
254 |
+
item_sales_df['Week'] = item_sales_df['Week'].astype(int)
|
255 |
+
item_sales_df = item_sales_df.sort_values(by=['FY', 'Week'])
|
256 |
+
|
257 |
+
# Dual-axis plot using Plotly Graph Objects
|
258 |
+
fig = go.Figure()
|
259 |
+
|
260 |
+
# Add SalesVolume trace
|
261 |
+
fig.add_trace(go.Scatter(
|
262 |
+
x=item_sales_df['FY_Week'],
|
263 |
+
y=item_sales_df['SalesVolume'],
|
264 |
+
mode='lines+markers',
|
265 |
+
name='SalesVolume',
|
266 |
+
line=dict(color='blue'),
|
267 |
+
hovertemplate='SalesVolume: %{y}<br>Week-Year: %{x}'
|
268 |
+
))
|
269 |
+
|
270 |
+
# Add UnitPrice trace with secondary Y-axis
|
271 |
+
fig.add_trace(go.Scatter(
|
272 |
+
x=item_sales_df['FY_Week'],
|
273 |
+
y=item_sales_df['UnitPrice'],
|
274 |
+
mode='lines+markers',
|
275 |
+
name='UnitPrice',
|
276 |
+
line=dict(color='green'),
|
277 |
+
yaxis='y2',
|
278 |
+
hovertemplate='UnitPrice: %{y}<br>Week-Year: %{x}'
|
279 |
+
))
|
280 |
+
|
281 |
+
# Update layout for dual axes
|
282 |
+
fig.update_layout(
|
283 |
+
title=f"Sales Volume & Unit Price vs Fiscal Week in {selected_itemtype}, {selected_chaincode}, {selected_state}",
|
284 |
+
xaxis_title='Fiscal Week',
|
285 |
+
yaxis_title='Sales Volume',
|
286 |
+
yaxis2=dict(title='Unit Price', overlaying='y', side='right'),
|
287 |
+
legend=dict(x=0.9, y=1.15),
|
288 |
+
hovermode="x unified", # Show both values in a tooltip
|
289 |
+
height=600,
|
290 |
+
margin=dict(l=50, r=50, t=50, b=50)
|
291 |
+
)
|
292 |
+
|
293 |
+
# Rotate X-axis labels
|
294 |
+
fig.update_xaxes(tickangle=90)
|
295 |
+
|
296 |
+
# Display the Plotly figure in Streamlit
|
297 |
+
st.plotly_chart(fig, use_container_width=True)
|
298 |
+
# Step 8: Display Top/Bottom Container Codes and Stores
|
299 |
+
st.subheader("Top & Bottom 3 Container Codes and Stores")
|
300 |
+
|
301 |
+
# Get top and bottom 3 container codes based on SalesVolume
|
302 |
+
top_containercodes = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode) & (df['Itemtype'] == selected_itemtype)].groupby('Containercode', observed=True)['SalesVolume'].sum().nlargest(3).reset_index()
|
303 |
+
bottom_containercodes = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode) & (df['Itemtype'] == selected_itemtype)].groupby('Containercode', observed=True)['SalesVolume'].sum().nsmallest(3).reset_index()
|
304 |
+
|
305 |
+
# Get top and bottom 3 stores based on SalesVolume
|
306 |
+
top_stores = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode) & (df['Itemtype'] == selected_itemtype)].groupby('Store', observed=True)['SalesVolume'].sum().nlargest(3).reset_index()
|
307 |
+
bottom_stores = df[(df['State'] == selected_state) & (df['Chaincode'] == selected_chaincode) & (df['Itemtype'] == selected_itemtype)].groupby('Store', observed=True)['SalesVolume'].sum().nsmallest(3).reset_index()
|
308 |
+
|
309 |
+
# Create a table with the top and bottom container codes and stores
|
310 |
+
st.write("### Top 3 Container Codes:")
|
311 |
+
st.dataframe(top_containercodes)
|
312 |
+
|
313 |
+
st.write("### Bottom 3 Container Codes:")
|
314 |
+
st.dataframe(bottom_containercodes)
|
315 |
+
|
316 |
+
st.write("### Top 3 Stores:")
|
317 |
+
st.dataframe(top_stores)
|
318 |
+
|
319 |
+
st.write("### Bottom 3 Stores:")
|
320 |
+
st.dataframe(bottom_stores)
|
321 |
##########################################################################################################
|
322 |
|
|
|
323 |
|
324 |
+
########################################### CARD #2 ####################################################
|
325 |
if st.session_state['active_card'] == 'card2':
|
326 |
+
# Identify the top 10 Itemtypes based on total SalesVolume
|
327 |
+
top_10_itemtypes = df.groupby('Itemtype')['SalesVolume'].sum().nlargest(10).index
|
328 |
+
|
329 |
+
# Filter the DataFrame to include only the top 10 Itemtypes
|
330 |
+
df = df[df['Itemtype'].isin(top_10_itemtypes)]
|
331 |
# Dropdown to select item type (using session_state)
|
332 |
st.session_state['selected_item_type'] = st.selectbox(
|
333 |
'Select Item Type', df['Itemtype'].unique(),
|
|
|
434 |
selected_item_type = st.selectbox("Select Item Type", item_type_options)
|
435 |
|
436 |
# Dropdown for selecting the region (multiple selection allowed)
|
437 |
+
region_options = df['Region'].dropna().unique()
|
438 |
selected_regions = st.multiselect("Select Region(s)", region_options, default=region_options)
|
439 |
|
440 |
# Filter data based on selected item type and selected regions
|