Samkeet-Blend360 commited on
Commit
e8d72c9
·
1 Parent(s): 53c950b
Streamlit_functions.py CHANGED
@@ -154,8 +154,9 @@ def pie_charts(start_date,end_date):
154
  hoverinfo='label+percent',
155
  textinfo= 'label+percent',
156
  showlegend= False,textfont=dict(size =10),
157
- title="Distribution of Spends"
158
- , marker=dict(colors=colors)
 
159
  ), 1, 1)
160
 
161
  fig.add_trace(go.Pie(labels=channels,
@@ -165,7 +166,8 @@ def pie_charts(start_date,end_date):
165
  textinfo= 'label+percent',
166
  showlegend= False,
167
  textfont=dict(size = 10),
168
- title = "Distribution of Revenue Contributions", marker=dict(colors=colors)
 
169
  ), 1, 2)
170
  # fig.update_layout(
171
  # title="Distribution Of Spends And Revenue Contributions"
@@ -261,69 +263,73 @@ def pie_spend(start_date,end_date):
261
 
262
  # Show the figure
263
  return fig
264
- def pie_contributions(start_date,end_date):
265
- colors = ['#ff2b2b', # Pastel Peach
266
- '#0068c9', # Pastel Blue
267
- '#83c9ff', # Pastel Pink
 
268
 
269
- '#ffabab', # Pastel Purple
270
- '#29b09d', # Pastel Green
271
- '#7defa1', # Pastel Yellow
272
- '#ff8700', # Pastel Gray
273
- '#ffd16a', # Pastel Red
274
- '#6d3fc0', # Pastel Rose
275
- '#d5dae5', # Pastel Lavender
276
- '#309bff', # Pastel Mauve
277
- '#e9f5ff', # Pastel Beige
278
- '#BEBADA' # Pastel Lilac
279
- ]
280
- start_date = pd.to_datetime(start_date)
281
- end_date = pd.to_datetime(end_date)
282
- cur_data = df[(df['Date'] >= start_date) & (df['Date'] <= end_date)]
283
- data = pd.DataFrame(cur_data[contribution_cols].sum().transpose())
284
- data.index = channels
285
- data.columns = ["p"]
286
- # Create a pie chart with custom options
287
- fig = go.Figure(data=[go.Pie(
288
- labels=channels,
289
- values=data["p"],#ype(str)+'<br>'+data.index,
290
- hoverinfo='label+percent',
291
- textinfo= 'label+percent',
292
- textposition='auto',
293
- showlegend= False,
294
- textfont=dict(size = 10)
295
- , marker=dict(colors=colors)
296
- )])
297
 
298
- # fig.add_annotation(showarrow=False)
299
- # Customize the layout
300
- fig.update_layout(
301
- # title="Distribution Of Contributions",
302
- title={
303
- 'text': "Distribution of Revenue",
304
- 'font': {
305
- 'size': 24,
306
- 'family': 'Arial',
307
- 'color': 'black',
308
- # 'bold': True
309
- }
310
- }
311
- # margin=dict(t=0, b=0, l=0, r=0)
312
- )
313
 
314
- fig.add_annotation(
315
- text=f"{start_date.strftime('%m-%d-%Y')} to {end_date.strftime('%m-%d-%Y')}",
316
- x=0,
317
- y=1.15,
318
- xref="x domain",
319
- yref="y domain",
320
- showarrow=False,
321
- font=dict(size=18),
322
- # align='left'
323
- )
 
 
 
 
 
324
 
325
- # Show the figure
326
- return fig
327
  def waterfall2(start_date1,end_date1,start_date2,end_date2):
328
  btn_chart = "Month on Month"
329
  # if pd.isnull(start_date) == True :
@@ -356,21 +362,21 @@ def waterfall2(start_date1,end_date1,start_date2,end_date2):
356
 
357
  # Example data for the waterfall chart
358
  data = [
359
- {'label': 'Previous Period', 'value': round(prev_data[contribution_cols].values.sum())},
360
- {'label': 'Broadcast TV', 'value': round(cur_data['Broadcast TV_Prospects'].sum()-prev_data['Broadcast TV_Prospects'].sum())},
361
  {'label': 'Cable TV', 'value': round(cur_data['Cable TV_Prospects'].sum()-prev_data['Cable TV_Prospects'].sum())},
362
- {'label': 'Connected & OTT TV', 'value': round(cur_data['Connected & OTT TV_Prospects'].sum()-prev_data['Connected & OTT TV_Prospects'].sum())},
363
- {'label': 'Video', 'value': round(cur_data['Video_Prospects'].sum()-prev_data['Video_Prospects'].sum())},
364
- {'label': 'Display Prospecting', 'value': round(cur_data['Display Prospecting_Prospects'].sum()-prev_data['Display Prospecting_Prospects'].sum())},
365
- {'label': 'Display Retargeting', 'value': round(cur_data['Display Retargeting_Prospects'].sum()-prev_data['Display Retargeting_Prospects'].sum())},
366
- {'label': 'Social Prospecting', 'value': round(cur_data['Social Prospecting_Prospects'].sum()-prev_data['Social Prospecting_Prospects'].sum())},
367
- {'label': 'Social Retargeting', 'value': round(cur_data['Social Retargeting_Prospects'].sum()-prev_data['Social Retargeting_Prospects'].sum())},
368
- {'label': 'Search Brand', 'value': round(cur_data['Search Brand_Prospects'].sum()-prev_data['Search Brand_Prospects'].sum())},
369
- {'label': 'Search Non-brand', 'value': round(cur_data['Search Non-brand_Prospects'].sum()-prev_data['Search Non-brand_Prospects'].sum())},
370
- {'label': 'Digital Partners', 'value': round(cur_data['Digital Partners_Prospects'].sum()-prev_data['Digital Partners_Prospects'].sum())},
371
- {'label': 'Audio', 'value': round(cur_data['Audio_Prospects'].sum()-prev_data['Audio_Prospects'].sum())},
372
- {'label': 'Email', 'value': round(cur_data['Email_Prospects'].sum()-prev_data['Email_Prospects'].sum())},
373
- {'label': 'Current Period', 'value': round(cur_data[contribution_cols].values.sum())}
374
  ]
