Pragya Jatav commited on
Commit
69b14e2
·
1 Parent(s): 85d2c7e

Delete two files

Browse files
pages/8_Scenario_Planner.py DELETED
@@ -1,1515 +0,0 @@
1
- import streamlit as st
2
- from numerize.numerize import numerize
3
- import numpy as np
4
- from functools import partial
5
- from collections import OrderedDict
6
- from plotly.subplots import make_subplots
7
- import plotly.graph_objects as go
8
- from utilities import (
9
- format_numbers,format_numbers_f,
10
- load_local_css,
11
- set_header,
12
- initialize_data,
13
- load_authenticator,
14
- send_email,
15
- channel_name_formating,
16
- )
17
- from classes import class_from_dict, class_to_dict
18
- import pickle
19
- import streamlit_authenticator as stauth
20
- import yaml
21
- from yaml import SafeLoader
22
- import re
23
- import pandas as pd
24
- import plotly.express as px
25
- # import response_curves_model_quality as rc
26
-
27
- st.set_page_config(layout="wide")
28
- load_local_css("styles.css")
29
- set_header()
30
-
31
-
32
- for k, v in st.session_state.items():
33
- if k not in ["logout", "login", "config"] and not k.startswith("FormSubmitter"):
34
- st.session_state[k] = v
35
- # ======================================================== #
36
- # ======================= Functions ====================== #
37
- # ======================================================== #
38
-
39
-
40
- def optimize(key, status_placeholder):
41
- """
42
- Optimize the spends for the sales
43
- """
44
-
45
- channel_list = [
46
- key for key, value in st.session_state["optimization_channels"].items() if value
47
- ]
48
-
49
- if len(channel_list) > 0:
50
- scenario = st.session_state["scenario"]
51
- if key.lower() == "media spends":
52
- with status_placeholder:
53
- with st.spinner("Optimizing"):
54
- result = st.session_state["scenario"].optimize(
55
- st.session_state["total_spends_change"], channel_list
56
- )
57
- # elif key.lower() == "revenue":
58
- else:
59
- with status_placeholder:
60
- with st.spinner("Optimizing"):
61
-
62
- result = st.session_state["scenario"].optimize_spends(
63
- st.session_state["total_sales_change"], channel_list
64
- )
65
- for channel_name, modified_spends in result:
66
-
67
- st.session_state[channel_name] = numerize(
68
- modified_spends * scenario.channels[channel_name].conversion_rate,
69
- 1,
70
- )
71
- prev_spends = (
72
- st.session_state["scenario"].channels[channel_name].actual_total_spends
73
- )
74
- st.session_state[f"{channel_name}_change"] = round(
75
- 100 * (modified_spends - prev_spends) / prev_spends, 2
76
- )
77
-
78
-
79
- def save_scenario(scenario_name):
80
- """
81
- Save the current scenario with the mentioned name in the session state
82
-
83
- Parameters
84
- ----------
85
- scenario_name
86
- Name of the scenario to be saved
87
- """
88
- if "saved_scenarios" not in st.session_state:
89
- st.session_state = OrderedDict()
90
-
91
- # st.session_state['saved_scenarios'][scenario_name] = st.session_state['scenario'].save()
92
- st.session_state["saved_scenarios"][scenario_name] = class_to_dict(
93
- st.session_state["scenario"]
94
- )
95
- st.session_state["scenario_input"] = ""
96
- # print(type(st.session_state['saved_scenarios']))
97
- with open("../saved_scenarios.pkl", "wb") as f:
98
- pickle.dump(st.session_state["saved_scenarios"], f)
99
-
100
-
101
- if "allow_spends_update" not in st.session_state:
102
- st.session_state["allow_spends_update"] = True
103
-
104
- if "allow_sales_update" not in st.session_state:
105
- st.session_state["allow_sales_update"] = True
106
-
107
-
108
- def update_sales_abs_slider():
109
- actual_sales = _scenario.actual_total_sales
110
- if validate_input(st.session_state["total_sales_change_abs_slider"]):
111
- modified_sales = extract_number_for_string(
112
- st.session_state["total_sales_change_abs_slider"]
113
- )
114
- st.session_state["total_sales_change"] = round(
115
- ((modified_sales / actual_sales) - 1) * 100
116
- )
117
- st.session_state["total_sales_change_abs"] = numerize(modified_sales, 1)
118
-
119
-
120
- def update_sales_abs():
121
- if (
122
- st.session_state["total_sales_change_abs"]
123
- in st.session_state["total_sales_change_abs_slider_options"]
124
- ):
125
- st.session_state["allow_sales_update"] = True
126
- else:
127
- st.session_state["allow_sales_update"] = False
128
-
129
- actual_sales = _scenario.actual_total_sales
130
- if (
131
- validate_input(st.session_state["total_sales_change_abs"])
132
- and st.session_state["allow_sales_update"]
133
- ):
134
- modified_sales = extract_number_for_string(
135
- st.session_state["total_sales_change_abs"]
136
- )
137
- st.session_state["total_sales_change"] = round(
138
- ((modified_sales / actual_sales) - 1) * 100
139
- )
140
- st.session_state["total_sales_change_abs_slider"] = numerize(modified_sales, 1)
141
-
142
-
143
- def update_sales():
144
- st.session_state["total_sales_change_abs"] = numerize(
145
- (1 + st.session_state["total_sales_change"] / 100)
146
- * _scenario.actual_total_sales,
147
- 1,
148
- )
149
- st.session_state["total_sales_change_abs_slider"] = numerize(
150
- (1 + st.session_state["total_sales_change"] / 100)
151
- * _scenario.actual_total_sales,
152
- 1,
153
- )
154
-
155
-
156
- def update_all_spends_abs_slider():
157
- actual_spends = _scenario.actual_total_spends
158
- if validate_input(st.session_state["total_spends_change_abs_slider"]):
159
- modified_spends = extract_number_for_string(
160
- st.session_state["total_spends_change_abs_slider"]
161
- )
162
- st.session_state["total_spends_change"] = round(
163
- ((modified_spends / actual_spends) - 1) * 100
164
- )
165
- st.session_state["total_spends_change_abs"] = numerize(modified_spends, 1)
166
-
167
- update_all_spends()
168
-
169
-
170
- # def update_all_spends_abs_slider():
171
- # actual_spends = _scenario.actual_total_spends
172
- # if validate_input(st.session_state["total_spends_change_abs_slider"]):
173
- # print("#" * 100)
174
- # print(st.session_state["total_spends_change_abs_slider"])C:\Users\PragyaJatav\Downloads\Untitled Folder 2\simulatorAldi\pages\8_Scenario_Planner.py
175
- # print("#" * 100)
176
-
177
- # modified_spends = extract_number_for_string(
178
- # st.session_state["total_spends_change_abs_slider"]
179
- # )
180
- # st.session_state["total_spends_change"] = (
181
- # (modified_spends / actual_spends) - 1
182
- # ) * 100
183
- # st.session_state["total_spends_change_abs"] = st.session_state[
184
- # "total_spends_change_abs_slider"
185
- # ]
186
-
187
- # update_all_spends()
188
-
189
-
190
- def update_all_spends_abs():
191
- if (
192
- st.session_state["total_spends_change_abs"]
193
- in st.session_state["total_spends_change_abs_slider_options"]
194
- ):
195
- st.session_state["allow_spends_update"] = True
196
- else:
197
- st.session_state["allow_spends_update"] = False
198
-
199
- actual_spends = _scenario.actual_total_spends
200
- if (
201
- validate_input(st.session_state["total_spends_change_abs"])
202
- and st.session_state["allow_spends_update"]
203
- ):
204
- modified_spends = extract_number_for_string(
205
- st.session_state["total_spends_change_abs"]
206
- )
207
- st.session_state["total_spends_change"] = (
208
- (modified_spends / actual_spends) - 1
209
- ) * 100
210
- st.session_state["total_spends_change_abs_slider"] = st.session_state[
211
- "total_spends_change_abs"
212
- ]
213
-
214
- update_all_spends()
215
-
216
-
217
- def update_spends():
218
- st.session_state["total_spends_change_abs"] = numerize(
219
- (1 + st.session_state["total_spends_change"] / 100)
220
- * _scenario.actual_total_spends,
221
- 1,
222
- )
223
- st.session_state["total_spends_change_abs_slider"] = numerize(
224
- (1 + st.session_state["total_spends_change"] / 100)
225
- * _scenario.actual_total_spends,
226
- 1,
227
- )
228
-
229
- update_all_spends()
230
-
231
-
232
- def update_all_spends():
233
- """
234
- Updates spends for all the channels with the given overall spends change
235
- """
236
- percent_change = st.session_state["total_spends_change"]
237
-
238
- for channel_name in st.session_state["channels_list"]:
239
- channel = st.session_state["scenario"].channels[channel_name]
240
- current_spends = channel.actual_total_spends
241
- modified_spends = (1 + percent_change / 100) * current_spends
242
- st.session_state["scenario"].update(channel_name, modified_spends)
243
- st.session_state[channel_name] = numerize(
244
- modified_spends * channel.conversion_rate, 1
245
- )
246
- st.session_state[f"{channel_name}_change"] = percent_change
247
-
248
-
249
- def extract_number_for_string(string_input):
250
- string_input = string_input.upper()
251
- if string_input.endswith("K"):
252
- return float(string_input[:-1]) * 10**3
253
- elif string_input.endswith("M"):
254
- return float(string_input[:-1]) * 10**6
255
- elif string_input.endswith("B"):
256
- return float(string_input[:-1]) * 10**9
257
-
258
-
259
- def validate_input(string_input):
260
- pattern = r"\d+\.?\d*[K|M|B]$"
261
- match = re.match(pattern, string_input)
262
- if match is None:
263
- return False
264
- return True
265
-
266
-
267
- def update_data_by_percent(channel_name):
268
- prev_spends = (
269
- st.session_state["scenario"].channels[channel_name].actual_total_spends
270
- * st.session_state["scenario"].channels[channel_name].conversion_rate
271
- )
272
- modified_spends = prev_spends * (
273
- 1 + st.session_state[f"{channel_name}_change"] / 100
274
- )
275
- st.session_state[channel_name] = numerize(modified_spends, 1)
276
- st.session_state["scenario"].update(
277
- channel_name,
278
- modified_spends
279
- / st.session_state["scenario"].channels[channel_name].conversion_rate,
280
- )
281
-
282
-
283
- def update_data(channel_name):
284
- """
285
- Updates the spends for the given channel
286
- """
287
-
288
- if validate_input(st.session_state[channel_name]):
289
- modified_spends = extract_number_for_string(st.session_state[channel_name])
290
- prev_spends = (
291
- st.session_state["scenario"].channels[channel_name].actual_total_spends
292
- * st.session_state["scenario"].channels[channel_name].conversion_rate
293
- )
294
- st.session_state[f"{channel_name}_change"] = round(
295
- 100 * (modified_spends - prev_spends) / prev_spends, 2
296
- )
297
- st.session_state["scenario"].update(
298
- channel_name,
299
- modified_spends
300
- / st.session_state["scenario"].channels[channel_name].conversion_rate,
301
- )
302
- # st.session_state['scenario'].update(channel_name, modified_spends)
303
- # else:
304
- # try:
305
- # modified_spends = float(st.session_state[channel_name])
306
- # prev_spends = st.session_state['scenario'].channels[channel_name].actual_total_spends * st.session_state['scenario'].channels[channel_name].conversion_rate
307
- # st.session_state[f'{channel_name}_change'] = round(100*(modified_spends - prev_spends) / prev_spends,2)
308
- # st.session_state['scenario'].update(channel_name, modified_spends/st.session_state['scenario'].channels[channel_name].conversion_rate)
309
- # st.session_state[f'{channel_name}'] = numerize(modified_spends,1)
310
- # except ValueError:
311
- # st.write('Invalid input')
312
-
313
-
314
- def select_channel_for_optimization(channel_name):
315
- """
316
- Marks the given channel for optimization
317
- """
318
- st.session_state["optimization_channels"][channel_name] = st.session_state[
319
- f"{channel_name}_selected"
320
- ]
321
-
322
-
323
- def select_all_channels_for_optimization():
324
- """
325
- Marks all the channel for optimization
326
- """
327
- for channel_name in st.session_state["optimization_channels"].keys():
328
- st.session_state[f"{channel_name}_selected"] = st.session_state[
329
- "optimze_all_channels"
330
- ]
331
- st.session_state["optimization_channels"][channel_name] = st.session_state[
332
- "optimze_all_channels"
333
- ]
334
-
335
-
336
- def update_penalty():
337
- """
338
- Updates the penalty flag for sales calculation
339
- """
340
- st.session_state["scenario"].update_penalty(st.session_state["apply_penalty"])
341
-
342
-
343
- def reset_scenario(panel_selected, file_selected, updated_rcs):
344
- # #print(st.session_state['default_scenario_dict'])
345
- # st.session_state['scenario'] = class_from_dict(st.session_state['default_scenario_dict'])
346
- # for channel in st.session_state['scenario'].channels.values():
347
- # st.session_state[channel.name] = float(channel.actual_total_spends * channel.conversion_rate)
348
- # initialize_data()
349
-
350
- if panel_selected == "Total Market":
351
- initialize_data(
352
- panel=panel_selected,
353
- target_file=file_selected,
354
- updated_rcs=updated_rcs,
355
- metrics=metrics_selected,
356
- )
357
- panel = None
358
- else:
359
- initialize_data(
360
- panel=panel_selected,
361
- target_file=file_selected,
362
- updated_rcs=updated_rcs,
363
- metrics=metrics_selected,
364
- )
365
-
366
- for channel_name in st.session_state["channels_list"]:
367
- st.session_state[f"{channel_name}_selected"] = False
368
- st.session_state[f"{channel_name}_change"] = 0
369
- st.session_state["optimze_all_channels"] = False
370
-
371
- st.session_state["total_sales_change"] = 0
372
-
373
- update_spends()
374
- update_sales()
375
-
376
- reset_inputs()
377
-
378
- # st.rerun()
379
-
380
-
381
- def format_number(num):
382
- if num >= 1_000_000:
383
- return f"{num / 1_000_000:.2f}M"
384
- elif num >= 1_000:
385
- return f"{num / 1_000:.0f}K"
386
- else:
387
- return f"{num:.2f}"
388
-
389
-
390
- def summary_plot(data, x, y, title, text_column):
391
- fig = px.bar(
392
- data,
393
- x=x,
394
- y=y,
395
- orientation="h",
396
- title=title,
397
- text=text_column,
398
- color="Channel_name",
399
- )
400
-
401
- # Convert text_column to numeric values
402
- data[text_column] = pd.to_numeric(data[text_column], errors="coerce")
403
-
404
- # Update the format of the displayed text based on magnitude
405
- fig.update_traces(
406
- texttemplate="%{text:.2s}",
407
- textposition="outside",
408
- hovertemplate="%{x:.2s}",
409
- )
410
-
411
- fig.update_layout(xaxis_title=x, yaxis_title="Channel Name", showlegend=False)
412
- return fig
413
-
414
-
415
- def s_curve(x, K, b, a, x0):
416
- return K / (1 + b * np.exp(-a * (x - x0)))
417
-
418
-
419
- def find_segment_value(x, roi, mroi):
420
- start_value = x[0]
421
- end_value = x[len(x) - 1]
422
-
423
- # Condition for green region: Both MROI and ROI > 1
424
- green_condition = (roi > 1) & (mroi > 1)
425
- left_indices = np.where(green_condition)[0]
426
- left_value = x[left_indices[0]] if left_indices.size > 0 else x[0]
427
-
428
- right_indices = np.where(green_condition)[0]
429
- right_value = x[right_indices[-1]] if right_indices.size > 0 else x[0]
430
-
431
- return start_value, end_value, left_value, right_value
432
-
433
-
434
- def calculate_rgba(
435
- start_value, end_value, left_value, right_value, current_channel_spends
436
- ):
437
- # Initialize alpha to None for clarity
438
- alpha = None
439
-
440
- # Determine the color and calculate relative_position and alpha based on the point's position
441
- if start_value <= current_channel_spends <= left_value:
442
- color = "yellow"
443
- relative_position = (current_channel_spends - start_value) / (
444
- left_value - start_value
445
- )
446
- alpha = 0.8 - (0.6 * relative_position) # Alpha decreases from start to end
447
-
448
- elif left_value < current_channel_spends <= right_value:
449
- color = "green"
450
- relative_position = (current_channel_spends - left_value) / (
451
- right_value - left_value
452
- )
453
- alpha = 0.8 - (0.6 * relative_position) # Alpha decreases from start to end
454
-
455
- elif right_value < current_channel_spends <= end_value:
456
- color = "red"
457
- relative_position = (current_channel_spends - right_value) / (
458
- end_value - right_value
459
- )
460
- alpha = 0.2 + (0.6 * relative_position) # Alpha increases from start to end
461
-
462
- else:
463
- # Default case, if the spends are outside the defined ranges
464
- return "rgba(136, 136, 136, 0.5)" # Grey for values outside the range
465
-
466
- # Ensure alpha is within the intended range in case of any calculation overshoot
467
- alpha = max(0.2, min(alpha, 0.8))
468
-
469
- # Define color codes for RGBA
470
- color_codes = {
471
- "yellow": "255, 255, 0", # RGB for yellow
472
- "green": "0, 128, 0", # RGB for green
473
- "red": "255, 0, 0", # RGB for red
474
- }
475
-
476
- rgba = f"rgba({color_codes[color]}, {alpha})"
477
- return rgba
478
-
479
-
480
- def debug_temp(x_test, power, K, b, a, x0):
481
- print("*" * 100)
482
- # Calculate the count of bins
483
- count_lower_bin = sum(1 for x in x_test if x <= 2524)
484
- count_center_bin = sum(1 for x in x_test if x > 2524 and x <= 3377)
485
- count_ = sum(1 for x in x_test if x > 3377)
486
-
487
- print(
488
- f"""
489
- lower : {count_lower_bin}
490
- center : {count_center_bin}
491
- upper : {count_}
492
- """
493
- )
494
-
495
-
496
- # @st.cache
497
- def plot_response_curves(summary_df_sorted):
498
- # cols = 3
499
- # rows = (
500
- # len(channels_list) // cols
501
- # if len(channels_list) % cols == 0
502
- # else len(channels_list) // cols + 1
503
- # )
504
- # rcs = st.session_state["rcs"]
505
- # shapes = []
506
- # fig = make_subplots(rows=rows, cols=cols, subplot_titles=channels_list)
507
- channel_cols = [
508
- 'BroadcastTV',
509
- 'CableTV',
510
- 'Connected&OTTTV',
511
- 'DisplayProspecting',
512
- 'DisplayRetargeting',
513
- 'Video',
514
- 'SocialProspecting',
515
- 'SocialRetargeting',
516
- 'SearchBrand',
517
- 'SearchNon-brand',
518
- 'DigitalPartners',
519
- 'Audio',
520
- 'Email']
521
- summary_df_sorted.index = summary_df_sorted["Channel_name"]
522
- for i in range(0, len(channels_list)):
523
- col = channels_list[i]
524
- if col == "Panel":
525
- continue
526
- st.write(col)
527
- x_modified = summary_df_sorted["Optimized_spend"][col]/104
528
- y_modified = summary_df_sorted["New_sales"][col]/104
529
- st.plotly_chart(rc.response_curves(col,x_modified,y_modified))
530
-
531
-
532
- # @st.cache
533
- # def plot_response_curves():
534
- # cols = 4
535
- # rcs = st.session_state["rcs"]
536
- # shapes = []
537
- # fig = make_subplots(rows=6, cols=cols, subplot_titles=channels_list)
538
- # for i in range(0, len(channels_list)):
539
- # col = channels_list[i]
540
- # x = st.session_state["actual_df"][col].values
541
- # spends = x.sum()
542
- # power = np.ceil(np.log(x.max()) / np.log(10)) - 3
543
- # x = np.linspace(0, 3 * x.max(), 200)
544
-
545
- # K = rcs[col]["K"]
546
- # b = rcs[col]["b"]
547
- # a = rcs[col]["a"]
548
- # x0 = rcs[col]["x0"]
549
-
550
- # y = s_curve(x / 10**power, K, b, a, x0)
551
- # roi = y / x
552
- # marginal_roi = a * (y) * (1 - y / K)
553
- # fig.add_trace(
554
- # go.Scatter(
555
- # x=52
556
- # * x
557
- # * st.session_state["scenario"].channels[col].conversion_rate,
558
- # y=52 * y,
559
- # name=col,
560
- # customdata=np.stack((roi, marginal_roi), axis=-1),
561
- # hovertemplate="Spend:%{x:$.2s}<br>Sale:%{y:$.2s}<br>ROI:%{customdata[0]:.3f}<br>MROI:%{customdata[1]:.3f}",
562
- # ),
563
- # row=1 + (i) // cols,
564
- # col=i % cols + 1,
565
- # )
566
-
567
- # fig.add_trace(
568
- # go.Scatter(
569
- # x=[
570
- # spends
571
- # * st.session_state["scenario"]
572
- # .channels[col]
573
- # .conversion_rate
574
- # ],
575
- # y=[52 * s_curve(spends / (10**power * 52), K, b, a, x0)],
576
- # name=col,
577
- # legendgroup=col,
578
- # showlegend=False,
579
- # marker=dict(color=["black"]),
580
- # ),
581
- # row=1 + (i) // cols,
582
- # col=i % cols + 1,
583
- # )
584
-
585
- # shapes.append(
586
- # go.layout.Shape(
587
- # type="line",
588
- # x0=0,
589
- # y0=52 * s_curve(spends / (10**power * 52), K, b, a, x0),
590
- # x1=spends
591
- # * st.session_state["scenario"].channels[col].conversion_rate,
592
- # y1=52 * s_curve(spends / (10**power * 52), K, b, a, x0),
593
- # line_width=1,
594
- # line_dash="dash",
595
- # line_color="black",
596
- # xref=f"x{i+1}",
597
- # yref=f"y{i+1}",
598
- # )
599
- # )
600
-
601
- # shapes.append(
602
- # go.layout.Shape(
603
- # type="line",
604
- # x0=spends
605
- # * st.session_state["scenario"].channels[col].conversion_rate,
606
- # y0=0,
607
- # x1=spends
608
- # * st.session_state["scenario"].channels[col].conversion_rate,
609
- # y1=52 * s_curve(spends / (10**power * 52), K, b, a, x0),
610
- # line_width=1,
611
- # line_dash="dash",
612
- # line_color="black",
613
- # xref=f"x{i+1}",
614
- # yref=f"y{i+1}",
615
- # )
616
- # )
617
-
618
- # fig.update_layout(
619
- # height=1500,
620
- # width=1000,
621
- # title_text="Response Curves",
622
- # showlegend=False,
623
- # shapes=shapes,
624
- # )
625
- # fig.update_annotations(font_size=10)
626
- # fig.update_xaxes(title="Spends")
627
- # fig.update_yaxes(title=target)
628
- # return fig
629
-
630
-
631
- # ======================================================== #
632
- # ==================== HTML Components =================== #
633
- # ======================================================== #
634
-
635
-
636
- def generate_spending_header(heading):
637
- return st.markdown(
638
- f"""<h2 class="spends-header">{heading}</h2>""", unsafe_allow_html=True
639
- )
640
-
641
-
642
- # ======================================================== #
643
- # =================== Session variables ================== #
644
- # ======================================================== #
645
-
646
- with open("config.yaml") as file:
647
- config = yaml.load(file, Loader=SafeLoader)
648
- st.session_state["config"] = config
649
-
650
- authenticator = stauth.Authenticate(
651
- config["credentials"],
652
- config["cookie"]["name"],
653
- config["cookie"]["key"],
654
- config["cookie"]["expiry_days"],
655
- config["preauthorized"],
656
- )
657
- st.session_state["authenticator"] = authenticator
658
- name, authentication_status, username = authenticator.login("Login", "main")
659
- auth_status = st.session_state.get("authentication_status")
660
-
661
- import os
662
- import glob
663
-
664
-
665
- def get_excel_names(directory):
666
- # Create a list to hold the final parts of the filenames
667
- last_portions = []
668
-
669
- # Patterns to match Excel files (.xlsx and .xls) that contain @#
670
- patterns = [
671
- os.path.join(directory, "*@#*.xlsx"),
672
- os.path.join(directory, "*@#*.xls"),
673
- ]
674
-
675
- # Process each pattern
676
- for pattern in patterns:
677
- files = glob.glob(pattern)
678
-
679
- # Extracting the last portion after @# for each file
680
- for file in files:
681
- base_name = os.path.basename(file)
682
- last_portion = base_name.split("@#")[-1]
683
- last_portion = last_portion.replace(".xlsx", "").replace(
684
- ".xls", ""
685
- ) # Removing extensions
686
- last_portions.append(last_portion)
687
-
688
- return last_portions
689
-
690
-
691
- def name_formating(channel_name):
692
- # Replace underscores with spaces
693
- name_mod = channel_name.replace("_", " ")
694
-
695
- # Capitalize the first letter of each word
696
- name_mod = name_mod.title()
697
-
698
- return name_mod
699
-
700
-
701
- @st.cache_data(show_spinner=False)
702
- def panel_fetch(file_selected):
703
- raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
704
-
705
- # if "Panel" in raw_data_mmm_df.columns:
706
- # panel = list(set(raw_data_mmm_df["Panel"]))
707
- # else:
708
- # raw_data_mmm_df = None
709
- # panel = None
710
- # raw_data_mmm_df = None
711
- panel = None
712
- return panel
713
-
714
-
715
- def reset_inputs():
716
- if "total_spends_change_abs" in st.session_state:
717
- del st.session_state.total_spends_change_abs
718
- if "total_spends_change" in st.session_state:
719
- del st.session_state.total_spends_change
720
- if "total_spends_change_abs_slider" in st.session_state:
721
- del st.session_state.total_spends_change_abs_slider
722
-
723
- if "total_sales_change_abs" in st.session_state:
724
- del st.session_state.total_sales_change_abs
725
- if "total_sales_change" in st.session_state:
726
- del st.session_state.total_sales_change
727
- if "total_sales_change_abs_slider" in st.session_state:
728
- del st.session_state.total_sales_change_abs_slider
729
-
730
- st.session_state["initialized"] = False
731
-
732
-
733
- if auth_status == True:
734
- authenticator.logout("Logout", "main")
735
- st.header("Scenario Planner")
736
- def scenario_planner_plots():
737
-
738
- with st.expander('Optimized Spends Overview'):
739
- # if st.button('Refresh'):
740
- # st.experimental_rerun()
741
-
742
- import plotly.graph_objects as go
743
- from plotly.subplots import make_subplots
744
-
745
- # Define light colors for bars
746
- import plotly.graph_objects as go
747
- from plotly.subplots import make_subplots
748
-
749
- st.empty()
750
- #st.header('Model Result Analysis')
751
- spends_data=pd.read_excel('Overview_data_test.xlsx')
752
-
753
- with open('summary_df.pkl', 'rb') as file:
754
- summary_df_sorted = pickle.load(file)
755
- #st.write(summary_df_sorted)
756
-
757
- # selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2'])
758
- summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
759
- summary_df_sorted['old_efficiency']=(summary_df_sorted['Old_sales']/summary_df_sorted['Old_sales'].sum())/(summary_df_sorted['Actual_spend']/summary_df_sorted['Actual_spend'].sum())
760
- summary_df_sorted['new_efficiency']=(summary_df_sorted['New_sales']/summary_df_sorted['New_sales'].sum())/(summary_df_sorted['Optimized_spend']/summary_df_sorted['Optimized_spend'].sum())
761
-
762
- summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend']
763
- summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend']
764
-
765
- total_actual_spend = summary_df_sorted['Actual_spend'].sum()
766
- total_optimized_spend = summary_df_sorted['Optimized_spend'].sum()
767
-
768
- actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100
769
- optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100
770
-
771
-
772
-
773
- light_blue = 'rgba(0, 31, 120, 0.7)'
774
- light_orange = 'rgba(0, 181, 219, 0.7)'
775
- light_green = 'rgba(240, 61, 20, 0.7)'
776
- light_red = 'rgba(250, 110, 10, 0.7)'
777
- light_purple = 'rgba(255, 191, 69, 0.7)'
778
-
779
-
780
- # # Create subplots with one row and two columns
781
- # fig = make_subplots(rows=3, cols=1, subplot_titles=("Actual vs. Optimized Spend", "Actual vs. Optimized Contribution", "Actual vs. Optimized ROI"))
782
-
783
- # # Add actual vs optimized spend bars
784
-
785
-
786
- # fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Actual_spend'], name='Actual',
787
- # text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '+' (' + actual_spend_percentage.round(2).astype(str) + '%)',
788
- # marker_color=light_blue, orientation='h'),
789
- # row=1,
790
- # col=1)
791
-
792
-
793
- # fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Optimized_spend'], name='Optimized',
794
- # text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' (' + optimized_spend_percentage.round(2).astype(str) + '%)',
795
- # marker_color=light_orange,
796
- # orientation='h'),
797
- # row=1,
798
- # col=1)
799
-
800
- # fig.update_xaxes(title_text="Amount", row=1, col=1)
801
-
802
- # # Add actual vs optimized Contribution
803
- # fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['New_sales'],
804
- # name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),
805
- # marker_color=light_orange, orientation='h',showlegend=False), row=2, col=1)
806
-
807
- # fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Old_sales'],
808
- # name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),
809
- # marker_color=light_blue, orientation='h',showlegend=False), row=2, col=1)
810
-
811
-
812
- # fig.update_xaxes(title_text="Contribution", row=2, col=1)
813
-
814
- # # Add actual vs optimized ROI bars
815
-
816
- # fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['new_roi'],
817
- # name='Optimized ROI',text=summary_df_sorted['new_roi'].apply(format_number) ,
818
- # marker_color=light_orange, orientation='h',showlegend=False), row=3, col=1)
819
-
820
- # fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['old_roi'],
821
- # name='Actual ROI', text=summary_df_sorted['old_roi'].apply(format_number) ,
822
- # marker_color=light_blue, orientation='h',showlegend=False), row=3, col=1)
823
-
824
- # fig.update_xaxes(title_text="ROI", row=3, col=1)
825
-
826
- # # Update layout
827
- # fig.update_layout(title_text="Actual vs. Optimized Metrics for Media Channels",
828
- # showlegend=True, yaxis=dict(title='Media Channels', autorange="reversed"))
829
-
830
- # st.plotly_chart(fig,use_container_width=True)
831
-
832
- # Create subplots with one row and two columns
833
- fig = go.Figure()
834
- # Add actual vs optimized spend bars
835
-
836
-
837
- fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Actual_spend'], name='Actual',
838
- text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '
839
- # +
840
- # ' '+
841
- # '</br> (' + actual_spend_percentage.astype(int).astype(str) + '%)'
842
- ,textposition='outside',#textfont=dict(size=30),
843
- marker_color=light_blue))
844
-
845
-
846
- fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Optimized_spend'], name='Optimized',
847
- text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' '
848
- # +
849
- # '</br> (' + optimized_spend_percentage.astype(int).astype(str) + '%)'
850
- ,textposition='outside',#textfont=dict(size=30),
851
- marker_color=light_orange))
852
-
853
- fig.update_xaxes(title_text="Channels")
854
- fig.update_yaxes(title_text="Spends ($)")
855
- fig.update_layout(
856
- title = "Actual vs. Optimized Spends",
857
- margin=dict(t=40, b=40, l=40, r=40)
858
- )
859
-
860
- st.plotly_chart(fig,use_container_width=True)
861
-
862
- # Add actual vs optimized Contribution
863
- fig = go.Figure()
864
- fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Old_sales'],
865
- name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),textposition='outside',
866
- marker_color=light_blue,showlegend=True))
867
-
868
- fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['New_sales'],
869
- name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),textposition='outside',
870
- marker_color=light_orange, showlegend=True))
871
-
872
-
873
-
874
- fig.update_yaxes(title_text="Contribution")
875
- fig.update_xaxes(title_text="Channels")
876
- fig.update_layout(
877
- title = "Actual vs. Optimized Contributions",
878
- margin=dict(t=40, b=40, l=40, r=40)
879
- # yaxis=dict(range=[0, 0.002]),
880
- )
881
- st.plotly_chart(fig,use_container_width=True)
882
-
883
- # Add actual vs optimized Efficiency bars
884
- fig = go.Figure()
885
- summary_df_sorted_p = summary_df_sorted[summary_df_sorted['Channel_name']!="Panel"]
886
- fig.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'], y=summary_df_sorted_p['old_efficiency'],
887
- name='Actual Efficiency', text=summary_df_sorted_p['old_efficiency'].apply(format_number) ,textposition='outside',
888
- marker_color=light_blue,showlegend=True))
889
- fig.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'], y=summary_df_sorted_p['new_efficiency'],
890
- name='Optimized Efficiency',text=summary_df_sorted_p['new_efficiency'].apply(format_number),textposition='outside' ,
891
- marker_color=light_orange,showlegend=True))
892
-
893
- fig.update_xaxes(title_text="Channels")
894
- fig.update_yaxes(title_text="ROI")
895
- fig.update_layout(
896
- title = "Actual vs. Optimized ROI",
897
- margin=dict(t=40, b=40, l=40, r=40),
898
- # yaxis=dict(range=[0, 0.002]),
899
- )
900
-
901
- st.plotly_chart(fig,use_container_width=True)
902
-
903
-
904
- # Response Metrics
905
- directory = "metrics_level_data"
906
- metrics_list = get_excel_names(directory)
907
-
908
- # metrics_selected = col1.selectbox(
909
- # "Response Metrics",
910
- # metrics_list,
911
- # format_func=name_formating,
912
- # index=0,
913
- # on_change=reset_inputs,
914
- # )
915
-
916
- metrics_selected='prospects'
917
- # Target
918
- target = name_formating(metrics_selected)
919
-
920
- file_selected = (
921
- f"Overview_data_test_panel@#{metrics_selected}.xlsx"
922
- )
923
-
924
- # Panel List
925
- panel_list = panel_fetch(file_selected)
926
-
927
- # # Panel Selected
928
- # panel_selected = st.selectbox(
929
- # "Markets",
930
- # ["Total Market"] + panel_list,
931
- # index=0,
932
- # on_change=reset_inputs,
933
- # )
934
-
935
- # st.write(panel_selected)
936
- panel_selected = "Total Market"
937
- st.session_state['selected_markets']=panel_selected
938
-
939
- if "update_rcs" in st.session_state:
940
- updated_rcs = st.session_state["update_rcs"]
941
- else:
942
- updated_rcs = None
943
-
944
- if "first_time" not in st.session_state:
945
- st.session_state["first_time"] = True
946
-
947
- # Check if state is initiaized
948
- is_state_initiaized = st.session_state.get("initialized", False)
949
- if not is_state_initiaized or st.session_state["first_time"]:
950
- # initialize_data()
951
- if panel_selected == "Total Market":
952
- initialize_data(
953
- panel=panel_selected,
954
- target_file=file_selected,
955
- updated_rcs=updated_rcs,
956
- metrics=metrics_selected,
957
- )
958
- panel = None
959
- else:
960
- initialize_data(
961
- panel=panel_selected,
962
- target_file=file_selected,
963
- updated_rcs=updated_rcs,
964
- metrics=metrics_selected,
965
- )
966
- st.session_state["initialized"] = True
967
- st.session_state["first_time"] = False
968
-
969
- # initialize_data(
970
- # panel=panel_selected,
971
- # target_file=file_selected,
972
- # updated_rcs=updated_rcs,
973
- # metrics=metrics_selected,
974
- # )
975
- # st.session_state["initialized"] = True
976
- # st.session_state["first_time"] = False
977
-
978
- # Channels List
979
- channels_list = st.session_state["channels_list"]
980
-
981
- # ======================================================== #
982
- # ========================== UI ========================== #
983
- # ======================================================== #
984
-
985
- # print(list(st.session_state.keys()))
986
- main_header = st.columns((2, 2))
987
- sub_header = st.columns((1, 1, 1, 1))
988
- _scenario = st.session_state["scenario"]
989
-
990
- if "total_spends_change" not in st.session_state:
991
- st.session_state.total_spends_change = 0
992
-
993
- if "total_sales_change" not in st.session_state:
994
- st.session_state.total_sales_change = 0
995
-
996
- if "total_spends_change_abs" not in st.session_state:
997
- st.session_state["total_spends_change_abs"] = numerize(
998
- _scenario.actual_total_spends, 1
999
- )
1000
-
1001
- if "total_sales_change_abs" not in st.session_state:
1002
- st.session_state["total_sales_change_abs"] = numerize(
1003
- _scenario.actual_total_sales, 1
1004
- )
1005
-
1006
- if "total_spends_change_abs_slider" not in st.session_state:
1007
- st.session_state.total_spends_change_abs_slider = numerize(
1008
- _scenario.actual_total_spends, 1
1009
- )
1010
-
1011
- if "total_sales_change_abs_slider" not in st.session_state:
1012
- st.session_state.total_sales_change_abs_slider = numerize(
1013
- _scenario.actual_total_sales, 1
1014
- )
1015
-
1016
- with main_header[0]:
1017
- st.subheader("Actual")
1018
-
1019
- with main_header[-1]:
1020
- st.subheader("Simulated")
1021
-
1022
- with sub_header[0]:
1023
- st.metric(label="Spends", value=format_numbers(_scenario.actual_total_spends))
1024
-
1025
- with sub_header[1]:
1026
- st.metric(
1027
- label=target,
1028
- value=format_numbers_f(
1029
- float(_scenario.actual_total_sales)
1030
- ),
1031
- )
1032
-
1033
- with sub_header[2]:
1034
- st.metric(
1035
- label="Spends",
1036
- value=format_numbers(_scenario.modified_total_spends),
1037
- delta=numerize(_scenario.delta_spends, 1),
1038
- )
1039
-
1040
- with sub_header[3]:
1041
- st.metric(
1042
- label=target,
1043
- value=format_numbers_f(
1044
- float(_scenario.modified_total_sales)
1045
- ),
1046
- delta=numerize(_scenario.delta_sales, 1),
1047
- )
1048
-
1049
- with st.expander("Channel Spends Simulator", expanded=True):
1050
- _columns1 = st.columns((2, 2, 1, 1))
1051
- with _columns1[0]:
1052
- optimization_selection = st.selectbox(
1053
- "Optimize", options=["Media Spends", target], key="optimization_key"
1054
- )
1055
-
1056
- with _columns1[1]:
1057
- st.markdown("#")
1058
- # if st.checkbox(
1059
- # label="Optimize all Channels",
1060
- # key="optimze_all_channels",
1061
- # value=False,
1062
- # # on_change=select_all_channels_for_optimization,
1063
- # ):
1064
- # select_all_channels_for_optimization()
1065
-
1066
- st.checkbox(
1067
- label="Optimize all Channels",
1068
- key="optimze_all_channels",
1069
- value=False,
1070
- on_change=select_all_channels_for_optimization,
1071
- )
1072
-
1073
- with _columns1[2]:
1074
- st.markdown("#")
1075
- # st.button(
1076
- # "Optimize",
1077
- # on_click=optimize,
1078
- # args=(st.session_state["optimization_key"]),
1079
- # use_container_width=True,
1080
- # )
1081
-
1082
- optimize_placeholder = st.empty()
1083
-
1084
- with _columns1[3]:
1085
- st.markdown("#")
1086
- st.button(
1087
- "Reset",
1088
- on_click=reset_scenario,
1089
- args=(panel_selected, file_selected, updated_rcs),
1090
- # use_container_width=True,
1091
- )
1092
- # st.write(target)
1093
-
1094
-
1095
- _columns2 = st.columns((2, 2, 2))
1096
- if st.session_state["optimization_key"] == "Media Spends":
1097
- with _columns2[0]:
1098
- spend_input = st.text_input(
1099
- "Absolute",
1100
- key="total_spends_change_abs",
1101
- # label_visibility="collapsed",
1102
- on_change=update_all_spends_abs,
1103
- )
1104
-
1105
- with _columns2[1]:
1106
- st.number_input(
1107
- "Percent Change",
1108
- key="total_spends_change",
1109
- min_value=-50,
1110
- max_value=50,
1111
- step=1,
1112
- on_change=update_spends,
1113
- )
1114
-
1115
- with _columns2[2]:
1116
- min_value = round(_scenario.actual_total_spends * 0.5)
1117
- max_value = round(_scenario.actual_total_spends * 1.5)
1118
- st.session_state["total_spends_change_abs_slider_options"] = [
1119
- numerize(value, 1)
1120
- for value in range(min_value, max_value + 1, int(1e4))
1121
- ]
1122
-
1123
- # st.select_slider(
1124
- # "Absolute Slider",
1125
- # options=st.session_state["total_spends_change_abs_slider_options"],
1126
- # key="total_spends_change_abs_slider",
1127
- # on_change=update_all_spends_abs_slider,
1128
- # )
1129
-
1130
- elif st.session_state["optimization_key"] == target:
1131
- # st.write(target)
1132
- with _columns2[0]:
1133
- sales_input = st.text_input(
1134
- "Absolute",
1135
- key="total_sales_change_abs",
1136
- on_change=update_sales_abs,
1137
- )
1138
-
1139
- with _columns2[1]:
1140
- st.number_input(
1141
- "Percent Change",
1142
- key="total_sales_change",
1143
- min_value=-50,
1144
- max_value=50,
1145
- step=1,
1146
- on_change=update_sales,
1147
- )
1148
- with _columns2[2]:
1149
- min_value = round(_scenario.actual_total_sales * 0.5)
1150
- max_value = round(_scenario.actual_total_sales * 1.5)
1151
- st.write(min_value)
1152
- st.write(max_value)
1153
- # for value in range(min_value, max_value + 1, int(100)):
1154
- # st.write(numerize(value, 1))
1155
- st.session_state["total_sales_change_abs_slider_options"] = [
1156
- numerize(value, 1)
1157
- for value in range(min_value, max_value + 1, int(100))
1158
- ]
1159
-
1160
- st.select_slider(
1161
- "Absolute Slider",
1162
- options=st.session_state["total_sales_change_abs_slider_options"],
1163
- key="total_sales_change_abs_slider",
1164
- on_change=update_sales_abs_slider,
1165
- # value=numerize(min_value, 1)
1166
- )
1167
-
1168
- if (
1169
- not st.session_state["allow_sales_update"]
1170
- and optimization_selection == target
1171
- ):
1172
- st.warning("Invalid Input")
1173
-
1174
- if (
1175
- not st.session_state["allow_spends_update"]
1176
- and optimization_selection == "Media Spends"
1177
- ):
1178
- st.warning("Invalid Input")
1179
-
1180
- status_placeholder = st.empty()
1181
-
1182
- # if optimize_placeholder.button("Optimize", use_container_width=True):
1183
- # optimize(st.session_state["optimization_key"], status_placeholder)
1184
- # st.rerun()
1185
-
1186
- optimize_placeholder.button(
1187
- "Optimize",
1188
- on_click=optimize,
1189
- args=(st.session_state["optimization_key"], status_placeholder),
1190
- # use_container_width=True,
1191
- )
1192
-
1193
- st.markdown("""<hr class="spends-heading-seperator">""", unsafe_allow_html=True)
1194
- _columns = st.columns((2.5, 2, 1.5, 1.5, 1))
1195
- with _columns[0]:
1196
- generate_spending_header("Channel")
1197
- with _columns[1]:
1198
- generate_spending_header("Spends Input")
1199
- with _columns[2]:
1200
- generate_spending_header("Spends")
1201
- with _columns[3]:
1202
- generate_spending_header(target)
1203
- with _columns[4]:
1204
- generate_spending_header("Optimize")
1205
-
1206
- st.markdown("""<hr class="spends-heading-seperator">""", unsafe_allow_html=True)
1207
-
1208
- if "acutual_predicted" not in st.session_state:
1209
- st.session_state["acutual_predicted"] = {
1210
- "Channel_name": [],
1211
- "Actual_spend": [],
1212
- "Optimized_spend": [],
1213
- "Delta": [],
1214
- "New_sales":[],
1215
- "Old_sales":[]
1216
- }
1217
- for i, channel_name in enumerate(channels_list):
1218
- # st.write(channel_name)
1219
- _channel_class = st.session_state["scenario"].channels[channel_name]
1220
- _columns = st.columns((2.5, 1.5, 1.5, 1.5, 1))
1221
- with _columns[0]:
1222
- st.write(channel_name_formating(channel_name))
1223
- bin_placeholder = st.container()
1224
-
1225
- with _columns[1]:
1226
- channel_bounds = _channel_class.bounds
1227
- channel_spends = float(_channel_class.actual_total_spends)
1228
- min_value = float((1 + channel_bounds[0] / 100) * channel_spends)
1229
- max_value = float((1 + channel_bounds[1] / 100) * channel_spends)
1230
- ##print(st.session_state[channel_name])
1231
- spend_input = st.text_input(
1232
- channel_name,
1233
- key=channel_name,
1234
- label_visibility="collapsed",
1235
- on_change=partial(update_data, channel_name),
1236
- )
1237
- if not validate_input(spend_input):
1238
- st.error("Invalid input")
1239
-
1240
- channel_name_current = f"{channel_name}_change"
1241
-
1242
- st.number_input(
1243
- "Percent Change",
1244
- key=channel_name_current,
1245
- step=1,
1246
- on_change=partial(update_data_by_percent, channel_name),
1247
- )
1248
-
1249
- with _columns[2]:
1250
- # spends
1251
- current_channel_spends = float(
1252
- _channel_class.modified_total_spends
1253
- * _channel_class.conversion_rate
1254
- )
1255
- actual_channel_spends = float(
1256
- _channel_class.actual_total_spends * _channel_class.conversion_rate
1257
- )
1258
- spends_delta = float(
1259
- _channel_class.delta_spends * _channel_class.conversion_rate
1260
- )
1261
- st.session_state["acutual_predicted"]["Channel_name"].append(
1262
- channel_name
1263
- )
1264
- st.session_state["acutual_predicted"]["Actual_spend"].append(
1265
- actual_channel_spends
1266
- )
1267
- st.session_state["acutual_predicted"]["Optimized_spend"].append(
1268
- current_channel_spends
1269
- )
1270
- st.session_state["acutual_predicted"]["Delta"].append(spends_delta)
1271
- ## REMOVE
1272
- st.metric(
1273
- "Spends",
1274
- format_numbers(current_channel_spends),
1275
- delta=numerize(spends_delta, 1),
1276
- label_visibility="collapsed",
1277
- )
1278
-
1279
- with _columns[3]:
1280
- # sales
1281
- current_channel_sales = float(_channel_class.modified_total_sales)
1282
- actual_channel_sales = float(_channel_class.actual_total_sales)
1283
- sales_delta = float(_channel_class.delta_sales)
1284
- st.session_state["acutual_predicted"]["Old_sales"].append(actual_channel_sales)
1285
- st.session_state["acutual_predicted"]["New_sales"].append(current_channel_sales)
1286
- #st.write(actual_channel_sales)
1287
-
1288
- st.metric(
1289
- target,
1290
- format_numbers_f(current_channel_sales),
1291
- delta=numerize(sales_delta, 1),
1292
- label_visibility="collapsed",
1293
- )
1294
-
1295
- with _columns[4]:
1296
-
1297
- # if st.checkbox(
1298
- # label="select for optimization",
1299
- # key=f"{channel_name}_selected",
1300
- # value=False,
1301
- # # on_change=partial(select_channel_for_optimization, channel_name),
1302
- # label_visibility="collapsed",
1303
- # ):
1304
- # select_channel_for_optimization(channel_name)
1305
-
1306
- st.checkbox(
1307
- label="select for optimization",
1308
- key=f"{channel_name}_selected",
1309
- value=False,
1310
- on_change=partial(select_channel_for_optimization, channel_name),
1311
- label_visibility="collapsed",
1312
- )
1313
-
1314
- st.markdown(
1315
- """<hr class="spends-child-seperator">""",
1316
- unsafe_allow_html=True,
1317
- )
1318
-
1319
- # Bins
1320
- col = channels_list[i]
1321
- x_actual = st.session_state["scenario"].channels[col].actual_spends
1322
- x_modified = st.session_state["scenario"].channels[col].modified_spends
1323
- # x_modified_total = 0
1324
- # for c in channels_list:
1325
- # # st.write(c)
1326
- # # st.write(st.session_state["scenario"].channels[c].modified_spends)
1327
- # x_modified_total = x_modified_total + st.session_state["scenario"].channels[c].modified_spends.sum()
1328
- # st.write(x_modified_total)
1329
-
1330
- x_total = x_modified.sum()
1331
- power = np.ceil(np.log(x_actual.max()) / np.log(10)) - 3
1332
-
1333
- updated_rcs_key = f"{metrics_selected}#@{panel_selected}#@{channel_name}"
1334
-
1335
- if updated_rcs and updated_rcs_key in list(updated_rcs.keys()):
1336
- K = updated_rcs[updated_rcs_key]["K"]
1337
- b = updated_rcs[updated_rcs_key]["b"]
1338
- a = updated_rcs[updated_rcs_key]["a"]
1339
- x0 = updated_rcs[updated_rcs_key]["x0"]
1340
- else:
1341
- K = st.session_state["rcs"][col]["K"]
1342
- b = st.session_state["rcs"][col]["b"]
1343
- a = st.session_state["rcs"][col]["a"]
1344
- x0 = st.session_state["rcs"][col]["x0"]
1345
-
1346
- x_plot = np.linspace(0, 5 * x_actual.sum(), 200)
1347
-
1348
- # Append current_channel_spends to the end of x_plot
1349
- x_plot = np.append(x_plot, current_channel_spends)
1350
-
1351
- x, y, marginal_roi = [], [], []
1352
- for x_p in x_plot:
1353
- x.append(x_p * x_actual / x_actual.sum())
1354
-
1355
- for index in range(len(x_plot)):
1356
- y.append(s_curve(x[index] / 10**power, K, b, a, x0))
1357
-
1358
- for index in range(len(x_plot)):
1359
- marginal_roi.append(
1360
- a * y[index] * (1 - y[index] / np.maximum(K, np.finfo(float).eps))
1361
- )
1362
-
1363
- x = (
1364
- np.sum(x, axis=1)
1365
- * st.session_state["scenario"].channels[col].conversion_rate
1366
- )
1367
- y = np.sum(y, axis=1)
1368
- marginal_roi = (
1369
- np.average(marginal_roi, axis=1)
1370
- / st.session_state["scenario"].channels[col].conversion_rate
1371
- )
1372
-
1373
- roi = y / np.maximum(x, np.finfo(float).eps)
1374
- # roi = (y/np.sum(y))/(x/np.sum(x))
1375
- # st.write(x)
1376
- # st.write(y)
1377
- # st.write(roi)
1378
-
1379
- # st.write(roi[-1])
1380
-
1381
- roi_current, marginal_roi_current = roi[-1], marginal_roi[-1]
1382
- x, y, roi, marginal_roi = (
1383
- x[:-1],
1384
- y[:-1],
1385
- roi[:-1],
1386
- marginal_roi[:-1],
1387
- ) # Drop data for current spends
1388
-
1389
- # roi_current =
1390
-
1391
- start_value, end_value, left_value, right_value = find_segment_value(
1392
- x,
1393
- roi,
1394
- marginal_roi,
1395
- )
1396
-
1397
- #st.write(roi_current)
1398
-
1399
- rgba = calculate_rgba(
1400
- start_value,
1401
- end_value,
1402
- left_value,
1403
- right_value,
1404
- current_channel_spends,
1405
- )
1406
-
1407
- summary_df = pd.DataFrame(st.session_state["acutual_predicted"])
1408
- # st.dataframe(summary_df)
1409
- summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True)
1410
- # st.dataframe(summary_df)
1411
-
1412
- summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False)
1413
- summary_df_sorted["Delta_percent"] = np.round(
1414
- ((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1)
1415
- * 100,
1416
- 2,
1417
- )
1418
-
1419
- summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
1420
- summary_df_sorted['old_efficiency']=(summary_df_sorted['Old_sales']/summary_df_sorted['Old_sales'].sum())/(summary_df_sorted['Actual_spend']/summary_df_sorted['Actual_spend'].sum())
1421
- summary_df_sorted['new_efficiency']=(summary_df_sorted['New_sales']/summary_df_sorted['New_sales'].sum())/(summary_df_sorted['Optimized_spend']/summary_df_sorted['Optimized_spend'].sum())
1422
-
1423
- a = (summary_df_sorted[summary_df_sorted['Channel_name']== col]).reset_index()['new_efficiency'][0]
1424
- # st.write(a)
1425
-
1426
- with bin_placeholder:
1427
- st.markdown(
1428
- f"""
1429
- <div style="
1430
- border-radius: 12px;
1431
- background-color: {rgba};
1432
- padding: 10px;
1433
- text-align: center;
1434
- color: #006EC0;
1435
- ">
1436
- <p style="margin: 0; font-size: 20px;">Efficiency: {round(a,2)}</p>
1437
- <!--<p style="margin: 0; font-size: 20px;">Marginal ROI: {round(marginal_roi_current,1)}</p>-->
1438
- </div>
1439
- """,
1440
- unsafe_allow_html=True,
1441
- )
1442
-
1443
- # with st.expander("See Response Curves", expanded=True):
1444
- # fig = plot_response_curves(summary_df_sorted)
1445
- # # st.plotly_chart(rc.response_curves(col))
1446
- # # st.plotly_chart(fig, use_container_width=True)
1447
-
1448
- summary_df = pd.DataFrame(st.session_state["acutual_predicted"])
1449
- # st.dataframe(summary_df)
1450
- summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True)
1451
- # st.dataframe(summary_df)
1452
-
1453
- summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False)
1454
- summary_df_sorted["Delta_percent"] = np.round(
1455
- ((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1)
1456
- * 100,
1457
- 2,
1458
- )
1459
-
1460
-
1461
-
1462
-
1463
-
1464
- with open("summary_df.pkl", "wb") as f:
1465
- pickle.dump(summary_df_sorted, f)
1466
- # st.dataframe(summary_df_sorted)
1467
- # ___columns=st.columns(3)
1468
- # with ___columns[2]:
1469
- # fig=summary_plot(summary_df_sorted, x='Delta_percent', y='Channel_name', title='Delta', text_column='Delta_percent')
1470
- # st.plotly_chart(fig,use_container_width=True)
1471
- # with ___columns[0]:
1472
- # fig=summary_plot(summary_df_sorted, x='Actual_spend', y='Channel_name', title='Actual Spend', text_column='Actual_spend')
1473
- # st.plotly_chart(fig,use_container_width=True)
1474
- # with ___columns[1]:
1475
- # fig=summary_plot(summary_df_sorted, x='Optimized_spend', y='Channel_name', title='Planned Spend', text_column='Optimized_spend')
1476
- # st.plotly_chart(fig,use_container_width=True)
1477
-
1478
- scenario_planner_plots()
1479
-
1480
- _columns = st.columns(2)
1481
- # with _columns[0]:
1482
- st.subheader("Save Scenario")
1483
- scenario_name = st.text_input(
1484
- "Scenario name",
1485
- key="scenario_input",
1486
- placeholder="Scenario name",
1487
- label_visibility="collapsed",
1488
- )
1489
- st.button(
1490
- "Save",
1491
- on_click=lambda: save_scenario(scenario_name),
1492
- disabled=len(st.session_state["scenario_input"]) == 0,#use_container_width=True
1493
- )
1494
-
1495
-
1496
-
1497
- elif auth_status == False:
1498
- st.error("Username/Password is incorrect")
1499
-
1500
- if auth_status != True:
1501
- try:
1502
- username_forgot_pw, email_forgot_password, random_password = (
1503
- authenticator.forgot_password("Forgot password")
1504
- )
1505
- if username_forgot_pw:
1506
- st.session_state["config"]["credentials"]["usernames"][username_forgot_pw][
1507
- "password"
1508
- ] = stauth.Hasher([random_password]).generate()[0]
1509
- send_email(email_forgot_password, random_password)
1510
- st.success("New password sent securely")
1511
- # Random password to be transferred to user securely
1512
- elif username_forgot_pw == False:
1513
- st.error("Username not found")
1514
- except Exception as e:
1515
- st.error(e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/9_Saved_Scenarios.py DELETED
@@ -1,280 +0,0 @@
1
- import streamlit as st
2
- from numerize.numerize import numerize
3
- import io
4
- import pandas as pd
5
- from utilities import (format_numbers,decimal_formater,
6
- channel_name_formating,
7
- load_local_css,set_header,
8
- initialize_data,
9
- load_authenticator)
10
- from openpyxl import Workbook
11
- from openpyxl.styles import Alignment,Font,PatternFill
12
- import pickle
13
- import streamlit_authenticator as stauth
14
- import yaml
15
- from yaml import SafeLoader
16
- from classes import class_from_dict
17
-
18
- st.set_page_config(layout='wide')
19
- load_local_css('styles.css')
20
- set_header()
21
-
22
- # for k, v in st.session_state.items():
23
- # if k not in ['logout', 'login','config'] and not k.startswith('FormSubmitter'):
24
- # st.session_state[k] = v
25
-
26
- def create_scenario_summary(scenario_dict):
27
- summary_rows = []
28
- for channel_dict in scenario_dict['channels']:
29
- name_mod = channel_name_formating(channel_dict['name'])
30
- summary_rows.append([name_mod,
31
- channel_dict.get('actual_total_spends') * channel_dict.get('conversion_rate'),
32
- channel_dict.get('modified_total_spends') * channel_dict.get('conversion_rate'),
33
- channel_dict.get('actual_total_sales') ,
34
- channel_dict.get('modified_total_sales'),
35
- # channel_dict.get('actual_total_sales') / (channel_dict.get('actual_total_spends') * channel_dict.get('conversion_rate')),
36
- # channel_dict.get('modified_total_sales') / (channel_dict.get('modified_total_spends') * channel_dict.get('conversion_rate')),
37
- # channel_dict.get('actual_mroi'),
38
- # channel_dict.get('modified_mroi'),
39
- # channel_dict.get('actual_total_spends') * channel_dict.get('conversion_rate') / channel_dict.get('actual_total_sales'),
40
- # channel_dict.get('modified_total_spends') * channel_dict.get('conversion_rate') / channel_dict.get('modified_total_sales')
41
- ])
42
-
43
- summary_rows.append(['Total',
44
- scenario_dict.get('actual_total_spends'),
45
- scenario_dict.get('modified_total_spends'),
46
- scenario_dict.get('actual_total_sales'),
47
- scenario_dict.get('modified_total_sales'),
48
- # scenario_dict.get('actual_total_sales') / scenario_dict.get('actual_total_spends'),
49
- # scenario_dict.get('modified_total_sales') / scenario_dict.get('modified_total_spends'),
50
- # '-',
51
- # '-',
52
- # scenario_dict.get('actual_total_spends') / scenario_dict.get('actual_total_sales'),
53
- # scenario_dict.get('modified_total_spends') / scenario_dict.get('modified_total_sales')
54
- ])
55
-
56
- columns_index = pd.MultiIndex.from_product([[''],['Channel']], names=["first", "second"])
57
- columns_index = columns_index.append(pd.MultiIndex.from_product([['Spends','Prospects'
58
- #,'ROI','MROI','Spend per NRPU'
59
- ],['Actual','Simulated']], names=["first", "second"]))
60
- return pd.DataFrame(summary_rows, columns=columns_index)
61
-
62
-
63
-
64
- def summary_df_to_worksheet(df, ws):
65
- heading_fill = PatternFill(fill_type='solid',start_color='FF11B6BD',end_color='FF11B6BD')
66
- for j,header in enumerate(df.columns.values):
67
- col = j + 1
68
- for i in range(1,3):
69
- ws.cell(row=i, column=j + 1, value=header[i - 1]).font = Font(bold=True, color='FF11B6BD')
70
- ws.cell(row=i,column=j+1).fill = heading_fill
71
- if col > 1 and (col - 6)%5==0:
72
- ws.merge_cells(start_row=1, end_row=1, start_column = col-3, end_column=col)
73
- ws.cell(row=1,column=col).alignment = Alignment(horizontal='center')
74
- for i,row in enumerate(df.itertuples()):
75
- for j,value in enumerate(row):
76
- if j == 0:
77
- continue
78
- elif (j-2)%4 == 0 or (j-3)%4 == 0:
79
- ws.cell(row=i+3, column = j, value=value).number_format = '$#,##0.0'
80
- else:
81
- ws.cell(row=i+3, column = j, value=value)
82
-
83
- from openpyxl.utils import get_column_letter
84
- from openpyxl.styles import Font, PatternFill
85
- import logging
86
-
87
- def scenario_df_to_worksheet(df, ws):
88
- heading_fill = PatternFill(start_color='FF11B6BD', end_color='FF11B6BD', fill_type='solid')
89
-
90
- for j, header in enumerate(df.columns.values):
91
- cell = ws.cell(row=1, column=j + 1, value=header)
92
- cell.font = Font(bold=True, color='FF11B6BD')
93
- cell.fill = heading_fill
94
-
95
- for i, row in enumerate(df.itertuples()):
96
- for j, value in enumerate(row[1:], start=1): # Start from index 1 to skip the index column
97
- try:
98
- cell = ws.cell(row=i + 2, column=j, value=value)
99
- if isinstance(value, (int, float)):
100
- cell.number_format = '$#,##0.0'
101
- elif isinstance(value, str):
102
- cell.value = value[:32767]
103
- else:
104
- cell.value = str(value)
105
- except ValueError as e:
106
- logging.error(f"Error assigning value '{value}' to cell {get_column_letter(j)}{i+2}: {e}")
107
- cell.value = None # Assign None to the cell where the error occurred
108
-
109
- return ws
110
-
111
-
112
-
113
-
114
-
115
-
116
- def download_scenarios():
117
- """
118
- Makes a excel with all saved scenarios and saves it locally
119
- """
120
- ## create summary page
121
- if len(scenarios_to_download) == 0:
122
- return
123
- wb = Workbook()
124
- wb.iso_dates = True
125
- wb.remove(wb.active)
126
- st.session_state['xlsx_buffer'] = io.BytesIO()
127
- summary_df = None
128
- #print(scenarios_to_download)
129
- for scenario_name in scenarios_to_download:
130
- scenario_dict = st.session_state['saved_scenarios'][scenario_name]
131
- _spends = []
132
- column_names = ['Date']
133
- _sales = None
134
- dates = None
135
- summary_rows = []
136
- for channel in scenario_dict['channels']:
137
- if dates is None:
138
- dates = channel.get('dates')
139
- _spends.append(dates)
140
- if _sales is None:
141
- _sales = channel.get('modified_sales')
142
- else:
143
- _sales += channel.get('modified_sales')
144
- _spends.append(channel.get('modified_spends') * channel.get('conversion_rate'))
145
- column_names.append(channel.get('name'))
146
-
147
- name_mod = channel_name_formating(channel['name'])
148
- summary_rows.append([name_mod,
149
- channel.get('modified_total_spends') * channel.get('conversion_rate') ,
150
- channel.get('modified_total_sales'),
151
- channel.get('modified_total_sales') / channel.get('modified_total_spends') * channel.get('conversion_rate'),
152
- channel.get('modified_mroi'),
153
- channel.get('modified_total_sales') / channel.get('modified_total_spends') * channel.get('conversion_rate')])
154
- _spends.append(_sales)
155
- column_names.append('NRPU')
156
- scenario_df = pd.DataFrame(_spends).T
157
- scenario_df.columns = column_names
158
- ## write to sheet
159
- ws = wb.create_sheet(scenario_name)
160
- scenario_df_to_worksheet(scenario_df, ws)
161
- summary_rows.append(['Total',
162
- scenario_dict.get('modified_total_spends') ,
163
- scenario_dict.get('modified_total_sales'),
164
- scenario_dict.get('modified_total_sales') / scenario_dict.get('modified_total_spends'),
165
- '-',
166
- scenario_dict.get('modified_total_spends') / scenario_dict.get('modified_total_sales')])
167
- columns_index = pd.MultiIndex.from_product([[''],['Channel']], names=["first", "second"])
168
- columns_index = columns_index.append(pd.MultiIndex.from_product([[scenario_name],['Spends','NRPU','ROI','MROI','Spends per NRPU']], names=["first", "second"]))
169
- if summary_df is None:
170
- summary_df = pd.DataFrame(summary_rows, columns = columns_index)
171
- summary_df = summary_df.set_index(('','Channel'))
172
- else:
173
- _df = pd.DataFrame(summary_rows, columns = columns_index)
174
- _df = _df.set_index(('','Channel'))
175
- summary_df = summary_df.merge(_df, left_index=True, right_index=True)
176
- ws = wb.create_sheet('Summary',0)
177
- summary_df_to_worksheet(summary_df.reset_index(), ws)
178
- wb.save(st.session_state['xlsx_buffer'])
179
- st.session_state['disable_download_button'] = False
180
-
181
- def disable_download_button():
182
- st.session_state['disable_download_button'] =True
183
-
184
- def transform(x):
185
- if x.name == ("",'Channel'):
186
- return x
187
- elif x.name[0] == 'ROI' or x.name[0] == 'MROI':
188
- return x.apply(lambda y : y if isinstance(y,str) else decimal_formater(format_numbers(y,include_indicator=False,n_decimals=4),n_decimals=4))
189
- else:
190
- return x.apply(lambda y : y if isinstance(y,str) else format_numbers(y))
191
-
192
- def delete_scenario():
193
- if selected_scenario in st.session_state['saved_scenarios']:
194
- del st.session_state['saved_scenarios'][selected_scenario]
195
- with open('../saved_scenarios.pkl', 'wb') as f:
196
- pickle.dump(st.session_state['saved_scenarios'],f)
197
-
198
- def load_scenario():
199
- if selected_scenario in st.session_state['saved_scenarios']:
200
- st.session_state['scenario'] = class_from_dict(selected_scenario_details)
201
-
202
-
203
-
204
- authenticator = st.session_state.get('authenticator')
205
- if authenticator is None:
206
- authenticator = load_authenticator()
207
-
208
- name, authentication_status, username = authenticator.login('Login', 'main')
209
- auth_status = st.session_state.get('authentication_status')
210
-
211
- if auth_status == True:
212
- is_state_initiaized = st.session_state.get('initialized',False)
213
- if not is_state_initiaized:
214
- #print("Scenario page state reloaded")
215
- initialize_data()
216
-
217
-
218
- saved_scenarios = st.session_state['saved_scenarios']
219
-
220
-
221
- if len(saved_scenarios) ==0:
222
- st.header('No saved scenarios')
223
-
224
- else:
225
-
226
- with st.sidebar:
227
- selected_scenario = st.radio(
228
- 'Pick a scenario to view details',
229
- list(saved_scenarios.keys())
230
- )
231
- st.markdown("""<hr>""", unsafe_allow_html=True)
232
- scenarios_to_download = st.multiselect('Select scenarios to download',
233
- list(saved_scenarios.keys()))
234
-
235
- st.button('Prepare download',on_click=download_scenarios)
236
- st.download_button(
237
- label="Download Scenarios",
238
- data=st.session_state['xlsx_buffer'].getvalue(),
239
- file_name="scenarios.xlsx",
240
- mime="application/vnd.ms-excel",
241
- disabled= st.session_state['disable_download_button'],
242
- on_click= disable_download_button
243
- )
244
-
245
- column_1, column_2,column_3 = st.columns((6,1,1))
246
- with column_1:
247
- st.header(selected_scenario)
248
- with column_2:
249
- st.button('Delete scenarios', on_click=delete_scenario)
250
- with column_3:
251
- st.button('Load Scenario', on_click=load_scenario)
252
-
253
- selected_scenario_details = saved_scenarios[selected_scenario]
254
-
255
- pd.set_option('display.max_colwidth', 100)
256
-
257
- st.markdown(create_scenario_summary(selected_scenario_details).transform(transform).style.set_table_styles(
258
- [{
259
- 'selector': 'th',
260
- 'props': [('background-color', '#11B6BD')]
261
- },
262
- {
263
- 'selector' : 'tr:nth-child(even)',
264
- 'props' : [('background-color', '#11B6BD')]
265
- }
266
- ]).to_html(),unsafe_allow_html=True)
267
-
268
- elif auth_status == False:
269
- st.error('Username/Password is incorrect')
270
-
271
- if auth_status != True:
272
- try:
273
- username_forgot_pw, email_forgot_password, random_password = authenticator.forgot_password('Forgot password')
274
- if username_forgot_pw:
275
- st.success('New password sent securely')
276
- # Random password to be transferred to user securely
277
- elif username_forgot_pw == False:
278
- st.error('Username not found')
279
- except Exception as e:
280
- st.error(e)