Samkeet-Blend360
commited on
Commit
·
e8d72c9
1
Parent(s):
53c950b
- Streamlit_functions.py +84 -78
- __pycache__/Streamlit_functions.cpython-310.pyc +0 -0
- __pycache__/classes.cpython-310.pyc +0 -0
- classes.py +33 -10
- pages/2_Scenario_Planner.py +96 -34
- summary_df.pkl +2 -2
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 |
-
,
|
|
|
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 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
|
|
268 |
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
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["
|
957 |
|
958 |
# Calculating Effectiveness as Revenue Contribution * 1,000,000 / Support
|
959 |
-
shares_table_df["Effectiveness"] = (shares_df["cur_contributions_share"] *
|
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 =
|
144 |
# # # # print(dividing_rate)
|
145 |
# x = np.sum(x)
|
146 |
else:
|
147 |
-
dividing_rate =
|
|
|
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(
|
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 |
-
|
456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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":
|
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 |
-
|
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 |
-
|
|
|
|
|
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>
|
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,
|
1660 |
# st.metric(label="", value='$ '+numerize(ef1,0))
|
1661 |
with _columns[2]:
|
1662 |
-
st.markdown(f"""<h4>{numerize(ef2,
|
1663 |
# st.metric(label="", value='$ '+numerize(ef2,0))
|
1664 |
|
1665 |
-
if ef2
|
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,
|
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"
|
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=
|
|
|
|
|
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=
|
|
|
|
|
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
|
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 |
-
|
2066 |
-
|
2067 |
-
|
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=
|
2091 |
-
min_value=-
|
2092 |
-
* float(st.session_state[channel_name_lower_bound]),
|
2093 |
)
|
2094 |
|
2095 |
-
channel_bounds_max = st.text_input(
|
2096 |
-
|
2097 |
-
|
2098 |
-
|
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
|
2408 |
fill_color_box = "#6bbf6b"
|
2409 |
-
elif a <= 1
|
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:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:35f08123f49d9966c361ad8e23d429995e4eac8ac44b70b337e3c2764129ddfc
|
3 |
+
size 1756
|