375
 
376
  # Calculate cumulative values for the waterfall chart
@@ -953,10 +959,10 @@ def shares_table_func(shares_df):
953
  shares_table_df = shares_df[["channels","cur_spend_share","cur_support_share","cur_contributions_share"]].copy()
954
 
955
  # Calculating ROI as Revenue Contribution / Spends
956
- shares_table_df["ROI"] = (shares_df["cur_contributions_share"] / shares_df["cur_spend_share"]).round(2)
957
 
958
  # Calculating Effectiveness as Revenue Contribution * 1,000,000 / Support
959
- shares_table_df["Effectiveness"] = (shares_df["cur_contributions_share"] * 1_000_000 / shares_df["cur_support_share"]).round(2)
960
 
961
  shares_table_df = shares_table_df.rename(columns = {"channels":"METRIC",
962
  "cur_spend_share":"Spend Share",
 
154
  hoverinfo='label+percent',
155
  textinfo= 'label+percent',
156
  showlegend= False,textfont=dict(size =10),
157
+ title="Distribution of Spends",
158
+ texttemplate='%{label}: %{percent:.1%}',
159
+ marker=dict(colors=colors)
160
  ), 1, 1)
161
 
162
  fig.add_trace(go.Pie(labels=channels,
 
166
  textinfo= 'label+percent',
167
  showlegend= False,
168
  textfont=dict(size = 10),
169
+ title = "Distribution of Revenue Contributions", marker=dict(colors=colors),
170
+ texttemplate='%{label}: %{percent:.1%}',
171
  ), 1, 2)
172
  # fig.update_layout(
173
  # title="Distribution Of Spends And Revenue Contributions"
 
263
 
264
  # Show the figure
265
  return fig
266
+
267
+ # def pie_contributions(start_date,end_date):
268
+ # colors = ['#ff2b2b', # Pastel Peach
269
+ # '#0068c9', # Pastel Blue
270
+ # '#83c9ff', # Pastel Pink
271
 
272
+ # '#ffabab', # Pastel Purple
273
+ # '#29b09d', # Pastel Green
274
+ # '#7defa1', # Pastel Yellow
275
+ # '#ff8700', # Pastel Gray
276
+ # '#ffd16a', # Pastel Red
277
+ # '#6d3fc0', # Pastel Rose
278
+ # '#d5dae5', # Pastel Lavender
279
+ # '#309bff', # Pastel Mauve
280
+ # '#e9f5ff', # Pastel Beige
281
+ # '#BEBADA' # Pastel Lilac
282
+ # ]
283
+ # start_date = pd.to_datetime(start_date)
284
+ # end_date = pd.to_datetime(end_date)
285
+ # cur_data = df[(df['Date'] >= start_date) & (df['Date'] <= end_date)]
286
+ # data = pd.DataFrame(cur_data[contribution_cols].sum().transpose())
287
+ # data.index = channels
288
+ # data.columns = ["p"]
289
+ # # Create a pie chart with custom options
290
+ # fig = go.Figure(data=[go.Pie(
291
+ # labels=channels,
292
+ # values=data["p"],#ype(str)+'<br>'+data.index,
293
+ # hoverinfo='label+percent',
294
+ # textinfo= 'label+percent',
295
+ # textposition='auto',
296
+ # showlegend= False,
297
+ # textfont=dict(size = 10)
298
+ # , marker=dict(colors=colors)
299
+ # )])
300
 
301
+ # # fig.add_annotation(showarrow=False)
302
+ # # Customize the layout
303
+ # fig.update_layout(
304
+ # # title="Distribution Of Contributions",
305
+ # title={
306
+ # 'text': "Distribution of Revenue",
307
+ # 'font': {
308
+ # 'size': 24,
309
+ # 'family': 'Arial',
310
+ # 'color': 'black',
311
+ # # 'bold': True
312
+ # }
313
+ # }
314
+ # # margin=dict(t=0, b=0, l=0, r=0)
315
+ # )
316
 
317
+ # fig.add_annotation(
318
+ # text=f"{start_date.strftime('%m-%d-%Y')} to {end_date.strftime('%m-%d-%Y')}",
319
+ # x=0,
320
+ # y=1.15,
321
+ # xref="x domain",
322
+ # yref="y domain",
323
+ # showarrow=False,
324
+ # font=dict(size=18),
325
+ # # align='left'
326
+ # )
327
+
328
+ # # Show the figure
329
+ # return fig
330
+
331
+
332
 
 
 
