Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -51,7 +51,7 @@ def load_data(active_card):
|
|
| 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 |
}
|
| 57 |
|
|
@@ -114,7 +114,7 @@ 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,
|
| 118 |
with col1:
|
| 119 |
if st.button("Sales Volume Trend"):
|
| 120 |
st.session_state['active_card'] = 'card1'
|
|
@@ -124,14 +124,14 @@ with col1:
|
|
| 124 |
st.session_state['selected_itemtype'] = None
|
| 125 |
st.session_state['selected_containercode'] = None
|
| 126 |
|
| 127 |
-
with col2:
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
|
| 136 |
with col3:
|
| 137 |
if st.button("Price Elasticity Coefficient Trend YoY"):
|
|
@@ -327,110 +327,110 @@ if st.session_state['active_card'] == 'card1':
|
|
| 327 |
|
| 328 |
|
| 329 |
########################################### CARD #2 ####################################################
|
| 330 |
-
if st.session_state['active_card'] == 'card2':
|
| 331 |
-
|
| 332 |
-
|
| 333 |
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
|
| 341 |
-
|
| 342 |
-
|
| 343 |
|
| 344 |
-
|
| 345 |
-
|
| 346 |
|
| 347 |
-
|
| 348 |
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
|
| 354 |
-
|
| 355 |
-
|
| 356 |
|
| 357 |
-
|
| 358 |
-
|
| 359 |
|
| 360 |
-
|
| 361 |
-
|
| 362 |
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
|
| 435 |
################################
|
| 436 |
if st.session_state['active_card'] == 'card3':
|
|
@@ -466,6 +466,11 @@ if st.session_state['active_card'] == 'card3':
|
|
| 466 |
|
| 467 |
# Drop rows where PE_Coeff is NaN (optional)
|
| 468 |
agg_df_filtered = agg_df_filtered.dropna(subset=['PE_Coeff'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
st.dataframe(agg_df_filtered)
|
| 470 |
st.write(agg_df_filtered.shape)
|
| 471 |
# Extract values for the current and previous years from row 1 and row 2 of the dataframe
|
|
@@ -485,25 +490,53 @@ if st.session_state['active_card'] == 'card3':
|
|
| 485 |
# Calculate PE Coefficient
|
| 486 |
pe_coeff = sales_volume_pct / unit_price_pct
|
| 487 |
|
| 488 |
-
|
| 489 |
st.latex(rf"""
|
| 490 |
-
\text{{Unit Price \% Change}} = \frac{{
|
| 491 |
""")
|
| 492 |
|
|
|
|
| 493 |
st.latex(rf"""
|
| 494 |
-
\text{{Sales Volume \% Change}} = \frac{{
|
| 495 |
""")
|
| 496 |
|
|
|
|
| 497 |
st.latex(rf"""
|
| 498 |
-
\text{{PE Coefficient}} = \frac{{
|
| 499 |
""")
|
| 500 |
-
|
|
|
|
| 501 |
st.markdown(f"""
|
| 502 |
-
###
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
# Plot the PE Coefficient with Plotly
|
| 508 |
fig = px.line(
|
| 509 |
agg_df_filtered,
|
|
|
|
| 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 |
}
|
| 57 |
|
|
|
|
| 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, col3 = st.columns(2)
|
| 118 |
with col1:
|
| 119 |
if st.button("Sales Volume Trend"):
|
| 120 |
st.session_state['active_card'] = 'card1'
|
|
|
|
| 124 |
st.session_state['selected_itemtype'] = None
|
| 125 |
st.session_state['selected_containercode'] = None
|
| 126 |
|
| 127 |
+
# with col2:
|
| 128 |
+
# if st.button("Sales Volume vs Median Unit Price Trend"):
|
| 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("Price Elasticity Coefficient Trend YoY"):
|
|
|
|
| 327 |
|
| 328 |
|
| 329 |
########################################### CARD #2 ####################################################
|
| 330 |
+
# if st.session_state['active_card'] == 'card2':
|
| 331 |
+
# # Identify the top 10 Itemtypes based on total SalesVolume
|
| 332 |
+
# top_10_itemtypes = df.groupby('Itemtype')['SalesVolume'].sum().nlargest(10).index
|
| 333 |
|
| 334 |
+
# # Filter the DataFrame to include only the top 10 Itemtypes
|
| 335 |
+
# df = df[df['Itemtype'].isin(top_10_itemtypes)]
|
| 336 |
+
# # Dropdown to select item type (using session_state)
|
| 337 |
+
# st.session_state['selected_item_type'] = st.selectbox(
|
| 338 |
+
# 'Select Item Type', df['Itemtype'].unique(),
|
| 339 |
+
# index=list(df['Itemtype'].unique()).index(st.session_state['selected_item_type']))
|
| 340 |
|
| 341 |
+
# # Dropdown to select the grouping category (container code, chain code, or state)
|
| 342 |
+
# group_by_option = st.selectbox('Group by', ['Containercode', 'Chaincode', 'State','Region'])
|
| 343 |
|
| 344 |
+
# # Multi-select checkbox to select multiple years
|
| 345 |
+
# selected_years = st.multiselect('Select Year(s)', [2021, 2022, 2023, 2024], default=[2021])
|
| 346 |
|
| 347 |
+
# st.subheader(f"Sales Volume & Unit Price Correlation for {group_by_option} in {', '.join(map(str, selected_years))}")
|
| 348 |
|
| 349 |
+
# # Convert 'Dt' column to datetime
|
| 350 |
+
# df['Dt'] = pd.to_datetime(df['Dt'], errors='coerce')
|
| 351 |
+
# df['Promo'] = np.where(df['Dt'].dt.month.astype(str).isin(['3', '4', '5', '6']), 'Promo', 'NoPromo')
|
| 352 |
+
# df["Promo"] = df["Promo"].astype("category")
|
| 353 |
|
| 354 |
+
# # Filter the dataframe based on the selected item type and selected years
|
| 355 |
+
# filtered_df = df[(df['Itemtype'] == st.session_state['selected_item_type']) & (df['Dt'].dt.year.isin(selected_years))]
|
| 356 |
|
| 357 |
+
# # Find the top 3 values based on total SalesVolume in the selected grouping category
|
| 358 |
+
# top_3_values = filtered_df.groupby(group_by_option, observed=True)['SalesVolume'].sum().nlargest(3).index
|
| 359 |
|
| 360 |
+
# # Filter the data for only the top 3 values
|
| 361 |
+
# top_group_data = filtered_df[filtered_df[group_by_option].isin(top_3_values)]
|
| 362 |
|
| 363 |
+
# # Aggregate data
|
| 364 |
+
# agg_df = top_group_data.groupby([group_by_option, 'Year', 'Week', 'Dt'], observed=True).agg({
|
| 365 |
+
# 'SalesVolume': 'sum',
|
| 366 |
+
# 'UnitPrice': 'mean'
|
| 367 |
+
# }).reset_index()
|
| 368 |
+
|
| 369 |
+
# # Create a new column 'week-year' for X-axis labels
|
| 370 |
+
# agg_df['week-year'] = agg_df['Dt'].dt.strftime('%U-%Y')
|
| 371 |
+
|
| 372 |
+
# # Loop through the top 3 values and create separate plots using Plotly
|
| 373 |
+
# for value in top_3_values:
|
| 374 |
+
# value_data = agg_df[agg_df[group_by_option] == value]
|
| 375 |
+
# # Assuming you have 'value_data' from your previous code
|
| 376 |
+
# mean_sales_volume = value_data['SalesVolume'].mean()
|
| 377 |
+
# mean_unit_price = value_data['UnitPrice'].mean()
|
| 378 |
+
|
| 379 |
+
# # Create a Plotly figure
|
| 380 |
+
# fig = go.Figure()
|
| 381 |
+
|
| 382 |
+
# # Add SalesVolume trace
|
| 383 |
+
# fig.add_trace(go.Scatter(
|
| 384 |
+
# x=value_data['week-year'],
|
| 385 |
+
# y=value_data['SalesVolume'],
|
| 386 |
+
# mode='lines+markers',
|
| 387 |
+
# name='SalesVolume',
|
| 388 |
+
# line=dict(color='blue'),
|
| 389 |
+
# hovertemplate='SalesVolume: %{y}<br>Week-Year: %{x}'
|
| 390 |
+
# ))
|
| 391 |
+
|
| 392 |
+
# # Add UnitPrice trace on a secondary Y-axis
|
| 393 |
+
# fig.add_trace(go.Scatter(
|
| 394 |
+
# x=value_data['week-year'],
|
| 395 |
+
# y=value_data['UnitPrice'],
|
| 396 |
+
# mode='lines+markers',
|
| 397 |
+
# name='UnitPrice',
|
| 398 |
+
# line=dict(color='green'),
|
| 399 |
+
# yaxis='y2',
|
| 400 |
+
# hovertemplate='UnitPrice: %{y}<br>Week-Year: %{x}'
|
| 401 |
+
# ))
|
| 402 |
+
# # Add mean line for SalesVolume
|
| 403 |
+
# fig.add_shape(type="line",
|
| 404 |
+
# x0=value_data['week-year'].min(), x1=value_data['week-year'].max(),
|
| 405 |
+
# y0=mean_sales_volume, y1=mean_sales_volume,
|
| 406 |
+
# line=dict(color="blue", width=2, dash="dash"),
|
| 407 |
+
# xref='x', yref='y')
|
| 408 |
+
|
| 409 |
+
# # Add mean line for UnitPrice (on secondary Y-axis)
|
| 410 |
+
# fig.add_shape(type="line",
|
| 411 |
+
# x0=value_data['week-year'].min(), x1=value_data['week-year'].max(),
|
| 412 |
+
# y0=mean_unit_price, y1=mean_unit_price,
|
| 413 |
+
# line=dict(color="green", width=2, dash="dash"),
|
| 414 |
+
# xref='x', yref='y2')
|
| 415 |
+
|
| 416 |
+
# # Update layout for dual axes
|
| 417 |
+
# fig.update_layout(
|
| 418 |
+
# template='plotly_white',
|
| 419 |
+
# title=f"SalesVolume and UnitPrice - {value} ({group_by_option})",
|
| 420 |
+
# xaxis_title='Week-Year',
|
| 421 |
+
# yaxis_title='Sales Volume',
|
| 422 |
+
# yaxis2=dict(title='UnitPrice', overlaying='y', side='right'),
|
| 423 |
+
# legend=dict(x=0.9, y=1.15),
|
| 424 |
+
# hovermode="x unified", # Show both values in a tooltip
|
| 425 |
+
# height=600,
|
| 426 |
+
# margin=dict(l=50, r=50, t=50, b=50)
|
| 427 |
+
# )
|
| 428 |
+
|
| 429 |
+
# # Rotate X-axis labels
|
| 430 |
+
# fig.update_xaxes(tickangle=90)
|
| 431 |
+
|
| 432 |
+
# # Display the Plotly figure in Streamlit
|
| 433 |
+
# st.plotly_chart(fig, use_container_width=True)
|
| 434 |
|
| 435 |
################################
|
| 436 |
if st.session_state['active_card'] == 'card3':
|
|
|
|
| 466 |
|
| 467 |
# Drop rows where PE_Coeff is NaN (optional)
|
| 468 |
agg_df_filtered = agg_df_filtered.dropna(subset=['PE_Coeff'])
|
| 469 |
+
agg_df_filtered = agg_df_filtered.rename(columns={
|
| 470 |
+
'SalesVolume_pct_change': 'SlVol%change',
|
| 471 |
+
'UnitPrice_pct_change': 'UnPr%change',
|
| 472 |
+
})
|
| 473 |
+
agg_df_filtered = agg_df_filtered.reset_index(drop=True)
|
| 474 |
st.dataframe(agg_df_filtered)
|
| 475 |
st.write(agg_df_filtered.shape)
|
| 476 |
# Extract values for the current and previous years from row 1 and row 2 of the dataframe
|
|
|
|
| 490 |
# Calculate PE Coefficient
|
| 491 |
pe_coeff = sales_volume_pct / unit_price_pct
|
| 492 |
|
| 493 |
+
st.markdown(f'''### Calculations for Price Elasticity Coefficient''')
|
| 494 |
st.latex(rf"""
|
| 495 |
+
\text{{Unit Price \% Change}} = \frac{{{unit_price_current_year:.2f} - {unit_price_previous_year:.2f}}}{{{unit_price_previous_year:.2f}}} \times 100 = {unit_price_pct:.2f}\%
|
| 496 |
""")
|
| 497 |
|
| 498 |
+
# Sales Volume % Change
|
| 499 |
st.latex(rf"""
|
| 500 |
+
\text{{Sales Volume \% Change}} = \frac{{{sales_volume_current_year:.2f} - {sales_volume_previous_year:.2f}}}{{{sales_volume_previous_year:.2f}}} \times 100 = {sales_volume_pct:.2f}\%
|
| 501 |
""")
|
| 502 |
|
| 503 |
+
# PE Coefficient
|
| 504 |
st.latex(rf"""
|
| 505 |
+
\text{{PE Coefficient}} = \frac{{{sales_volume_pct:.2f}}}{{{unit_price_pct:.2f}}} = {pe_coeff:.2f}
|
| 506 |
""")
|
| 507 |
+
|
| 508 |
+
# Explanation for PE Coefficient Conditions
|
| 509 |
st.markdown(f"""
|
| 510 |
+
### Interpretation of Price Elasticity (PE) Coefficient:
|
| 511 |
+
The Price Elasticity (PE) coefficient reflects how sensitive sales volume is to changes in unit price.
|
| 512 |
+
|
| 513 |
+
- If the **PE coefficient is positive**:
|
| 514 |
+
1. When the price increases, sales volume increases.
|
| 515 |
+
2. When the price decreases, sales volume decreases.
|
| 516 |
+
|
| 517 |
+
- If the **PE coefficient is negative**:
|
| 518 |
+
1. When the price increases, sales volume decreases.
|
| 519 |
+
2. When the price decreases, sales volume increases.
|
| 520 |
+
|
| 521 |
""")
|
| 522 |
+
|
| 523 |
+
# Dynamic analysis based on the calculated PE coefficient and signs of changes
|
| 524 |
+
if unit_price_pct > 0 and sales_volume_pct > 0:
|
| 525 |
+
st.warning(f"""
|
| 526 |
+
Both unit price and sales volume increased (refer first and second row of the table). The PE coefficient of **{pe_coeff:.2f}** indicates that for every 1% increase in unit price, sales volume increased by approximately **{pe_coeff:.2f}%**.
|
| 527 |
+
""")
|
| 528 |
+
elif unit_price_pct < 0 and sales_volume_pct < 0:
|
| 529 |
+
st.warning(f"""
|
| 530 |
+
Both unit price and sales volume decreased (refer first and second row of the table). The PE coefficient of **{pe_coeff:.2f}** suggests that for every 1% decrease in unit price, sales volume decreased by approximately **{pe_coeff:.2f}%**.
|
| 531 |
+
""")
|
| 532 |
+
elif unit_price_pct > 0 and sales_volume_pct < 0:
|
| 533 |
+
st.warning(f"""
|
| 534 |
+
The unit price increased while sales volume decreased (refer first and second row of the table). The negative PE coefficient of **{pe_coeff:.2f}** means that for every 1% increase in unit price, sales volume fell by approximately **{abs(pe_coeff):.2f}%**.
|
| 535 |
+
""")
|
| 536 |
+
elif unit_price_pct < 0 and sales_volume_pct > 0:
|
| 537 |
+
st.warning(f"""
|
| 538 |
+
The unit price decreased while sales volume increased (refer first and second row of the table). The negative PE coefficient of **{pe_coeff:.2f}** implies that for every 1% decrease in unit price, sales volume increased by approximately **{abs(pe_coeff):.2f}%**.
|
| 539 |
+
""")
|
| 540 |
# Plot the PE Coefficient with Plotly
|
| 541 |
fig = px.line(
|
| 542 |
agg_df_filtered,
|