ProtonDataLabs commited on
Commit
ba7f8df
1 Parent(s): 2a243f7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -114
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, col2, col3 = st.columns(3)
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
- 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,110 +327,110 @@ if st.session_state['active_card'] == 'card1':
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,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
- # Render LaTeX formulas with dynamic values using st.latex
489
  st.latex(rf"""
490
- \text{{Unit Price \% Change}} = \frac{{\text{{Unit Price in Current Year}} - \text{{Unit Price in Previous Year}}}}{{\text{{Unit Price in Previous Year}}}} \times 100 = \frac{{{unit_price_current_year:.2f} - {unit_price_previous_year:.2f}}}{{{unit_price_previous_year:.2f}}} \times 100 = {unit_price_pct:.2f}\%
491
  """)
492
 
 
493
  st.latex(rf"""
494
- \text{{Sales Volume \% Change}} = \frac{{\text{{Sales Volume in Current Year}} - \text{{Sales Volume in Previous Year}}}}{{\text{{Sales Volume in Previous Year}}}} \times 100 = \frac{{{sales_volume_current_year:.2f} - {sales_volume_previous_year:.2f}}}{{{sales_volume_previous_year:.2f}}} \times 100 = {sales_volume_pct:.2f}\%
495
  """)
496
 
 
497
  st.latex(rf"""
498
- \text{{PE Coefficient}} = \frac{{\text{{Sales Volume \% Change}}}}{{\text{{Unit Price \% Change}}}} = \frac{{{sales_volume_pct:.2f}}}{{{unit_price_pct:.2f}}} = {pe_coeff:.2f}
499
  """)
500
- # Explanation Text
 
501
  st.markdown(f"""
502
- ### Explanation of Calculations (for {current_year_row['Region']}, {current_year_row['Itemtype']}, FY {current_year_row['Fy']}):
503
- - **Unit Price Percentage Change**: The percentage change in unit price YOY. For FY {current_year_row['Fy']}, the unit price changed by **{unit_price_pct:.2f}%**.
504
- - **Sales Volume Percentage Change**: The percentage change in sales volume YOY. For FY {current_year_row['Fy']}, the sales volume changed by **{sales_volume_pct:.2f}%**.
505
- - **Price Elasticity (PE) Coefficient**: The PE coefficient for FY {current_year_row['Fy']} is **{pe_coeff:.2f}**.
 
 
 
 
 
 
 
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,