333
  def waterfall2(start_date1,end_date1,start_date2,end_date2):
334
  btn_chart = "Month on Month"
335
  # if pd.isnull(start_date) == True :
 
362
 
363
  # Example data for the waterfall chart
364
  data = [
365
+ {'label': 'Previous Period', 'value': round(prev_data[contribution_cols].values.sum(), 1)},
366
+ {'label': 'Broadcast TV', 'value': round(cur_data['Broadcast TV_Prospects'].sum()-prev_data['Broadcast TV_Prospects'].sum(), 1)},
367
  {'label': 'Cable TV', 'value': round(cur_data['Cable TV_Prospects'].sum()-prev_data['Cable TV_Prospects'].sum())},
368
+ {'label': 'Connected & OTT TV', 'value': round(cur_data['Connected & OTT TV_Prospects'].sum()-prev_data['Connected & OTT TV_Prospects'].sum(), 1)},
369
+ {'label': 'Video', 'value': round(cur_data['Video_Prospects'].sum()-prev_data['Video_Prospects'].sum(), 1)},
370
+ {'label': 'Display Prospecting', 'value': round(cur_data['Display Prospecting_Prospects'].sum()-prev_data['Display Prospecting_Prospects'].sum(), 1)},
371
+ {'label': 'Display Retargeting', 'value': round(cur_data['Display Retargeting_Prospects'].sum()-prev_data['Display Retargeting_Prospects'].sum(), 1)},
372
+ {'label': 'Social Prospecting', 'value': round(cur_data['Social Prospecting_Prospects'].sum()-prev_data['Social Prospecting_Prospects'].sum(), 1)},
373
+ {'label': 'Social Retargeting', 'value': round(cur_data['Social Retargeting_Prospects'].sum()-prev_data['Social Retargeting_Prospects'].sum(), 1)},
374
+ {'label': 'Search Brand', 'value': round(cur_data['Search Brand_Prospects'].sum()-prev_data['Search Brand_Prospects'].sum(), 1)},
375
+ {'label': 'Search Non-brand', 'value': round(cur_data['Search Non-brand_Prospects'].sum()-prev_data['Search Non-brand_Prospects'].sum(), 1)},
376
+ {'label': 'Digital Partners', 'value': round(cur_data['Digital Partners_Prospects'].sum()-prev_data['Digital Partners_Prospects'].sum(), 1)},
377
+ {'label': 'Audio', 'value': round(cur_data['Audio_Prospects'].sum()-prev_data['Audio_Prospects'].sum(), 1)},
378
+ {'label': 'Email', 'value': round(cur_data['Email_Prospects'].sum()-prev_data['Email_Prospects'].sum(), 1)},
379
+ {'label': 'Current Period', 'value': round(cur_data[contribution_cols].values.sum(), 1)}
380
  ]
381
 
382
  # Calculate cumulative values for the waterfall chart
 
959
  shares_table_df = shares_df[["channels","cur_spend_share","cur_support_share","cur_contributions_share"]].copy()
960
 
961
  # Calculating ROI as Revenue Contribution / Spends
962
+ shares_table_df["ROI"] = (shares_df["cur_total_contributions"] / shares_df["cur_total_spend"]).round(1)
963
 
964
  # Calculating Effectiveness as Revenue Contribution * 1,000,000 / Support
965
+ shares_table_df["Effectiveness"] = (shares_df["cur_contributions_share"] * 1000 / shares_df["cur_support_share"]).round(1)
966
 
