Spaces:
Sleeping
Sleeping
ProtonDataLabs
commited on
Commit
•
8776749
1
Parent(s):
3065b7d
Update app.py
Browse files
app.py
CHANGED
@@ -11,7 +11,30 @@ from datetime import datetime, timedelta
|
|
11 |
import warnings
|
12 |
import time
|
13 |
import dask.dataframe as dd
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
@st.cache_data
|
16 |
def date_from_week(year, week):
|
17 |
# Assuming the fiscal year starts in August and the week starts from August 1st
|
@@ -29,6 +52,7 @@ def load_data(active_card):
|
|
29 |
card_specific_cols = {
|
30 |
'card1': ['FyWeek', 'State', 'Itemtype', 'Chaincode', 'SalesVolume'],
|
31 |
'card2': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'],
|
|
|
32 |
}
|
33 |
|
34 |
# Choose columns based on the active card
|
@@ -57,7 +81,7 @@ def load_data(active_card):
|
|
57 |
df = ddf.compute()
|
58 |
|
59 |
|
60 |
-
if active_card in ['card2']:
|
61 |
df = df.groupby(['FyWeek', 'Fy', 'Chaincode', 'Store', 'Address', 'Zipcode', 'City', 'State', 'Containercode', 'Itemtype'], observed=True).agg({
|
62 |
'SalesVolume': 'sum',
|
63 |
'UnitPrice': 'mean',
|
@@ -68,6 +92,9 @@ def load_data(active_card):
|
|
68 |
df['Year'] = df['FY'].str[2:].astype(int) # Extract year part and convert to int
|
69 |
df['Dt'] = date_from_week(df['Year'], df['Week'])
|
70 |
|
|
|
|
|
|
|
71 |
# st.write(df.columns)
|
72 |
return df
|
73 |
|
@@ -75,10 +102,9 @@ def load_data(active_card):
|
|
75 |
st.image("bonnie.png", width=150) # Adjust width as needed
|
76 |
|
77 |
# Display title
|
78 |
-
st.title("Bonnie Plants Pricing & Sales Analytics Dashboard")
|
|
|
79 |
|
80 |
-
# Close the div for logo and title
|
81 |
-
st.markdown('</div>', unsafe_allow_html=True)
|
82 |
|
83 |
# Initialize session state for storing which card was clicked and item type
|
84 |
if 'active_card' not in st.session_state:
|
@@ -90,7 +116,7 @@ if 'selected_feature' not in st.session_state:
|
|
90 |
st.session_state['selected_feature'] = 'Chaincode' # Default to 'Chain Code'
|
91 |
|
92 |
# Card selection buttons
|
93 |
-
col1, col2 = st.columns(
|
94 |
# Define buttons for plot categories, update session state when clicked
|
95 |
with col1:
|
96 |
if st.button("Sales Volume Trend for Item Category"):
|
@@ -99,7 +125,10 @@ with col1:
|
|
99 |
with col2:
|
100 |
if st.button("Sales Volume & Unit Price Correlation for Item Category and Container Code"):
|
101 |
st.session_state['active_card'] = 'card2'
|
102 |
-
|
|
|
|
|
|
|
103 |
start_time=time.time()
|
104 |
# st.write(st.session_state['active_card'])
|
105 |
df = load_data(st.session_state['active_card'])
|
@@ -246,3 +275,58 @@ if st.session_state['active_card'] == 'card2':
|
|
246 |
|
247 |
|
248 |
##########################################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
import warnings
|
12 |
import time
|
13 |
import dask.dataframe as dd
|
14 |
+
state_to_region = {
|
15 |
+
# WEST
|
16 |
+
'AK': 'WEST', 'CA': 'WEST', 'CO': 'WEST', 'HI': 'WEST', 'ID': 'WEST',
|
17 |
+
'MT': 'WEST', 'NV': 'WEST', 'OR': 'WEST', 'UT': 'WEST', 'WA': 'WEST', 'WY': 'WEST',
|
18 |
+
|
19 |
+
# SOUTHWEST
|
20 |
+
'AZ': 'SOUTHWEST', 'NM': 'SOUTHWEST', 'OK': 'SOUTHWEST', 'TX': 'SOUTHWEST',
|
21 |
+
|
22 |
+
# MIDWEST
|
23 |
+
'IL': 'MIDWEST', 'IN': 'MIDWEST', 'IA': 'MIDWEST', 'KS': 'MIDWEST', 'MI': 'MIDWEST',
|
24 |
+
'MN': 'MIDWEST', 'MO': 'MIDWEST', 'NE': 'MIDWEST', 'ND': 'MIDWEST', 'OH': 'MIDWEST',
|
25 |
+
'SD': 'MIDWEST', 'WI': 'MIDWEST',
|
26 |
+
|
27 |
+
# SOUTHEAST
|
28 |
+
'AL': 'SOUTHEAST', 'AR': 'SOUTHEAST', 'DE': 'SOUTHEAST', 'FL': 'SOUTHEAST',
|
29 |
+
'GA': 'SOUTHEAST', 'KY': 'SOUTHEAST', 'LA': 'SOUTHEAST', 'MD': 'SOUTHEAST',
|
30 |
+
'MS': 'SOUTHEAST', 'NC': 'SOUTHEAST', 'SC': 'SOUTHEAST', 'TN': 'SOUTHEAST',
|
31 |
+
'VA': 'SOUTHEAST', 'WV': 'SOUTHEAST',
|
32 |
+
|
33 |
+
# NORTHEAST
|
34 |
+
'CT': 'NORTHEAST', 'ME': 'NORTHEAST', 'MA': 'NORTHEAST', 'NH': 'NORTHEAST',
|
35 |
+
'NJ': 'NORTHEAST', 'NY': 'NORTHEAST', 'PA': 'NORTHEAST', 'RI': 'NORTHEAST',
|
36 |
+
'VT': 'NORTHEAST'
|
37 |
+
}
|
38 |
@st.cache_data
|
39 |
def date_from_week(year, week):
|
40 |
# Assuming the fiscal year starts in August and the week starts from August 1st
|
|
|
52 |
card_specific_cols = {
|
53 |
'card1': ['FyWeek', 'State', 'Itemtype', 'Chaincode', 'SalesVolume'],
|
54 |
'card2': ['FyWeek', 'Fy', 'State','Store','Address','Zipcode','City','Itemtype', 'Chaincode', 'Containercode', 'SalesVolume', 'UnitPrice', 'Sales'],
|
55 |
+
'card3': ['FyWeek', 'Fy', 'State', 'Store', 'Itemtype', 'Chaincode', 'SalesVolume', 'UnitPrice', 'Sales'] # Added for PE calculation card
|
56 |
}
|
57 |
|
58 |
# Choose columns based on the active card
|
|
|
81 |
df = ddf.compute()
|
82 |
|
83 |
|
84 |
+
if active_card in ['card2','card3']:
|
85 |
df = df.groupby(['FyWeek', 'Fy', 'Chaincode', 'Store', 'Address', 'Zipcode', 'City', 'State', 'Containercode', 'Itemtype'], observed=True).agg({
|
86 |
'SalesVolume': 'sum',
|
87 |
'UnitPrice': 'mean',
|
|
|
92 |
df['Year'] = df['FY'].str[2:].astype(int) # Extract year part and convert to int
|
93 |
df['Dt'] = date_from_week(df['Year'], df['Week'])
|
94 |
|
95 |
+
# Add the region column based on state
|
96 |
+
df['Region'] = df['State'].map(state_to_region)
|
97 |
+
|
98 |
# st.write(df.columns)
|
99 |
return df
|
100 |
|
|
|
102 |
st.image("bonnie.png", width=150) # Adjust width as needed
|
103 |
|
104 |
# Display title
|
105 |
+
# st.title("Bonnie Plants Pricing & Sales Analytics Dashboard")
|
106 |
+
st.title("Price vs. Sales Volume Tracker Dashboard")
|
107 |
|
|
|
|
|
108 |
|
109 |
# Initialize session state for storing which card was clicked and item type
|
110 |
if 'active_card' not in st.session_state:
|
|
|
116 |
st.session_state['selected_feature'] = 'Chaincode' # Default to 'Chain Code'
|
117 |
|
118 |
# Card selection buttons
|
119 |
+
col1, col2 ,col3= st.columns(3)
|
120 |
# Define buttons for plot categories, update session state when clicked
|
121 |
with col1:
|
122 |
if st.button("Sales Volume Trend for Item Category"):
|
|
|
125 |
with col2:
|
126 |
if st.button("Sales Volume & Unit Price Correlation for Item Category and Container Code"):
|
127 |
st.session_state['active_card'] = 'card2'
|
128 |
+
with col3:
|
129 |
+
if st.button("PE Coefficient Calculation for Regions & Item Categories"):
|
130 |
+
st.session_state['active_card'] = 'card3'
|
131 |
+
|
132 |
start_time=time.time()
|
133 |
# st.write(st.session_state['active_card'])
|
134 |
df = load_data(st.session_state['active_card'])
|
|
|
275 |
|
276 |
|
277 |
##########################################################################################################
|
278 |
+
|
279 |
+
if st.session_state['active_card'] == 'card3':
|
280 |
+
# Dropdown for selecting the item type
|
281 |
+
item_type_options = df['Itemtype'].unique()
|
282 |
+
selected_item_type = st.selectbox("Select Item Type", item_type_options)
|
283 |
+
|
284 |
+
# Dropdown for selecting the region (multiple selection allowed)
|
285 |
+
region_options = df['Region'].unique()
|
286 |
+
selected_regions = st.multiselect("Select Region(s)", region_options, default=region_options)
|
287 |
+
|
288 |
+
# Filter data based on selected item type and selected regions
|
289 |
+
filtered_df = df[(df['Itemtype'] == selected_item_type) & (df['Region'].isin(selected_regions))]
|
290 |
+
|
291 |
+
# Group by Year, Region, Itemtype and Promo, and aggregate SalesVolume and UnitPrice
|
292 |
+
agg_df = filtered_df.groupby(['Fy', 'Region', 'Itemtype',]).agg({
|
293 |
+
'SalesVolume': 'sum',
|
294 |
+
'UnitPrice': 'mean'
|
295 |
+
}).reset_index()
|
296 |
+
|
297 |
+
# Sort values by Region, Itemtype, Fy, and Promo for YOY calculation
|
298 |
+
agg_df = agg_df.sort_values(by=['Region', 'Itemtype', 'Fy',])
|
299 |
+
|
300 |
+
# Calculate YOY percentage changes in Sales Volume and Unit Price
|
301 |
+
agg_df['SalesVolume_pct_change'] = agg_df.groupby(['Region', 'Itemtype',])['SalesVolume'].pct_change().round(3) * 100
|
302 |
+
agg_df['UnitPrice_pct_change'] = agg_df.groupby(['Region', 'Itemtype', ])['UnitPrice'].pct_change().round(3) * 100
|
303 |
+
|
304 |
+
# Calculate Price Elasticity Coefficient (PE)
|
305 |
+
agg_df['PE_Coeff'] = (agg_df['SalesVolume_pct_change'] / agg_df['UnitPrice_pct_change']).round(2)
|
306 |
+
|
307 |
+
# Exclude FY 2025 but keep FY 2021 even with NaN values
|
308 |
+
agg_df_filtered = agg_df[agg_df['Fy'] != 'FY 2025']
|
309 |
+
|
310 |
+
# Drop rows where PE_Coeff is NaN (optional)
|
311 |
+
agg_df_filtered = agg_df_filtered.dropna(subset=['PE_Coeff'])
|
312 |
+
st.dataframe(agg_df_filtered)
|
313 |
+
st.write(agg_df_filtered.shape)
|
314 |
+
# Plot the PE Coefficient with Plotly
|
315 |
+
fig = px.line(
|
316 |
+
agg_df_filtered,
|
317 |
+
x='Fy',
|
318 |
+
y='PE_Coeff', # Differentiate between Promo and NoPromo
|
319 |
+
line_dash='Region', # Differentiate lines by Region
|
320 |
+
title=f"Price Elasticity Coefficient (PE) by Year for {selected_item_type}",
|
321 |
+
labels={'Fy': 'Fiscal Year', 'PE_Coeff': 'Price Elasticity Coefficient'},
|
322 |
+
markers=True
|
323 |
+
)
|
324 |
+
|
325 |
+
# Customize layout and show plot
|
326 |
+
fig.update_layout(
|
327 |
+
height=600,
|
328 |
+
width=1000,
|
329 |
+
)
|
330 |
+
|
331 |
+
st.plotly_chart(fig, use_container_width=True)
|
332 |
+
###################################################################################################################
|