967
  shares_table_df = shares_table_df.rename(columns = {"channels":"METRIC",
968
  "cur_spend_share":"Spend Share",
__pycache__/Streamlit_functions.cpython-310.pyc CHANGED
Binary files a/__pycache__/Streamlit_functions.cpython-310.pyc and b/__pycache__/Streamlit_functions.cpython-310.pyc differ
 
__pycache__/classes.cpython-310.pyc CHANGED
Binary files a/__pycache__/classes.cpython-310.pyc and b/__pycache__/classes.cpython-310.pyc differ
 
classes.py CHANGED
@@ -123,6 +123,7 @@ class Channel:
123
 
124
  def hill_equation(x, Kd, n):
125
  return x**n / (Kd**n + x**n)
 
126
  def response_curve(self, x):
127
  # # # # print(x)
128
  # if self.penalty:
@@ -132,6 +133,7 @@ class Channel:
132
  # x,
133
  # self.upper_limit + (x - self.upper_limit) * self.upper_limit / x,
134
  # )
 
135
  if self.response_curve_type == "hill-eq":
136
  # dividing_parameter = check_dividing_parameter()
137
  # # # # print("lalala")
@@ -139,12 +141,14 @@ class Channel:
139
  # # # # print(len(x))
140
  # # # # print("in response curve function")
141
  # # # # print(x)
 
142
  if len(x) == 1:
143
- dividing_rate = self.response_curve_params["num_pos_obsv"]
144
  # # # # print(dividing_rate)
145
  # x = np.sum(x)
146
  else:
147
- dividing_rate = 1
 
148
  # dividing_rate = self.response_curve_params["num_pos_obsv"]
149
  # x = np.sum(x)
150
  # dividing_rate = 104
@@ -158,13 +162,12 @@ class Channel:
158
  # # # # # print(x_min)
159
  # # # # # print(Kd,n,x_min,x_max,y_min,y_max)
160
  # # # # # print(np.sum(x)/104)
161
- x_inp = ( x/dividing_rate- x_min) / (x_max - x_min)
162
  # # # # # print("x",x)
163
  # # # # # print("x_inp",x_inp)
164
  x_out = x_inp**n / (Kd**n + x_inp**n) #self.hill_equation(x_inp,Kd, n)
165
  # # # # # print("x_out",x_out)
166
 
167
-
168
  x_val_inv = (x_out*x_max + (1 - x_out) * x_min)
169
  sales = (x_val_inv*y_min/y_max)*dividing_rate
170
  # sales = ((x_max - x_min)*x_out + x_min)*dividing_rate
@@ -364,9 +367,10 @@ class Scenario:
364
 
365
 
366
 
367
-
368
 
369
  def optimize_spends(self, sales_percent, channels_list, algo="trust-constr"):
 
370
  num_channels = len(channels_list)
371
  # # # # # print("%"*100)
372
  desired_sales = self.actual_total_sales * (1 + sales_percent / 100.0)
@@ -404,14 +408,14 @@ class Scenario:
404
  constraints = [NonlinearConstraint(constraint, -1.0, 1.0),
405
  # LinearConstraint(np.ones((num_channels,)), lb = -50*calc_overall_bounds(channels_list), ub = 50*calc_overall_bounds(channels_list))
406
  ]
407
-
408
  res = minimize(
409
  lambda x: sum(x) / 10 ** (power),
410
  bounds=bounds,
411
  x0=initial_point,
412
  constraints=constraints,
413
  method=algo,
414
- options={"maxiter": int(2e7), "xtol": 10},
415
  )
416
 
417
  for channel_name, modified_spends in zip(channels_list, res.x):
@@ -452,8 +456,27 @@ class Scenario:
452
  # )
453
  old_spends.append(channel_actual_total_spends)
454
  # bounds.append((1+ channel_bounds / 100) * channel_actual_total_spends)
455
- lb = (1- int(_channel_class.channel_bounds_min) / 100) * _channel_class.actual_total_spends
456
- ub = (1+ int(_channel_class.channel_bounds_max) / 100) * _channel_class.actual_total_spends
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
  bounds.append((lb,ub))
458
  # # # # print("aaaaaa")
459
  # # # print((_channel_class.channel_bounds_max,_channel_class.channel_bounds_min))
@@ -500,7 +523,7 @@ class Scenario:
500
  x0=old_spends,
501
  constraints=constraint,
502
  bounds=bounds,
503
- options={"maxiter": int(1e7), "xtol": 0.1},
504
  )
505
 
506
  for channel_name, modified_spends in zip(channels_list, res.x):
 
123
 
124
  def hill_equation(x, Kd, n):
125
  return x**n / (Kd**n + x**n)
126
+
127
  def response_curve(self, x):
128
  # # # # print(x)
129
  # if self.penalty:
 
133
  # x,
134
  # self.upper_limit + (x - self.upper_limit) * self.upper_limit / x,
135
  # )
136
+
137
  if self.response_curve_type == "hill-eq":
138
  # dividing_parameter = check_dividing_parameter()
139
  # # # # print("lalala")
 
141
  # # # # print(len(x))
142
  # # # # print("in response curve function")
143
  # # # # print(x)
144
+
145
  if len(x) == 1:
146
+ dividing_rate = 1
147
  # # # # print(dividing_rate)
148
  # x = np.sum(x)
149
  else:
150
+ dividing_rate = self.response_curve_params["num_pos_obsv"]
151
+
152
  # dividing_rate = self.response_curve_params["num_pos_obsv"]
153
  # x = np.sum(x)
154
  # dividing_rate = 104
 
162
  # # # # # print(x_min)
163
  # # # # # print(Kd,n,x_min,x_max,y_min,y_max)
164
  # # # # # print(np.sum(x)/104)
165
+ x_inp = ( (x/dividing_rate) - x_min) / (x_max - x_min)
166
  # # # # # print("x",x)
167
  # # # # # print("x_inp",x_inp)
168
  x_out = x_inp**n / (Kd**n + x_inp**n) #self.hill_equation(x_inp,Kd, n)
169
  # # # # # print("x_out",x_out)
170
 
 
171
  x_val_inv = (x_out*x_max + (1 - x_out) * x_min)
172
  sales = (x_val_inv*y_min/y_max)*dividing_rate
173
  # sales = ((x_max - x_min)*x_out + x_min)*dividing_rate
 
367
 
368
 
369
 
370
+
371
 
372
  def optimize_spends(self, sales_percent, channels_list, algo="trust-constr"):
373
+ import streamlit as st
374
  num_channels = len(channels_list)
375
  # # # # # print("%"*100)
376
  desired_sales = self.actual_total_sales * (1 + sales_percent / 100.0)
 
408
  constraints = [NonlinearConstraint(constraint, -1.0, 1.0),
409
  # LinearConstraint(np.ones((num_channels,)), lb = -50*calc_overall_bounds(channels_list), ub = 50*calc_overall_bounds(channels_list))
410
  ]
411
+
412
  res = minimize(
413
  lambda x: sum(x) / 10 ** (power),
414
  bounds=bounds,
415
  x0=initial_point,
416
  constraints=constraints,
417
  method=algo,
418
+ options={"maxiter": int(1e5), "xtol": 1000},
419
  )
420
 
421
  for channel_name, modified_spends in zip(channels_list, res.x):
 
456
  # )
457
  old_spends.append(channel_actual_total_spends)
458
  # bounds.append((1+ channel_bounds / 100) * channel_actual_total_spends)
459
+
460
+ # lb = (1- int(_channel_class.channel_bounds_min) / 100) * _channel_class.actual_total_spends
461
+ # ub = (1+ int(_channel_class.channel_bounds_max) / 100) * _channel_class.actual_total_spends
462
+
463
+ import streamlit as st
464
+
465
+ if "overall_lower_bound" in st.session_state:
466
+ try:
467
+ lower_val = float(st.session_state["overall_lower_bound"])
468
+ except (ValueError, TypeError):
469
+ lower_val = 30.0
470
+
471
+ if "overall_upper_bound" in st.session_state:
472
+ try:
473
+ upper_val = float(st.session_state["overall_upper_bound"])
474
+ except (ValueError, TypeError):
475
+ upper_val = 30.0
476
+
477
+ lb = (1 - float(lower_val) / 100) * _channel_class.actual_total_spends
478
+ ub = (1 + float(upper_val) / 100) * _channel_class.actual_total_spends
479
+
480
  bounds.append((lb,ub))
481
  # # # # print("aaaaaa")
482
  # # # print((_channel_class.channel_bounds_max,_channel_class.channel_bounds_min))
 
523
  x0=old_spends,
524
  constraints=constraint,
525
  bounds=bounds,
526
+ options={"maxiter": int(1e7), "xtol": 100},
527
  )
528
 
529
  for channel_name, modified_spends in zip(channels_list, res.x):
pages/2_Scenario_Planner.py CHANGED
@@ -359,15 +359,33 @@ def update_all_spends_abs():
359
 
360
  actual_spends = _scenario.actual_total_spends
361
  if (
362
- validate_input(st.session_state["total_spends_change_abs"])
363
  and st.session_state["allow_spends_update"]
364
  ):
365
  modified_spends = extract_number_for_string(
366
  st.session_state["total_spends_change_abs"]
367
  )
368
- st.session_state["total_spends_change"] = (
369
  (modified_spends / actual_spends) - 1
370
  ) * 100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  st.session_state["total_spends_change_abs_slider"] = st.session_state[
372
  "total_spends_change_abs"
373
  ]
@@ -499,9 +517,29 @@ def update_data(channel_name):
499
  st.session_state["scenario"].channels[channel_name].actual_total_spends
500
  * st.session_state["scenario"].channels[channel_name].conversion_rate
501
  )
502
- st.session_state[f"{channel_name}_change"] = round(
 
 
503
  100 * (modified_spends - prev_spends) / prev_spends, 2
504
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  st.session_state["scenario"].update(
506
  channel_name,
507
  modified_spends
@@ -584,6 +622,13 @@ def reset_scenario(panel_selected, file_selected, updated_rcs):
584
 
585
  st.session_state["total_sales_change"] = 0
586
 
 
 
 
 
 
 
 
587
  update_spends()
588
  update_sales()
589
 
@@ -739,9 +784,10 @@ def plot_response_curves(summary_df_sorted):
739
  summary_df_sorted["Optimized_spend"][channels_list[i]],
740
  summary_df_sorted["New_sales"][channels_list[i]],
741
  )
742
- for i in range(13)
743
  ]
744
 
 
745
  # for i in range()
746
 
747
  # Display figures in a grid layout
@@ -1596,7 +1642,7 @@ if auth_status == True:
1596
  _columns = st.columns((1, 1, 1, 1, 1))
1597
  with _columns[0]:
1598
  # st.header("Prospects")
1599
- st.markdown("""<h4> Revenue</h4>""", unsafe_allow_html=True)
1600
  with _columns[1]:
1601
  st.markdown(
1602
  f"""<h4>$ {header_df["Prospects"]["Actual"]}</h4>""",
@@ -1656,13 +1702,13 @@ if auth_status == True:
1656
  st.markdown("""<h4>ROI</h4>""", unsafe_allow_html=True)
1657
  # st.header("Cost Per Prospect")
1658
  with _columns[1]:
1659
- st.markdown(f"""<h4>{numerize(ef1,0)}</h4>""", unsafe_allow_html=True)
1660
  # st.metric(label="", value='$ '+numerize(ef1,0))
1661
  with _columns[2]:
1662
- st.markdown(f"""<h4>{numerize(ef2,0)}</h4>""", unsafe_allow_html=True)
1663
  # st.metric(label="", value='$ '+numerize(ef2,0))
1664
 
1665
- if ef2 <= ef1:
1666
  st.markdown(
1667
  """
1668
  <style>
@@ -1691,7 +1737,7 @@ if auth_status == True:
1691
 
1692
  # Apply custom styles to text
1693
  st.markdown(
1694
- f'<h4 class="custom-text1">{numerize(ef2-ef1,0)}</h4>',
1695
  unsafe_allow_html=True,
1696
  )
1697
  # st.markdown(f'<p style="color: red;">{st.metric(label="", value=header_df["Prospects"]["Change"])}</p>', unsafe_allow_html=True)
@@ -1701,7 +1747,7 @@ if auth_status == True:
1701
  # st.markdown(f'<p></hr></p>', unsafe_allow_html=True)
1702
  # Apply custom styles to text
1703
  st.markdown(
1704
- f'<h4 class="custom-text1">{round((ef2-ef1)/ef1*100,2)}%</h4>',
1705
  unsafe_allow_html=True,
1706
  )
1707
  st.markdown("""<hr class="spends-child-seperator">""", unsafe_allow_html=True)
@@ -1804,7 +1850,7 @@ if auth_status == True:
1804
  _columns1 = st.columns((1, 1, 1, 1))
1805
  with _columns1[0]:
1806
  optimization_selection = st.selectbox(
1807
- "Optimize", options=["Media Spends", target], key="optimization_key"
1808
  )
1809
 
1810
  with _columns1[1]:
@@ -1845,17 +1891,22 @@ if auth_status == True:
1845
  with _columns2[2]:
1846
  overall_lower_bound = st.number_input(
1847
  "Overall Lower Bound for Spends",
1848
- value=50.0,
 
 
1849
  key="overall_lower_bound",
1850
  # on_change=partial(update_data_bound_min_overall)
1851
  )
1852
  with _columns2[3]:
1853
  overall_upper_bound = st.number_input(
1854
  "Overall Upper Bound for Spends",
1855
- value=50.0,
 
 
1856
  key="overall_upper_bound",
1857
  # on_change=partial(update_data_bound_max_overall)
1858
  )
 
1859
  min_value = round(
1860
  _scenario.actual_total_spends * (1 - overall_lower_bound / 100)
1861
  )
@@ -1876,7 +1927,9 @@ if auth_status == True:
1876
  st.number_input(
1877
  "Percent Change",
1878
  key="total_spends_change",
1879
- min_value=-1 * overall_lower_bound,
 
 
1880
  max_value=overall_upper_bound,
1881
  step=0.01,
1882
  value=0.00,
@@ -1906,7 +1959,7 @@ if auth_status == True:
1906
 
1907
  with _columns2[1]:
1908
  st.number_input(
1909
- "Percent Change",
1910
  key="total_sales_change",
1911
  min_value=-50.00,
1912
  max_value=50.00,
@@ -2001,6 +2054,10 @@ if auth_status == True:
2001
  "Old_sales": [],
2002
  }
2003
  for i, channel_name in enumerate(channels_list):
 
 
 
 
2004
  # st.write(channel_name)
2005
  _channel_class = st.session_state["scenario"].channels[channel_name]
2006
  # st.write(st.session_state["scenario"].channels[channel_name])
@@ -2060,12 +2117,14 @@ if auth_status == True:
2060
  / param_dicts["current_spends"][channel_name]
2061
  )
2062
  )
2063
- # st.write(st.session_state[channel_name_lower_bound])
2064
- channel_bounds_min = st.text_input(
2065
- "Lower Bound Percentage",
2066
- key=channel_name_lower_bound,
2067
- on_change=partial(update_data_bound_min, channel_name),
2068
- )
 
 
2069
  # st.write(st.session_state[channel_name_lower_bound])
2070
  # if not validate_input_lb(str(channel_bounds_min)):
2071
  # st.error("Invalid input")
@@ -2087,30 +2146,32 @@ if auth_status == True:
2087
  step=1.00,
2088
  value=0.00,
2089
  on_change=partial(update_data_by_percent, channel_name),
2090
- max_value=calc_min_value(),
2091
- min_value=-1
2092
- * float(st.session_state[channel_name_lower_bound]),
2093
  )
2094
 
2095
- channel_bounds_max = st.text_input(
2096
- "Upper Bound Percentage",
2097
- key=channel_name_upper_bound,
2098
- on_change=partial(update_data_bound_max, channel_name),
2099
- )
2100
  # if not validate_input(channel_bounds_max):
2101
  # st.error("Invalid input")
 
 
2102
  with _columns[2]:
2103
  # spends
2104
  current_channel_spends = float(
2105
  _channel_class.modified_total_spends
2106
- * _channel_class.conversion_rate
2107
  )
2108
  actual_channel_spends = float(
2109
  _channel_class.actual_total_spends
2110
- * _channel_class.conversion_rate
2111
  )
2112
  spends_delta = float(
2113
- _channel_class.delta_spends * _channel_class.conversion_rate
 
2114
  )
2115
  st.session_state["acutual_predicted"]["Channel_name"].append(
2116
  channel_name
@@ -2183,6 +2244,7 @@ if auth_status == True:
2183
  st.session_state["acutual_predicted"]["New_sales"].append(
2184
  current_channel_sales
2185
  )
 
2186
  # st.write(actual_channel_sales)
2187
 
2188
  _prospect_cols = st.columns(2)
@@ -2404,9 +2466,9 @@ if auth_status == True:
2404
  # # print(summary_df_sorted['Old_sales'])
2405
  # # print(col, "old efficiency ", a)
2406
  with bin_placeholder:
2407
- if a > 1.2:
2408
  fill_color_box = "#6bbf6b"
2409
- elif a <= 1.2:
2410
  fill_color_box = "#ff6868"
2411
  else:
2412
  fill_color_box = "#ff6868"
 
359
 
360
  actual_spends = _scenario.actual_total_spends
361
  if (
362
+ "total_spends_change_abs" in st.session_state and validate_input(st.session_state["total_spends_change_abs"])
363
  and st.session_state["allow_spends_update"]
364
  ):
365
  modified_spends = extract_number_for_string(
366
  st.session_state["total_spends_change_abs"]
367
  )
368
+ total_spends_change_val = (
369
  (modified_spends / actual_spends) - 1
370
  ) * 100
371
+
372
+ if "overall_lower_bound" in st.session_state:
373
+ try:
374
+ lower_val = float(st.session_state["overall_lower_bound"])
375
+ except (ValueError, TypeError):
376
+ lower_val = 30.0
377
+
378
+ if "overall_upper_bound" in st.session_state:
379
+ try:
380
+ upper_val = float(st.session_state["overall_upper_bound"])
381
+ except (ValueError, TypeError):
382
+ upper_val = 30.0
383
+
384
+ if total_spends_change_val > upper_val or total_spends_change_val < -lower_val:
385
+ del st.session_state.total_spends_change_abs
386
+ return
387
+
388
+ st.session_state["total_spends_change"] = total_spends_change_val
389
  st.session_state["total_spends_change_abs_slider"] = st.session_state[
390
  "total_spends_change_abs"
391
  ]
 
517
  st.session_state["scenario"].channels[channel_name].actual_total_spends
518
  * st.session_state["scenario"].channels[channel_name].conversion_rate
519
  )
520
+
521
+
522
+ channel_spends_change = round(
523
  100 * (modified_spends - prev_spends) / prev_spends, 2
524
  )
525
+
526
+ if "overall_lower_bound" in st.session_state:
527
+ try:
528
+ lower_val = float(st.session_state["overall_lower_bound"])
529
+ except (ValueError, TypeError):
530
+ lower_val = 30.0
531
+
532
+ if "overall_upper_bound" in st.session_state:
533
+ try:
534
+ upper_val = float(st.session_state["overall_upper_bound"])
535
+ except (ValueError, TypeError):
536
+ upper_val = 30.0
537
+
538
+ if channel_spends_change > upper_val or channel_spends_change < -lower_val:
539
+ del st.session_state[channel_name]
540
+ return
541
+
542
+ st.session_state[f"{channel_name}_change"] = channel_spends_change
543
  st.session_state["scenario"].update(
544
  channel_name,
545
  modified_spends
 
622
 
623
  st.session_state["total_sales_change"] = 0
624
 
625
+ if "overall_lower_bound" in st.session_state and "overall_upper_bound" in st.session_state:
626
+ del st.session_state["overall_lower_bound"]
627
+ del st.session_state["overall_upper_bound"]
628
+
629
+ st.session_state["overall_lower_bound"] = 30.0
630
+ st.session_state["overall_upper_bound"] = 30.0
631
+
632
  update_spends()
633
  update_sales()
634
 
 
784
  summary_df_sorted["Optimized_spend"][channels_list[i]],
785
  summary_df_sorted["New_sales"][channels_list[i]],
786
  )
787
+ for i in range(13) if channels_list[i] != "Email"
788
  ]
789
 
790
+
791
  # for i in range()
792
 
793
  # Display figures in a grid layout
 
1642
  _columns = st.columns((1, 1, 1, 1, 1))
1643
  with _columns[0]:
1644
  # st.header("Prospects")
1645
+ st.markdown("""<h4>Revenue</h4>""", unsafe_allow_html=True)
1646
  with _columns[1]:
1647
  st.markdown(
1648
  f"""<h4>$ {header_df["Prospects"]["Actual"]}</h4>""",
 
1702
  st.markdown("""<h4>ROI</h4>""", unsafe_allow_html=True)
1703
  # st.header("Cost Per Prospect")
1704
  with _columns[1]:
1705
+ st.markdown(f"""<h4>{numerize(ef1, 2)}</h4>""", unsafe_allow_html=True)
1706
  # st.metric(label="", value='$ '+numerize(ef1,0))
1707
  with _columns[2]:
1708
+ st.markdown(f"""<h4>{numerize(ef2, 2)}</h4>""", unsafe_allow_html=True)
1709
  # st.metric(label="", value='$ '+numerize(ef2,0))
1710
 
1711
+ if ef2 >= ef1:
1712
  st.markdown(
1713
  """
1714
  <style>
 
1737
 
1738
  # Apply custom styles to text
1739
  st.markdown(
1740
+ f'<h4 class="custom-text1">{numerize(ef2-ef1, 2)}</h4>',
1741
  unsafe_allow_html=True,
1742
  )
1743
  # st.markdown(f'<p style="color: red;">{st.metric(label="", value=header_df["Prospects"]["Change"])}</p>', unsafe_allow_html=True)
 
1747
  # st.markdown(f'<p></hr></p>', unsafe_allow_html=True)
1748
  # Apply custom styles to text
1749
  st.markdown(
1750
+ f'<h4 class="custom-text1">{round((ef2-ef1)/ef1*100, 2)}%</h4>',
1751
  unsafe_allow_html=True,
1752
  )
1753
  st.markdown("""<hr class="spends-child-seperator">""", unsafe_allow_html=True)
 
1850
  _columns1 = st.columns((1, 1, 1, 1))
1851
  with _columns1[0]:
1852
  optimization_selection = st.selectbox(
1853
+ "Optimize", options=["Media Spends"], key="optimization_key"
1854
  )
1855
 
1856
  with _columns1[1]:
 
1891
  with _columns2[2]:
1892
  overall_lower_bound = st.number_input(
1893
  "Overall Lower Bound for Spends",
1894
+ value=30.0,
1895
+ min_value=0.0,
1896
+ max_value=30.0,
1897
  key="overall_lower_bound",
1898
  # on_change=partial(update_data_bound_min_overall)
1899
  )
1900
  with _columns2[3]:
1901
  overall_upper_bound = st.number_input(
1902
  "Overall Upper Bound for Spends",
1903
+ value=30.0,
1904
+ min_value=0.0,
1905
+ max_value=30.0,
1906
  key="overall_upper_bound",
1907
  # on_change=partial(update_data_bound_max_overall)
1908
  )
1909
+
1910
  min_value = round(
1911
  _scenario.actual_total_spends * (1 - overall_lower_bound / 100)
1912
  )
 
1927
  st.number_input(
1928
  "Percent Change",
1929
  key="total_spends_change",
1930
+ # min_value=-1 * overall_lower_bound,
1931
+ # max_value=overall_upper_bound,
1932
+ min_value=-overall_lower_bound,
1933
  max_value=overall_upper_bound,
1934
  step=0.01,
1935
  value=0.00,
 
1959
 
1960
  with _columns2[1]:
1961
  st.number_input(
1962
+ "Percent aaChange",
1963
  key="total_sales_change",
1964
  min_value=-50.00,
1965
  max_value=50.00,
 
2054
  "Old_sales": [],
2055
  }
2056
  for i, channel_name in enumerate(channels_list):
2057
+
2058
+ if channel_name == "Email":
2059
+ continue
2060
+
2061
  # st.write(channel_name)
2062
  _channel_class = st.session_state["scenario"].channels[channel_name]
2063
  # st.write(st.session_state["scenario"].channels[channel_name])
 
2117
  / param_dicts["current_spends"][channel_name]
2118
  )
2119
  )
2120
+ # # st.write(st.session_state[channel_name_lower_bound])
2121
+ # channel_bounds_min = st.text_input(
2122
+ # "Lower Bound Percentage",
2123
+ # key=channel_name_lower_bound,
2124
+ # on_change=partial(update_data_bound_min, channel_name),
2125
+ # )
2126
+
2127
+ channel_bounds_min = 30.0
2128
  # st.write(st.session_state[channel_name_lower_bound])
2129
  # if not validate_input_lb(str(channel_bounds_min)):
2130
  # st.error("Invalid input")
 
2146
  step=1.00,
2147
  value=0.00,
2148
  on_change=partial(update_data_by_percent, channel_name),
2149
+ max_value=st.session_state["overall_upper_bound"],
2150
+ min_value=-st.session_state["overall_lower_bound"],
 
2151
  )
2152
 
2153
+ # channel_bounds_max = st.text_input(
2154
+ # "Upper Bound Percentage",
2155
+ # key=channel_name_upper_bound,
2156
+ # on_change=partial(update_data_bound_max, channel_name),
2157
+ # )
2158
  # if not validate_input(channel_bounds_max):
2159
  # st.error("Invalid input")
2160
+ channel_bounds_max = 30.0
2161
+
2162
  with _columns[2]:
2163
  # spends
2164
  current_channel_spends = float(
2165
  _channel_class.modified_total_spends
2166
+ # * _channel_class.conversion_rate
2167
  )
2168
  actual_channel_spends = float(
2169
  _channel_class.actual_total_spends
2170
+ # * _channel_class.conversion_rate
2171
  )
2172
  spends_delta = float(
2173
+ # _channel_class.delta_spends * _channel_class.conversion_rate
2174
+ _channel_class.delta_spends
2175
  )
2176
  st.session_state["acutual_predicted"]["Channel_name"].append(
2177
  channel_name
 
2244
  st.session_state["acutual_predicted"]["New_sales"].append(
2245
  current_channel_sales
2246
  )
2247
+
2248
  # st.write(actual_channel_sales)
2249
 
2250
  _prospect_cols = st.columns(2)
 
2466
  # # print(summary_df_sorted['Old_sales'])
2467
  # # print(col, "old efficiency ", a)
2468
  with bin_placeholder:
2469
+ if a > 1:
2470
  fill_color_box = "#6bbf6b"
2471
+ elif a <= 1:
2472
  fill_color_box = "#ff6868"
2473
  else:
2474
  fill_color_box = "#ff6868"
summary_df.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:4279102a6e3c64422e780dad800d1de417ff74112d57e124b790a1f6af5376ea
3
- size 1820
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:35f08123f49d9966c361ad8e23d429995e4eac8ac44b70b337e3c2764129ddfc
3
+ size 1756