Spaces:
Sleeping
Sleeping
Pragya Jatav
commited on
Commit
·
7202334
1
Parent(s):
8351d98
test1
Browse files- Model_Result_Overview.py +124 -133
- README.md +1 -1
- Test/scenario_test_df.csv +104 -104
- __pycache__/utilities.cpython-310.pyc +0 -0
- __pycache__/utilities_with_panel.cpython-310.pyc +0 -0
- pages/8_Scenario_Planner.py +309 -342
- summary_df.pkl +2 -2
- utilities.py +5 -0
- utilities_with_panel.py +18 -18
Model_Result_Overview.py
CHANGED
|
@@ -1,12 +1,3 @@
|
|
| 1 |
-
'''
|
| 2 |
-
MMO Build Sprint 3
|
| 3 |
-
additions : contributions calculated using tuned Mixed LM model
|
| 4 |
-
pending : contributions calculations using - 1. not tuned Mixed LM model, 2. tuned OLS model, 3. not tuned OLS model
|
| 5 |
-
|
| 6 |
-
MMO Build Sprint 4
|
| 7 |
-
additions : response metrics selection
|
| 8 |
-
pending : contributions calculations using - 1. not tuned Mixed LM model, 2. tuned OLS model, 3. not tuned OLS model
|
| 9 |
-
'''
|
| 10 |
|
| 11 |
import streamlit as st
|
| 12 |
import pandas as pd
|
|
@@ -38,175 +29,175 @@ load_local_css('styles.css')
|
|
| 38 |
set_header()
|
| 39 |
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
|
| 50 |
-
|
| 51 |
|
| 52 |
|
| 53 |
-
|
| 54 |
-
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
|
| 79 |
-
|
| 80 |
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
|
| 85 |
-
#
|
| 86 |
-
#
|
| 87 |
-
#
|
| 88 |
-
|
| 89 |
-
|
| 90 |
|
| 91 |
-
#
|
| 92 |
|
| 93 |
-
|
| 94 |
|
| 95 |
-
#
|
| 96 |
-
|
| 97 |
-
|
| 98 |
|
| 99 |
-
|
| 100 |
-
|
| 101 |
|
| 102 |
-
|
| 103 |
|
| 104 |
-
|
| 105 |
-
|
| 106 |
|
| 107 |
-
|
| 108 |
-
|
| 109 |
|
| 110 |
-
|
| 111 |
-
|
| 112 |
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
|
| 117 |
-
|
| 118 |
-
|
| 119 |
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
|
| 126 |
-
|
| 127 |
|
| 128 |
-
|
| 129 |
-
|
| 130 |
|
| 131 |
-
|
| 132 |
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
|
| 138 |
-
|
| 139 |
-
|
| 140 |
|
| 141 |
|
| 142 |
-
|
| 143 |
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
|
| 149 |
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
#
|
| 155 |
-
#
|
| 156 |
-
|
| 157 |
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
|
| 164 |
|
| 165 |
-
|
| 166 |
-
|
| 167 |
|
| 168 |
-
|
| 169 |
-
#
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
|
| 181 |
-
|
| 182 |
-
|
| 183 |
|
| 184 |
-
|
| 185 |
-
|
| 186 |
|
| 187 |
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
|
| 193 |
-
|
| 194 |
-
|
| 195 |
|
| 196 |
-
|
| 197 |
|
| 198 |
-
|
| 199 |
|
| 200 |
-
#
|
| 201 |
-
#
|
| 202 |
|
| 203 |
-
#
|
| 204 |
-
#
|
| 205 |
-
#
|
| 206 |
-
#
|
| 207 |
-
#
|
| 208 |
-
#
|
| 209 |
-
#
|
| 210 |
-
#
|
| 211 |
-
#
|
| 212 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
|
| 2 |
import streamlit as st
|
| 3 |
import pandas as pd
|
|
|
|
| 29 |
set_header()
|
| 30 |
|
| 31 |
|
| 32 |
+
def get_random_effects(media_data, panel_col, mdf):
|
| 33 |
+
random_eff_df = pd.DataFrame(columns=[panel_col, "random_effect"])
|
| 34 |
|
| 35 |
+
for i, market in enumerate(media_data[panel_col].unique()):
|
| 36 |
+
print(i, end='\r')
|
| 37 |
+
intercept = mdf.random_effects[market].values[0]
|
| 38 |
+
random_eff_df.loc[i, 'random_effect'] = intercept
|
| 39 |
+
random_eff_df.loc[i, panel_col] = market
|
| 40 |
|
| 41 |
+
return random_eff_df
|
| 42 |
|
| 43 |
|
| 44 |
+
def process_train_and_test(train, test, features, panel_col, target_col):
|
| 45 |
+
X1 = train[features]
|
| 46 |
|
| 47 |
+
ss = MinMaxScaler()
|
| 48 |
+
X1 = pd.DataFrame(ss.fit_transform(X1), columns=X1.columns)
|
| 49 |
|
| 50 |
+
X1[panel_col] = train[panel_col]
|
| 51 |
+
X1[target_col] = train[target_col]
|
| 52 |
|
| 53 |
+
if test is not None:
|
| 54 |
+
X2 = test[features]
|
| 55 |
+
X2 = pd.DataFrame(ss.transform(X2), columns=X2.columns)
|
| 56 |
+
X2[panel_col] = test[panel_col]
|
| 57 |
+
X2[target_col] = test[target_col]
|
| 58 |
+
return X1, X2
|
| 59 |
+
return X1
|
| 60 |
|
| 61 |
+
def mdf_predict(X_df, mdf, random_eff_df) :
|
| 62 |
+
X=X_df.copy()
|
| 63 |
+
X=pd.merge(X, random_eff_df[[panel_col,'random_effect']], on=panel_col, how='left')
|
| 64 |
+
X['pred_fixed_effect'] = mdf.predict(X)
|
| 65 |
|
| 66 |
+
X['pred'] = X['pred_fixed_effect'] + X['random_effect']
|
| 67 |
+
X.to_csv('Test/merged_df_contri.csv',index=False)
|
| 68 |
+
X.drop(columns=['pred_fixed_effect', 'random_effect'], inplace=True)
|
| 69 |
|
| 70 |
+
return X
|
| 71 |
|
| 72 |
|
| 73 |
+
target_col='Prospects'
|
| 74 |
+
target='Prospects'
|
| 75 |
|
| 76 |
+
# is_panel=False
|
| 77 |
+
# is_panel = st.session_state['is_panel']
|
| 78 |
+
#panel_col = [col.lower().replace('.','_').replace('@','_').replace(" ", "_").replace('-', '').replace(':', '').replace("__", "_") for col in st.session_state['bin_dict']['Panel Level 1'] ] [0]# set the panel column
|
| 79 |
+
panel_col='Panel'
|
| 80 |
+
date_col = 'date'
|
| 81 |
|
| 82 |
+
#st.write(media_data)
|
| 83 |
|
| 84 |
+
is_panel = True
|
| 85 |
|
| 86 |
+
# panel_col='markets'
|
| 87 |
+
date_col = 'date'
|
| 88 |
+
for k, v in st.session_state.items():
|
| 89 |
|
| 90 |
+
if k not in ['logout', 'login','config'] and not k.startswith('FormSubmitter'):
|
| 91 |
+
st.session_state[k] = v
|
| 92 |
|
| 93 |
+
authenticator = st.session_state.get('authenticator')
|
| 94 |
|
| 95 |
+
if authenticator is None:
|
| 96 |
+
authenticator = load_authenticator()
|
| 97 |
|
| 98 |
+
name, authentication_status, username = authenticator.login('Login', 'main')
|
| 99 |
+
auth_status = st.session_state['authentication_status']
|
| 100 |
|
| 101 |
+
if auth_status:
|
| 102 |
+
authenticator.logout('Logout', 'main')
|
| 103 |
|
| 104 |
+
is_state_initiaized = st.session_state.get('initialized',False)
|
| 105 |
+
if not is_state_initiaized:
|
| 106 |
+
a=1
|
| 107 |
|
| 108 |
+
def panel_fetch(file_selected):
|
| 109 |
+
raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
|
| 110 |
|
| 111 |
+
if "Panel" in raw_data_mmm_df.columns:
|
| 112 |
+
panel = list(set(raw_data_mmm_df["Panel"]))
|
| 113 |
+
else:
|
| 114 |
+
raw_data_mmm_df = None
|
| 115 |
+
panel = None
|
| 116 |
|
| 117 |
+
return panel
|
| 118 |
|
| 119 |
+
def rerun():
|
| 120 |
+
st.rerun()
|
| 121 |
|
| 122 |
+
metrics_selected='prospects'
|
| 123 |
|
| 124 |
+
file_selected = (
|
| 125 |
+
f"Overview_data_test_panel@#{metrics_selected}.xlsx"
|
| 126 |
+
)
|
| 127 |
+
panel_list = panel_fetch(file_selected)
|
| 128 |
|
| 129 |
+
if "selected_markets" not in st.session_state:
|
| 130 |
+
st.session_state['selected_markets']='DMA1'
|
| 131 |
|
| 132 |
|
| 133 |
+
st.header('Overview of previous spends')
|
| 134 |
|
| 135 |
+
selected_market= st.selectbox(
|
| 136 |
+
"Select Markets",
|
| 137 |
+
["Total Market"] + panel_list
|
| 138 |
+
)
|
| 139 |
|
| 140 |
|
| 141 |
|
| 142 |
+
initialize_data(target_col,selected_market)
|
| 143 |
+
scenario = st.session_state['scenario']
|
| 144 |
+
raw_df = st.session_state['raw_df']
|
| 145 |
+
# st.write(scenario.actual_total_spends)
|
| 146 |
+
# st.write(scenario.actual_total_sales)
|
| 147 |
+
columns = st.columns((1,1,3))
|
| 148 |
|
| 149 |
+
with columns[0]:
|
| 150 |
+
st.metric(label='Spends', value=format_numbers(float(scenario.actual_total_spends)))
|
| 151 |
+
###print(f"##################### {scenario.actual_total_sales} ##################")
|
| 152 |
+
with columns[1]:
|
| 153 |
+
st.metric(label=target, value=format_numbers(float(scenario.actual_total_sales),include_indicator=False))
|
| 154 |
|
| 155 |
|
| 156 |
+
actual_summary_df = create_channel_summary(scenario)
|
| 157 |
+
actual_summary_df['Channel'] = actual_summary_df['Channel'].apply(channel_name_formating)
|
| 158 |
|
| 159 |
+
columns = st.columns((2,1))
|
| 160 |
+
#with columns[0]:
|
| 161 |
+
with st.expander('Channel wise overview'):
|
| 162 |
+
st.markdown(actual_summary_df.style.set_table_styles(
|
| 163 |
+
[{
|
| 164 |
+
'selector': 'th',
|
| 165 |
+
'props': [('background-color', '#FFFFF')]
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
'selector' : 'tr:nth-child(even)',
|
| 169 |
+
'props' : [('background-color', '#FFFFF')]
|
| 170 |
+
}]).to_html(), unsafe_allow_html=True)
|
| 171 |
|
| 172 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
| 173 |
+
##############################
|
| 174 |
|
| 175 |
+
st.plotly_chart(create_contribution_pie(scenario),use_container_width=True)
|
| 176 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
| 177 |
|
| 178 |
|
| 179 |
+
################################3
|
| 180 |
+
st.plotly_chart(create_contribuion_stacked_plot(scenario),use_container_width=True)
|
| 181 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
| 182 |
+
#######################################
|
| 183 |
|
| 184 |
+
selected_channel_name = st.selectbox('Channel', st.session_state['channels_list'] + ['non media'], format_func=channel_name_formating)
|
| 185 |
+
selected_channel = scenario.channels.get(selected_channel_name,None)
|
| 186 |
|
| 187 |
+
st.plotly_chart(create_channel_spends_sales_plot(selected_channel), use_container_width=True)
|
| 188 |
|
| 189 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
| 190 |
|
| 191 |
+
# elif auth_status == False:
|
| 192 |
+
# st.error('Username/Password is incorrect')
|
| 193 |
|
| 194 |
+
# if auth_status != True:
|
| 195 |
+
# try:
|
| 196 |
+
# username_forgot_pw, email_forgot_password, random_password = authenticator.forgot_password('Forgot password')
|
| 197 |
+
# if username_forgot_pw:
|
| 198 |
+
# st.success('New password sent securely')
|
| 199 |
+
# # Random password to be transferred to user securely
|
| 200 |
+
# elif username_forgot_pw == False:
|
| 201 |
+
# st.error('Username not found')
|
| 202 |
+
# except Exception as e:
|
| 203 |
+
# st.error(e)
|
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
emoji: 🏆
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: pink
|
|
|
|
| 1 |
---
|
| 2 |
+
title: UOPX
|
| 3 |
emoji: 🏆
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: pink
|
Test/scenario_test_df.csv
CHANGED
|
@@ -1,105 +1,105 @@
|
|
| 1 |
other_contributions,correction,sales
|
| 2 |
-
1,-890.
|
| 3 |
-
1,-475.
|
| 4 |
-
1,-3.
|
| 5 |
-
1,-55.
|
| 6 |
-
1,-556.
|
| 7 |
-
1,-798.
|
| 8 |
-
1,-831.
|
| 9 |
-
1,-747.
|
| 10 |
-
1,-420.
|
| 11 |
-
1,-271.
|
| 12 |
-
1,36.
|
| 13 |
-
1,301.
|
| 14 |
-
1,-149.
|
| 15 |
-
1,-178.
|
| 16 |
-
1,-344.
|
| 17 |
-
1,-230.
|
| 18 |
-
1,123.
|
| 19 |
-
1,-346.
|
| 20 |
-
1,-271.
|
| 21 |
-
1,-354.
|
| 22 |
-
1,-19.
|
| 23 |
-
1,280.
|
| 24 |
-
1,219.
|
| 25 |
-
1,781.
|
| 26 |
-
1,1294.
|
| 27 |
-
1,738.
|
| 28 |
-
1,796.
|
| 29 |
-
1,415.
|
| 30 |
-
1,786.
|
| 31 |
-
1,699.
|
| 32 |
-
1,539.
|
| 33 |
-
1,377.
|
| 34 |
-
1,-171.
|
| 35 |
-
1,2.
|
| 36 |
-
1,-34.
|
| 37 |
-
1,-232.
|
| 38 |
-
1,-468.
|
| 39 |
-
1,-322.
|
| 40 |
-
1,-286.
|
| 41 |
-
1,-567.
|
| 42 |
-
1,-178.
|
| 43 |
-
1,-138.
|
| 44 |
-
1,-224.
|
| 45 |
-
1,792.
|
| 46 |
-
1,1355.
|
| 47 |
-
1,986.
|
| 48 |
-
1,1059.
|
| 49 |
-
1,383.
|
| 50 |
-
1,-187.
|
| 51 |
-
1,-212.
|
| 52 |
-
1,72.
|
| 53 |
-
1,-95.
|
| 54 |
-
1,-120.
|
| 55 |
-
1,-129.
|
| 56 |
-
1,-225.
|
| 57 |
-
1,-218.
|
| 58 |
-
1,-527.
|
| 59 |
-
1,-787.
|
| 60 |
-
1,-1039.
|
| 61 |
-
1,-753.
|
| 62 |
-
1,-357.
|
| 63 |
-
1,-324.
|
| 64 |
-
1,-133.
|
| 65 |
-
1,-45.
|
| 66 |
-
1,-198.
|
| 67 |
-
1,-140.
|
| 68 |
-
1,-328.
|
| 69 |
-
1,-471.
|
| 70 |
-
1,-340.
|
| 71 |
-
1,-451.
|
| 72 |
-
1,-470.
|
| 73 |
-
1,-241.
|
| 74 |
-
1,208.
|
| 75 |
-
1,515.
|
| 76 |
-
1,645.
|
| 77 |
-
1,600.
|
| 78 |
-
1,991.
|
| 79 |
-
1,1013.
|
| 80 |
-
1,917.
|
| 81 |
-
1,1015.
|
| 82 |
-
1,696.
|
| 83 |
-
1,847.
|
| 84 |
-
1,306.
|
| 85 |
-
1,584.
|
| 86 |
-
1,320.
|
| 87 |
-
1,90.
|
| 88 |
-
1,403.
|
| 89 |
-
1,83.
|
| 90 |
-
1,-278.
|
| 91 |
-
1,-594.
|
| 92 |
-
1,-638.
|
| 93 |
-
1,-820.
|
| 94 |
-
1,-777.
|
| 95 |
-
1,-937.
|
| 96 |
-
1,-766.
|
| 97 |
-
1,-601.
|
| 98 |
-
1,-43.
|
| 99 |
-
1,783.
|
| 100 |
-
1,1048.
|
| 101 |
-
1,942.
|
| 102 |
-
1,459.
|
| 103 |
-
1,-457.
|
| 104 |
-
1,-547.
|
| 105 |
-
1,-1007.
|
|
|
|
| 1 |
other_contributions,correction,sales
|
| 2 |
+
1,-890.9083269913208,5690.218095071322
|
| 3 |
+
1,-475.04172715926325,5552.575607149263
|
| 4 |
+
1,-3.0084997762223793,5560.943568626222
|
| 5 |
+
1,-55.835992656835515,5425.282497616836
|
| 6 |
+
1,-556.3423571615149,5516.629386071515
|
| 7 |
+
1,-798.7293276068531,5445.739089056853
|
| 8 |
+
1,-831.8661367345003,5200.4253466845
|
| 9 |
+
1,-747.1985886525281,5374.302970882529
|
| 10 |
+
1,-420.26596056385733,5332.913056923857
|
| 11 |
+
1,-271.1869770058056,5319.342549515806
|
| 12 |
+
1,36.61704801202177,5391.429887731978
|
| 13 |
+
1,301.40268262302834,5389.612139710971
|
| 14 |
+
1,-149.4327829167596,5242.93423795676
|
| 15 |
+
1,-178.18371062845563,5131.547398718455
|
| 16 |
+
1,-344.31242848795137,5289.838616957952
|
| 17 |
+
1,-230.8534688342088,5451.796660734209
|
| 18 |
+
1,123.81965248641245,5218.377356663587
|
| 19 |
+
1,-346.37018641133545,5376.028569331336
|
| 20 |
+
1,-271.2351337049313,5328.863885024932
|
| 21 |
+
1,-354.554715570026,5403.077810960025
|
| 22 |
+
1,-19.42185301387599,5485.364920013876
|
| 23 |
+
1,280.9211846086464,5590.702815091353
|
| 24 |
+
1,219.92735776987683,5516.867885530122
|
| 25 |
+
1,781.0334815120623,5679.809801587939
|
| 26 |
+
1,1294.2147923458106,5794.62514015419
|
| 27 |
+
1,738.501471567386,5867.577001832614
|
| 28 |
+
1,796.9528952899409,5766.399026290058
|
| 29 |
+
1,415.426998269626,5870.755899660374
|
| 30 |
+
1,786.9046031624202,5653.93211614758
|
| 31 |
+
1,699.8259613792034,5780.4945612307965
|
| 32 |
+
1,539.745101025057,5709.584150782943
|
| 33 |
+
1,377.1008301603306,5701.305955438669
|
| 34 |
+
1,-171.62603119793766,5654.003287164937
|
| 35 |
+
1,2.582553312521668,5483.3585810364775
|
| 36 |
+
1,-34.22562033747363,5514.875846412473
|
| 37 |
+
1,-232.94753657288948,5380.036090195889
|
| 38 |
+
1,-468.2093499173443,5549.191483465345
|
| 39 |
+
1,-322.5520717213203,5460.3946979333205
|
| 40 |
+
1,-286.06881459022316,4870.059378248223
|
| 41 |
+
1,-567.8495337345976,5126.330691409597
|
| 42 |
+
1,-178.17958404447836,4755.834189569478
|
| 43 |
+
1,-138.0179383988425,4914.4588403388425
|
| 44 |
+
1,-224.74888886520512,5285.073225435204
|
| 45 |
+
1,792.8627605627134,5620.162487447287
|
| 46 |
+
1,1355.6289643675454,6164.484521602455
|
| 47 |
+
1,986.2797608661913,6162.196124983808
|
| 48 |
+
1,1059.455769237742,6192.769529952258
|
| 49 |
+
1,383.32346060172495,6147.518456028276
|
| 50 |
+
1,-187.89672830752534,5715.406060937526
|
| 51 |
+
1,-212.61946644455293,5361.829613484553
|
| 52 |
+
1,72.72524427662756,5103.391602309372
|
| 53 |
+
1,-95.74246649852375,5238.581337104524
|
| 54 |
+
1,-120.67574389038145,5559.6276727923805
|
| 55 |
+
1,-129.05511796418978,5484.72889985719
|
| 56 |
+
1,-225.81656994822333,5494.042520330224
|
| 57 |
+
1,-218.3729272379751,5302.365695685976
|
| 58 |
+
1,-527.1306773658152,5229.707354409815
|
| 59 |
+
1,-787.2566332929828,5426.519151763983
|
| 60 |
+
1,-1039.0776762177748,5539.477859049774
|
| 61 |
+
1,-753.3501980635592,5429.758980752559
|
| 62 |
+
1,-357.5844211273052,5439.306041177304
|
| 63 |
+
1,-324.8985270979465,5678.245679517946
|
| 64 |
+
1,-133.5001332835127,5695.581704533513
|
| 65 |
+
1,-45.999364494504334,5662.909688574504
|
| 66 |
+
1,-198.8982053530026,5516.533581953001
|
| 67 |
+
1,-140.84226664971084,5403.844047839711
|
| 68 |
+
1,-328.0694341550152,5409.443929865015
|
| 69 |
+
1,-471.0469150562021,5319.741307806202
|
| 70 |
+
1,-340.9581299499314,4979.624243809932
|
| 71 |
+
1,-451.5102744182759,4939.252369518276
|
| 72 |
+
1,-470.3738494522695,5272.673163112269
|
| 73 |
+
1,-241.20911973847979,5185.85509377848
|
| 74 |
+
1,208.8574132962849,5444.731311283715
|
| 75 |
+
1,515.8201019324006,5531.571609717599
|
| 76 |
+
1,645.0637292085712,5567.486440531428
|
| 77 |
+
1,600.0432433501528,5726.386967019846
|
| 78 |
+
1,991.718208446463,5546.432488283537
|
| 79 |
+
1,1013.1534153918865,5402.554699058114
|
| 80 |
+
1,917.9498416432871,5331.587882096714
|
| 81 |
+
1,1015.0218196550877,5173.547445494913
|
| 82 |
+
1,696.1648921444839,5336.375056005516
|
| 83 |
+
1,847.2335698491934,5141.959263320808
|
| 84 |
+
1,306.98931138977787,5080.857405947222
|
| 85 |
+
1,584.0043413540361,4984.766656686964
|
| 86 |
+
1,320.81565350241544,4936.522939377584
|
| 87 |
+
1,90.34779668819192,5252.465610906807
|
| 88 |
+
1,403.10225090216045,5224.36913916284
|
| 89 |
+
1,83.73958567298178,5191.899359654019
|
| 90 |
+
1,-278.22837426408205,5013.4219235420815
|
| 91 |
+
1,-594.5906903171744,5002.829538211175
|
| 92 |
+
1,-638.5744723089219,4758.680377859922
|
| 93 |
+
1,-820.1630688997875,5052.951763736787
|
| 94 |
+
1,-777.5222929965912,5052.983144825591
|
| 95 |
+
1,-937.3473140298447,5133.260108853845
|
| 96 |
+
1,-766.0759176046422,5175.758653442641
|
| 97 |
+
1,-601.9624005578062,5336.127374237805
|
| 98 |
+
1,-43.38206579649068,5912.821508406491
|
| 99 |
+
1,783.5557775286761,5872.092495641323
|
| 100 |
+
1,1048.3380060975596,5779.24874920244
|
| 101 |
+
1,942.7156660498758,5657.687045620124
|
| 102 |
+
1,459.9194845831371,5422.163026676863
|
| 103 |
+
1,-457.0944462735897,5375.19352051359
|
| 104 |
+
1,-547.8520567101305,4949.85955425913
|
| 105 |
+
1,-1007.0066006714123,5301.205921773412
|
__pycache__/utilities.cpython-310.pyc
CHANGED
|
Binary files a/__pycache__/utilities.cpython-310.pyc and b/__pycache__/utilities.cpython-310.pyc differ
|
|
|
__pycache__/utilities_with_panel.cpython-310.pyc
CHANGED
|
Binary files a/__pycache__/utilities_with_panel.cpython-310.pyc and b/__pycache__/utilities_with_panel.cpython-310.pyc differ
|
|
|
pages/8_Scenario_Planner.py
CHANGED
|
@@ -6,7 +6,7 @@ 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,
|
| 10 |
load_local_css,
|
| 11 |
set_header,
|
| 12 |
initialize_data,
|
|
@@ -22,12 +22,13 @@ from yaml import SafeLoader
|
|
| 22 |
import re
|
| 23 |
import pandas as pd
|
| 24 |
import plotly.express as px
|
| 25 |
-
|
| 26 |
|
| 27 |
st.set_page_config(layout="wide")
|
| 28 |
load_local_css("styles.css")
|
| 29 |
set_header()
|
| 30 |
|
|
|
|
| 31 |
for k, v in st.session_state.items():
|
| 32 |
if k not in ["logout", "login", "config"] and not k.startswith("FormSubmitter"):
|
| 33 |
st.session_state[k] = v
|
|
@@ -170,7 +171,7 @@ def update_all_spends_abs_slider():
|
|
| 170 |
# actual_spends = _scenario.actual_total_spends
|
| 171 |
# if validate_input(st.session_state["total_spends_change_abs_slider"]):
|
| 172 |
# print("#" * 100)
|
| 173 |
-
# print(st.session_state["total_spends_change_abs_slider"])
|
| 174 |
# print("#" * 100)
|
| 175 |
|
| 176 |
# modified_spends = extract_number_for_string(
|
|
@@ -493,192 +494,40 @@ def debug_temp(x_test, power, K, b, a, x0):
|
|
| 493 |
|
| 494 |
|
| 495 |
# @st.cache
|
| 496 |
-
def plot_response_curves():
|
| 497 |
-
cols =
|
| 498 |
-
rows = (
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
)
|
| 503 |
-
rcs = st.session_state["rcs"]
|
| 504 |
-
shapes = []
|
| 505 |
-
fig = make_subplots(rows=rows, cols=cols, subplot_titles=channels_list)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
for i in range(0, len(channels_list)):
|
| 507 |
col = channels_list[i]
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
a = rcs[col]["a"]
|
| 516 |
-
x0 = rcs[col]["x0"]
|
| 517 |
-
|
| 518 |
-
x_plot = np.linspace(0, 5 * x_actual.sum(), 50)
|
| 519 |
-
|
| 520 |
-
x, y, marginal_roi = [], [], []
|
| 521 |
-
for x_p in x_plot:
|
| 522 |
-
x.append(x_p * x_actual / x_actual.sum())
|
| 523 |
-
|
| 524 |
-
for index in range(len(x_plot)):
|
| 525 |
-
y.append(s_curve(x[index] / 10**power, K, b, a, x0))
|
| 526 |
-
|
| 527 |
-
for index in range(len(x_plot)):
|
| 528 |
-
marginal_roi.append(
|
| 529 |
-
a * y[index] * (1 - y[index] / np.maximum(K, np.finfo(float).eps))
|
| 530 |
-
)
|
| 531 |
-
|
| 532 |
-
x = (
|
| 533 |
-
np.sum(x, axis=1)
|
| 534 |
-
* st.session_state["scenario"].channels[col].conversion_rate
|
| 535 |
-
)
|
| 536 |
-
y = np.sum(y, axis=1)
|
| 537 |
-
marginal_roi = (
|
| 538 |
-
np.average(marginal_roi, axis=1)
|
| 539 |
-
/ st.session_state["scenario"].channels[col].conversion_rate
|
| 540 |
-
)
|
| 541 |
-
|
| 542 |
-
roi = y / np.maximum(x, np.finfo(float).eps)
|
| 543 |
-
|
| 544 |
-
fig.add_trace(
|
| 545 |
-
go.Scatter(
|
| 546 |
-
x=x,
|
| 547 |
-
y=y,
|
| 548 |
-
name=col,
|
| 549 |
-
customdata=np.stack((roi, marginal_roi), axis=-1),
|
| 550 |
-
hovertemplate="Spend:%{x:$.2s}<br>Sale:%{y:$.2s}<br>ROI:%{customdata[0]:.3f}<br>MROI:%{customdata[1]:.3f}",
|
| 551 |
-
line=dict(color="blue"),
|
| 552 |
-
),
|
| 553 |
-
row=1 + (i) // cols,
|
| 554 |
-
col=i % cols + 1,
|
| 555 |
-
)
|
| 556 |
-
|
| 557 |
-
x_optimal = (
|
| 558 |
-
st.session_state["scenario"].channels[col].modified_total_spends
|
| 559 |
-
* st.session_state["scenario"].channels[col].conversion_rate
|
| 560 |
-
)
|
| 561 |
-
y_optimal = st.session_state["scenario"].channels[col].modified_total_sales
|
| 562 |
-
|
| 563 |
-
# if col == "Paid_social_others":
|
| 564 |
-
# debug_temp(x_optimal * x_actual / x_actual.sum(), power, K, b, a, x0)
|
| 565 |
-
|
| 566 |
-
fig.add_trace(
|
| 567 |
-
go.Scatter(
|
| 568 |
-
x=[x_optimal],
|
| 569 |
-
y=[y_optimal],
|
| 570 |
-
name=col,
|
| 571 |
-
legendgroup=col,
|
| 572 |
-
showlegend=False,
|
| 573 |
-
marker=dict(color=["black"]),
|
| 574 |
-
),
|
| 575 |
-
row=1 + (i) // cols,
|
| 576 |
-
col=i % cols + 1,
|
| 577 |
-
)
|
| 578 |
-
|
| 579 |
-
shapes.append(
|
| 580 |
-
go.layout.Shape(
|
| 581 |
-
type="line",
|
| 582 |
-
x0=0,
|
| 583 |
-
y0=y_optimal,
|
| 584 |
-
x1=x_optimal,
|
| 585 |
-
y1=y_optimal,
|
| 586 |
-
line_width=1,
|
| 587 |
-
line_dash="dash",
|
| 588 |
-
line_color="black",
|
| 589 |
-
xref=f"x{i+1}",
|
| 590 |
-
yref=f"y{i+1}",
|
| 591 |
-
)
|
| 592 |
-
)
|
| 593 |
-
|
| 594 |
-
shapes.append(
|
| 595 |
-
go.layout.Shape(
|
| 596 |
-
type="line",
|
| 597 |
-
x0=x_optimal,
|
| 598 |
-
y0=0,
|
| 599 |
-
x1=x_optimal,
|
| 600 |
-
y1=y_optimal,
|
| 601 |
-
line_width=1,
|
| 602 |
-
line_dash="dash",
|
| 603 |
-
line_color="black",
|
| 604 |
-
xref=f"x{i+1}",
|
| 605 |
-
yref=f"y{i+1}",
|
| 606 |
-
)
|
| 607 |
-
)
|
| 608 |
-
|
| 609 |
-
start_value, end_value, left_value, right_value = find_segment_value(
|
| 610 |
-
x,
|
| 611 |
-
roi,
|
| 612 |
-
marginal_roi,
|
| 613 |
-
)
|
| 614 |
-
|
| 615 |
-
# Adding background colors
|
| 616 |
-
y_max = y.max() * 1.3 # 30% extra space above the max
|
| 617 |
-
|
| 618 |
-
# Yellow region
|
| 619 |
-
shapes.append(
|
| 620 |
-
go.layout.Shape(
|
| 621 |
-
type="rect",
|
| 622 |
-
x0=start_value,
|
| 623 |
-
y0=0,
|
| 624 |
-
x1=left_value,
|
| 625 |
-
y1=y_max,
|
| 626 |
-
line=dict(width=0),
|
| 627 |
-
fillcolor="rgba(255, 255, 0, 0.3)",
|
| 628 |
-
layer="below",
|
| 629 |
-
xref=f"x{i+1}",
|
| 630 |
-
yref=f"y{i+1}",
|
| 631 |
-
)
|
| 632 |
-
)
|
| 633 |
-
|
| 634 |
-
# Green region
|
| 635 |
-
shapes.append(
|
| 636 |
-
go.layout.Shape(
|
| 637 |
-
type="rect",
|
| 638 |
-
x0=left_value,
|
| 639 |
-
y0=0,
|
| 640 |
-
x1=right_value,
|
| 641 |
-
y1=y_max,
|
| 642 |
-
line=dict(width=0),
|
| 643 |
-
fillcolor="rgba(0, 255, 0, 0.3)",
|
| 644 |
-
layer="below",
|
| 645 |
-
xref=f"x{i+1}",
|
| 646 |
-
yref=f"y{i+1}",
|
| 647 |
-
)
|
| 648 |
-
)
|
| 649 |
-
|
| 650 |
-
# Red region
|
| 651 |
-
shapes.append(
|
| 652 |
-
go.layout.Shape(
|
| 653 |
-
type="rect",
|
| 654 |
-
x0=right_value,
|
| 655 |
-
y0=0,
|
| 656 |
-
x1=end_value,
|
| 657 |
-
y1=y_max,
|
| 658 |
-
line=dict(width=0),
|
| 659 |
-
fillcolor="rgba(255, 0, 0, 0.3)",
|
| 660 |
-
layer="below",
|
| 661 |
-
xref=f"x{i+1}",
|
| 662 |
-
yref=f"y{i+1}",
|
| 663 |
-
)
|
| 664 |
-
)
|
| 665 |
-
|
| 666 |
-
fig.update_layout(
|
| 667 |
-
# height=1000,
|
| 668 |
-
# width=1000,
|
| 669 |
-
title_text=f"Response Curves (X: Spends Vs Y: {target})",
|
| 670 |
-
showlegend=False,
|
| 671 |
-
shapes=shapes,
|
| 672 |
-
)
|
| 673 |
-
fig.update_annotations(font_size=10)
|
| 674 |
-
# fig.update_xaxes(title="Spends")
|
| 675 |
-
# fig.update_yaxes(title=target)
|
| 676 |
-
fig.update_yaxes(
|
| 677 |
-
gridcolor="rgba(136, 136, 136, 0.5)", gridwidth=0.5, griddash="dash"
|
| 678 |
-
)
|
| 679 |
-
|
| 680 |
-
return fig
|
| 681 |
-
|
| 682 |
|
| 683 |
# @st.cache
|
| 684 |
# def plot_response_curves():
|
|
@@ -849,7 +698,7 @@ def name_formating(channel_name):
|
|
| 849 |
return name_mod
|
| 850 |
|
| 851 |
|
| 852 |
-
|
| 853 |
def panel_fetch(file_selected):
|
| 854 |
raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
|
| 855 |
|
|
@@ -882,118 +731,174 @@ def reset_inputs():
|
|
| 882 |
|
| 883 |
if auth_status == True:
|
| 884 |
authenticator.logout("Logout", "main")
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
with st.expander('Optimized Spends Overview'):
|
| 888 |
-
if st.button('Refresh'):
|
| 889 |
-
st.rerun()
|
| 890 |
-
|
| 891 |
-
import plotly.graph_objects as go
|
| 892 |
-
from plotly.subplots import make_subplots
|
| 893 |
-
|
| 894 |
-
# Define light colors for bars
|
| 895 |
-
import plotly.graph_objects as go
|
| 896 |
-
from plotly.subplots import make_subplots
|
| 897 |
-
|
| 898 |
-
st.empty()
|
| 899 |
-
#st.header('Model Result Analysis')
|
| 900 |
-
spends_data=pd.read_excel('Overview_data_test.xlsx')
|
| 901 |
-
|
| 902 |
-
with open('summary_df.pkl', 'rb') as file:
|
| 903 |
-
summary_df_sorted = pickle.load(file)
|
| 904 |
-
#st.write(summary_df_sorted)
|
| 905 |
-
|
| 906 |
-
# selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2'])
|
| 907 |
-
summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
|
| 908 |
-
summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend']
|
| 909 |
-
summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend']
|
| 910 |
-
|
| 911 |
-
total_actual_spend = summary_df_sorted['Actual_spend'].sum()
|
| 912 |
-
total_optimized_spend = summary_df_sorted['Optimized_spend'].sum()
|
| 913 |
-
|
| 914 |
-
actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100
|
| 915 |
-
optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
light_blue = 'rgba(0, 31, 120, 0.7)'
|
| 920 |
-
light_orange = 'rgba(0, 181, 219, 0.7)'
|
| 921 |
-
light_green = 'rgba(240, 61, 20, 0.7)'
|
| 922 |
-
light_red = 'rgba(250, 110, 10, 0.7)'
|
| 923 |
-
light_purple = 'rgba(255, 191, 69, 0.7)'
|
| 924 |
-
|
| 925 |
-
|
| 926 |
-
# Create subplots with one row and two columns
|
| 927 |
-
fig = make_subplots(rows=1, cols=3, subplot_titles=("Actual vs. Optimized Spend", "Actual vs. Optimized Contribution", "Actual vs. Optimized ROI"))
|
| 928 |
-
|
| 929 |
-
# Add actual vs optimized spend bars
|
| 930 |
-
|
| 931 |
-
|
| 932 |
-
fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Actual_spend'], name='Actual',
|
| 933 |
-
text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '+' (' + actual_spend_percentage.round(2).astype(str) + '%)',
|
| 934 |
-
marker_color=light_blue, orientation='h'),
|
| 935 |
-
row=1,
|
| 936 |
-
col=1)
|
| 937 |
-
|
| 938 |
|
| 939 |
-
|
| 940 |
-
|
| 941 |
-
|
| 942 |
-
|
| 943 |
-
|
| 944 |
-
|
| 945 |
-
|
| 946 |
-
|
| 947 |
-
|
| 948 |
-
|
| 949 |
-
|
| 950 |
-
|
| 951 |
-
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
|
| 959 |
-
|
| 960 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 961 |
|
| 962 |
-
|
| 963 |
-
name='Optimized ROI',text=summary_df_sorted['new_roi'].apply(format_number) ,
|
| 964 |
-
marker_color=light_orange, orientation='h',showlegend=False), row=1, col=3)
|
| 965 |
-
|
| 966 |
-
fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['old_roi'],
|
| 967 |
-
name='Actual ROI', text=summary_df_sorted['old_roi'].apply(format_number) ,
|
| 968 |
-
marker_color=light_blue, orientation='h',showlegend=False), row=1, col=3)
|
| 969 |
-
|
| 970 |
-
fig.update_xaxes(title_text="ROI", row=1, col=3)
|
| 971 |
-
|
| 972 |
-
# Update layout
|
| 973 |
-
fig.update_layout(title_text="Actual vs. Optimized Metrics for Media Channels",
|
| 974 |
-
showlegend=True, yaxis=dict(title='Media Channels', autorange="reversed"))
|
| 975 |
-
|
| 976 |
-
st.plotly_chart(fig,use_container_width=True)
|
| 977 |
|
| 978 |
-
# fig = make_subplots(rows=1, cols=2, subplot_titles=("Actual Spend", "Optimized Spend"), specs=[[{'type': 'domain'}, {'type': 'domain'}]])
|
| 979 |
-
|
| 980 |
-
# # Actual spend donut chart
|
| 981 |
-
# fig.add_trace(go.Pie(labels=summary_df_sorted['Channel_name'],
|
| 982 |
-
# values=summary_df_sorted['Actual_spend'], name='Actual Spend', hole=0.3,
|
| 983 |
-
# marker_colors=[light_blue, light_orange, light_green, light_red, light_purple]), row=1, col=1)
|
| 984 |
-
|
| 985 |
-
# # Optimized spend donut chart
|
| 986 |
-
# fig.add_trace(go.Pie(labels=summary_df_sorted['Channel_name'],
|
| 987 |
-
# values=summary_df_sorted['Optimized_spend'], name='Optimized Spend', hole=0.3,
|
| 988 |
-
# arker_colors=[light_blue, light_orange, light_green, light_red, light_purple]), row=1, col=2)
|
| 989 |
-
|
| 990 |
-
# # Update layout
|
| 991 |
-
# fig.update_layout(title_text="Actual vs. Optimized Spend Distribution")
|
| 992 |
-
|
| 993 |
-
# # Show plot
|
| 994 |
-
# st.plotly_chart(fig, use_container_width=True)
|
| 995 |
-
|
| 996 |
-
#col1, col2 = st.columns([1, 1])
|
| 997 |
|
| 998 |
# Response Metrics
|
| 999 |
directory = "metrics_level_data"
|
|
@@ -1018,14 +923,16 @@ if auth_status == True:
|
|
| 1018 |
# Panel List
|
| 1019 |
panel_list = panel_fetch(file_selected)
|
| 1020 |
|
| 1021 |
-
# Panel Selected
|
| 1022 |
-
panel_selected = st.selectbox(
|
| 1023 |
-
|
| 1024 |
-
|
| 1025 |
-
|
| 1026 |
-
|
| 1027 |
-
)
|
| 1028 |
|
|
|
|
|
|
|
| 1029 |
st.session_state['selected_markets']=panel_selected
|
| 1030 |
|
| 1031 |
if "update_rcs" in st.session_state:
|
|
@@ -1058,6 +965,15 @@ if auth_status == True:
|
|
| 1058 |
st.session_state["initialized"] = True
|
| 1059 |
st.session_state["first_time"] = False
|
| 1060 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1061 |
# Channels List
|
| 1062 |
channels_list = st.session_state["channels_list"]
|
| 1063 |
|
|
@@ -1108,7 +1024,7 @@ if auth_status == True:
|
|
| 1108 |
with sub_header[1]:
|
| 1109 |
st.metric(
|
| 1110 |
label=target,
|
| 1111 |
-
value=
|
| 1112 |
float(_scenario.actual_total_sales)
|
| 1113 |
),
|
| 1114 |
)
|
|
@@ -1123,7 +1039,7 @@ if auth_status == True:
|
|
| 1123 |
with sub_header[3]:
|
| 1124 |
st.metric(
|
| 1125 |
label=target,
|
| 1126 |
-
value=
|
| 1127 |
float(_scenario.modified_total_sales)
|
| 1128 |
),
|
| 1129 |
delta=numerize(_scenario.delta_sales, 1),
|
|
@@ -1169,8 +1085,11 @@ if auth_status == True:
|
|
| 1169 |
st.button(
|
| 1170 |
"Reset",
|
| 1171 |
on_click=reset_scenario,
|
| 1172 |
-
args=(panel_selected, file_selected, updated_rcs)
|
|
|
|
| 1173 |
)
|
|
|
|
|
|
|
| 1174 |
|
| 1175 |
_columns2 = st.columns((2, 2, 2))
|
| 1176 |
if st.session_state["optimization_key"] == "Media Spends":
|
|
@@ -1206,8 +1125,9 @@ if auth_status == True:
|
|
| 1206 |
# key="total_spends_change_abs_slider",
|
| 1207 |
# on_change=update_all_spends_abs_slider,
|
| 1208 |
# )
|
| 1209 |
-
|
| 1210 |
elif st.session_state["optimization_key"] == target:
|
|
|
|
| 1211 |
with _columns2[0]:
|
| 1212 |
sales_input = st.text_input(
|
| 1213 |
"Absolute",
|
|
@@ -1227,9 +1147,13 @@ if auth_status == True:
|
|
| 1227 |
with _columns2[2]:
|
| 1228 |
min_value = round(_scenario.actual_total_sales * 0.5)
|
| 1229 |
max_value = round(_scenario.actual_total_sales * 1.5)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1230 |
st.session_state["total_sales_change_abs_slider_options"] = [
|
| 1231 |
numerize(value, 1)
|
| 1232 |
-
for value in range(min_value, max_value + 1, int(
|
| 1233 |
]
|
| 1234 |
|
| 1235 |
st.select_slider(
|
|
@@ -1237,6 +1161,7 @@ if auth_status == True:
|
|
| 1237 |
options=st.session_state["total_sales_change_abs_slider_options"],
|
| 1238 |
key="total_sales_change_abs_slider",
|
| 1239 |
on_change=update_sales_abs_slider,
|
|
|
|
| 1240 |
)
|
| 1241 |
|
| 1242 |
if (
|
|
@@ -1261,7 +1186,7 @@ if auth_status == True:
|
|
| 1261 |
"Optimize",
|
| 1262 |
on_click=optimize,
|
| 1263 |
args=(st.session_state["optimization_key"], status_placeholder),
|
| 1264 |
-
use_container_width=True,
|
| 1265 |
)
|
| 1266 |
|
| 1267 |
st.markdown("""<hr class="spends-heading-seperator">""", unsafe_allow_html=True)
|
|
@@ -1289,6 +1214,7 @@ if auth_status == True:
|
|
| 1289 |
"Old_sales":[]
|
| 1290 |
}
|
| 1291 |
for i, channel_name in enumerate(channels_list):
|
|
|
|
| 1292 |
_channel_class = st.session_state["scenario"].channels[channel_name]
|
| 1293 |
_columns = st.columns((2.5, 1.5, 1.5, 1.5, 1))
|
| 1294 |
with _columns[0]:
|
|
@@ -1360,7 +1286,7 @@ if auth_status == True:
|
|
| 1360 |
|
| 1361 |
st.metric(
|
| 1362 |
target,
|
| 1363 |
-
|
| 1364 |
delta=numerize(sales_delta, 1),
|
| 1365 |
label_visibility="collapsed",
|
| 1366 |
)
|
|
@@ -1393,7 +1319,13 @@ if auth_status == True:
|
|
| 1393 |
col = channels_list[i]
|
| 1394 |
x_actual = st.session_state["scenario"].channels[col].actual_spends
|
| 1395 |
x_modified = st.session_state["scenario"].channels[col].modified_spends
|
| 1396 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1397 |
x_total = x_modified.sum()
|
| 1398 |
power = np.ceil(np.log(x_actual.max()) / np.log(10)) - 3
|
| 1399 |
|
|
@@ -1438,9 +1370,13 @@ if auth_status == True:
|
|
| 1438 |
)
|
| 1439 |
|
| 1440 |
roi = y / np.maximum(x, np.finfo(float).eps)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1441 |
|
| 1442 |
-
#st.write(roi[-1])
|
| 1443 |
-
|
| 1444 |
roi_current, marginal_roi_current = roi[-1], marginal_roi[-1]
|
| 1445 |
x, y, roi, marginal_roi = (
|
| 1446 |
x[:-1],
|
|
@@ -1449,6 +1385,8 @@ if auth_status == True:
|
|
| 1449 |
marginal_roi[:-1],
|
| 1450 |
) # Drop data for current spends
|
| 1451 |
|
|
|
|
|
|
|
| 1452 |
start_value, end_value, left_value, right_value = find_segment_value(
|
| 1453 |
x,
|
| 1454 |
roi,
|
|
@@ -1465,6 +1403,25 @@ if auth_status == True:
|
|
| 1465 |
current_channel_spends,
|
| 1466 |
)
|
| 1467 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1468 |
with bin_placeholder:
|
| 1469 |
st.markdown(
|
| 1470 |
f"""
|
|
@@ -1475,41 +1432,33 @@ if auth_status == True:
|
|
| 1475 |
text-align: center;
|
| 1476 |
color: #006EC0;
|
| 1477 |
">
|
| 1478 |
-
<p style="margin: 0; font-size: 20px;">
|
| 1479 |
-
|
| 1480 |
</div>
|
| 1481 |
""",
|
| 1482 |
unsafe_allow_html=True,
|
| 1483 |
)
|
| 1484 |
|
| 1485 |
-
|
| 1486 |
-
|
| 1487 |
-
|
| 1488 |
-
|
| 1489 |
-
# _columns = st.columns(2)
|
| 1490 |
-
# # with _columns[0]:
|
| 1491 |
-
# st.subheader("Save Scenario")
|
| 1492 |
-
# scenario_name = st.text_input(
|
| 1493 |
-
# "Scenario name",
|
| 1494 |
-
# key="scenario_input",
|
| 1495 |
-
# placeholder="Scenario name",
|
| 1496 |
-
# label_visibility="collapsed",
|
| 1497 |
-
# )
|
| 1498 |
-
# st.button(
|
| 1499 |
-
# "Save",
|
| 1500 |
-
# on_click=lambda: save_scenario(scenario_name),
|
| 1501 |
-
# disabled=len(st.session_state["scenario_input"]) == 0,use_container_width=True
|
| 1502 |
-
# )
|
| 1503 |
|
| 1504 |
-
|
| 1505 |
-
#
|
|
|
|
|
|
|
| 1506 |
|
| 1507 |
-
|
| 1508 |
-
|
| 1509 |
-
|
| 1510 |
-
|
| 1511 |
-
|
| 1512 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1513 |
|
| 1514 |
with open("summary_df.pkl", "wb") as f:
|
| 1515 |
pickle.dump(summary_df_sorted, f)
|
|
@@ -1525,6 +1474,24 @@ if auth_status == True:
|
|
| 1525 |
# fig=summary_plot(summary_df_sorted, x='Optimized_spend', y='Channel_name', title='Planned Spend', text_column='Optimized_spend')
|
| 1526 |
# st.plotly_chart(fig,use_container_width=True)
|
| 1527 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1528 |
|
| 1529 |
elif auth_status == False:
|
| 1530 |
st.error("Username/Password is incorrect")
|
|
|
|
| 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,
|
|
|
|
| 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
|
|
|
|
| 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(
|
|
|
|
| 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():
|
|
|
|
| 698 |
return name_mod
|
| 699 |
|
| 700 |
|
| 701 |
+
@st.experimental_memo(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 |
|
|
|
|
| 731 |
|
| 732 |
if auth_status == True:
|
| 733 |
authenticator.logout("Logout", "main")
|
| 734 |
+
st.header("Scenario Planner")
|
| 735 |
+
def scenario_planner_plots():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 736 |
|
| 737 |
+
with st.expander('Optimized Spends Overview'):
|
| 738 |
+
# if st.button('Refresh'):
|
| 739 |
+
# st.experimental_rerun()
|
| 740 |
+
|
| 741 |
+
import plotly.graph_objects as go
|
| 742 |
+
from plotly.subplots import make_subplots
|
| 743 |
+
|
| 744 |
+
# Define light colors for bars
|
| 745 |
+
import plotly.graph_objects as go
|
| 746 |
+
from plotly.subplots import make_subplots
|
| 747 |
+
|
| 748 |
+
st.empty()
|
| 749 |
+
#st.header('Model Result Analysis')
|
| 750 |
+
spends_data=pd.read_excel('Overview_data_test.xlsx')
|
| 751 |
+
|
| 752 |
+
with open('summary_df.pkl', 'rb') as file:
|
| 753 |
+
summary_df_sorted = pickle.load(file)
|
| 754 |
+
#st.write(summary_df_sorted)
|
| 755 |
+
|
| 756 |
+
# selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2'])
|
| 757 |
+
summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
|
| 758 |
+
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())
|
| 759 |
+
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())
|
| 760 |
+
|
| 761 |
+
summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend']
|
| 762 |
+
summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend']
|
| 763 |
+
|
| 764 |
+
total_actual_spend = summary_df_sorted['Actual_spend'].sum()
|
| 765 |
+
total_optimized_spend = summary_df_sorted['Optimized_spend'].sum()
|
| 766 |
+
|
| 767 |
+
actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100
|
| 768 |
+
optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100
|
| 769 |
+
|
| 770 |
+
|
| 771 |
+
|
| 772 |
+
light_blue = 'rgba(0, 31, 120, 0.7)'
|
| 773 |
+
light_orange = 'rgba(0, 181, 219, 0.7)'
|
| 774 |
+
light_green = 'rgba(240, 61, 20, 0.7)'
|
| 775 |
+
light_red = 'rgba(250, 110, 10, 0.7)'
|
| 776 |
+
light_purple = 'rgba(255, 191, 69, 0.7)'
|
| 777 |
+
|
| 778 |
+
|
| 779 |
+
# # Create subplots with one row and two columns
|
| 780 |
+
# fig = make_subplots(rows=3, cols=1, subplot_titles=("Actual vs. Optimized Spend", "Actual vs. Optimized Contribution", "Actual vs. Optimized ROI"))
|
| 781 |
+
|
| 782 |
+
# # Add actual vs optimized spend bars
|
| 783 |
+
|
| 784 |
+
|
| 785 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Actual_spend'], name='Actual',
|
| 786 |
+
# text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '+' (' + actual_spend_percentage.round(2).astype(str) + '%)',
|
| 787 |
+
# marker_color=light_blue, orientation='h'),
|
| 788 |
+
# row=1,
|
| 789 |
+
# col=1)
|
| 790 |
+
|
| 791 |
+
|
| 792 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Optimized_spend'], name='Optimized',
|
| 793 |
+
# text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' (' + optimized_spend_percentage.round(2).astype(str) + '%)',
|
| 794 |
+
# marker_color=light_orange,
|
| 795 |
+
# orientation='h'),
|
| 796 |
+
# row=1,
|
| 797 |
+
# col=1)
|
| 798 |
+
|
| 799 |
+
# fig.update_xaxes(title_text="Amount", row=1, col=1)
|
| 800 |
+
|
| 801 |
+
# # Add actual vs optimized Contribution
|
| 802 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['New_sales'],
|
| 803 |
+
# name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),
|
| 804 |
+
# marker_color=light_orange, orientation='h',showlegend=False), row=2, col=1)
|
| 805 |
+
|
| 806 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Old_sales'],
|
| 807 |
+
# name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),
|
| 808 |
+
# marker_color=light_blue, orientation='h',showlegend=False), row=2, col=1)
|
| 809 |
+
|
| 810 |
+
|
| 811 |
+
# fig.update_xaxes(title_text="Contribution", row=2, col=1)
|
| 812 |
+
|
| 813 |
+
# # Add actual vs optimized ROI bars
|
| 814 |
+
|
| 815 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['new_roi'],
|
| 816 |
+
# name='Optimized ROI',text=summary_df_sorted['new_roi'].apply(format_number) ,
|
| 817 |
+
# marker_color=light_orange, orientation='h',showlegend=False), row=3, col=1)
|
| 818 |
+
|
| 819 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['old_roi'],
|
| 820 |
+
# name='Actual ROI', text=summary_df_sorted['old_roi'].apply(format_number) ,
|
| 821 |
+
# marker_color=light_blue, orientation='h',showlegend=False), row=3, col=1)
|
| 822 |
+
|
| 823 |
+
# fig.update_xaxes(title_text="ROI", row=3, col=1)
|
| 824 |
+
|
| 825 |
+
# # Update layout
|
| 826 |
+
# fig.update_layout(title_text="Actual vs. Optimized Metrics for Media Channels",
|
| 827 |
+
# showlegend=True, yaxis=dict(title='Media Channels', autorange="reversed"))
|
| 828 |
+
|
| 829 |
+
# st.plotly_chart(fig,use_container_width=True)
|
| 830 |
+
|
| 831 |
+
# Create subplots with one row and two columns
|
| 832 |
+
fig = go.Figure()
|
| 833 |
+
# Add actual vs optimized spend bars
|
| 834 |
+
|
| 835 |
+
|
| 836 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Actual_spend'], name='Actual',
|
| 837 |
+
text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '
|
| 838 |
+
# +
|
| 839 |
+
# ' '+
|
| 840 |
+
# '</br> (' + actual_spend_percentage.astype(int).astype(str) + '%)'
|
| 841 |
+
,textposition='outside',#textfont=dict(size=30),
|
| 842 |
+
marker_color=light_blue))
|
| 843 |
+
|
| 844 |
+
|
| 845 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Optimized_spend'], name='Optimized',
|
| 846 |
+
text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' '
|
| 847 |
+
# +
|
| 848 |
+
# '</br> (' + optimized_spend_percentage.astype(int).astype(str) + '%)'
|
| 849 |
+
,textposition='outside',#textfont=dict(size=30),
|
| 850 |
+
marker_color=light_orange))
|
| 851 |
+
|
| 852 |
+
fig.update_xaxes(title_text="Channels")
|
| 853 |
+
fig.update_yaxes(title_text="Spends ($)")
|
| 854 |
+
fig.update_layout(
|
| 855 |
+
title = "Actual vs. Optimized Spends",
|
| 856 |
+
margin=dict(t=40, b=40, l=40, r=40)
|
| 857 |
+
)
|
| 858 |
+
|
| 859 |
+
st.plotly_chart(fig,use_container_width=True)
|
| 860 |
+
|
| 861 |
+
# Add actual vs optimized Contribution
|
| 862 |
+
fig = go.Figure()
|
| 863 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Old_sales'],
|
| 864 |
+
name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),textposition='outside',
|
| 865 |
+
marker_color=light_blue,showlegend=True))
|
| 866 |
+
|
| 867 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['New_sales'],
|
| 868 |
+
name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),textposition='outside',
|
| 869 |
+
marker_color=light_orange, showlegend=True))
|
| 870 |
+
|
| 871 |
+
|
| 872 |
+
|
| 873 |
+
fig.update_yaxes(title_text="Contribution")
|
| 874 |
+
fig.update_xaxes(title_text="Channels")
|
| 875 |
+
fig.update_layout(
|
| 876 |
+
title = "Actual vs. Optimized Contributions",
|
| 877 |
+
margin=dict(t=40, b=40, l=40, r=40)
|
| 878 |
+
# yaxis=dict(range=[0, 0.002]),
|
| 879 |
+
)
|
| 880 |
+
st.plotly_chart(fig,use_container_width=True)
|
| 881 |
+
|
| 882 |
+
# Add actual vs optimized Efficiency bars
|
| 883 |
+
fig = go.Figure()
|
| 884 |
+
summary_df_sorted_p = summary_df_sorted[summary_df_sorted['Channel_name']!="Panel"]
|
| 885 |
+
fig.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'], y=summary_df_sorted_p['old_efficiency'],
|
| 886 |
+
name='Actual Efficiency', text=summary_df_sorted_p['old_efficiency'].apply(format_number) ,textposition='outside',
|
| 887 |
+
marker_color=light_blue,showlegend=True))
|
| 888 |
+
fig.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'], y=summary_df_sorted_p['new_efficiency'],
|
| 889 |
+
name='Optimized Efficiency',text=summary_df_sorted_p['new_efficiency'].apply(format_number),textposition='outside' ,
|
| 890 |
+
marker_color=light_orange,showlegend=True))
|
| 891 |
+
|
| 892 |
+
fig.update_xaxes(title_text="Channels")
|
| 893 |
+
fig.update_yaxes(title_text="ROI")
|
| 894 |
+
fig.update_layout(
|
| 895 |
+
title = "Actual vs. Optimized ROI",
|
| 896 |
+
margin=dict(t=40, b=40, l=40, r=40),
|
| 897 |
+
# yaxis=dict(range=[0, 0.002]),
|
| 898 |
+
)
|
| 899 |
|
| 900 |
+
st.plotly_chart(fig,use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 901 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 902 |
|
| 903 |
# Response Metrics
|
| 904 |
directory = "metrics_level_data"
|
|
|
|
| 923 |
# Panel List
|
| 924 |
panel_list = panel_fetch(file_selected)
|
| 925 |
|
| 926 |
+
# # Panel Selected
|
| 927 |
+
# panel_selected = st.selectbox(
|
| 928 |
+
# "Markets",
|
| 929 |
+
# ["Total Market"] + panel_list,
|
| 930 |
+
# index=0,
|
| 931 |
+
# on_change=reset_inputs,
|
| 932 |
+
# )
|
| 933 |
|
| 934 |
+
# st.write(panel_selected)
|
| 935 |
+
panel_selected = "Total Market"
|
| 936 |
st.session_state['selected_markets']=panel_selected
|
| 937 |
|
| 938 |
if "update_rcs" in st.session_state:
|
|
|
|
| 965 |
st.session_state["initialized"] = True
|
| 966 |
st.session_state["first_time"] = False
|
| 967 |
|
| 968 |
+
# initialize_data(
|
| 969 |
+
# panel=panel_selected,
|
| 970 |
+
# target_file=file_selected,
|
| 971 |
+
# updated_rcs=updated_rcs,
|
| 972 |
+
# metrics=metrics_selected,
|
| 973 |
+
# )
|
| 974 |
+
# st.session_state["initialized"] = True
|
| 975 |
+
# st.session_state["first_time"] = False
|
| 976 |
+
|
| 977 |
# Channels List
|
| 978 |
channels_list = st.session_state["channels_list"]
|
| 979 |
|
|
|
|
| 1024 |
with sub_header[1]:
|
| 1025 |
st.metric(
|
| 1026 |
label=target,
|
| 1027 |
+
value=format_numbers_f(
|
| 1028 |
float(_scenario.actual_total_sales)
|
| 1029 |
),
|
| 1030 |
)
|
|
|
|
| 1039 |
with sub_header[3]:
|
| 1040 |
st.metric(
|
| 1041 |
label=target,
|
| 1042 |
+
value=format_numbers_f(
|
| 1043 |
float(_scenario.modified_total_sales)
|
| 1044 |
),
|
| 1045 |
delta=numerize(_scenario.delta_sales, 1),
|
|
|
|
| 1085 |
st.button(
|
| 1086 |
"Reset",
|
| 1087 |
on_click=reset_scenario,
|
| 1088 |
+
args=(panel_selected, file_selected, updated_rcs),
|
| 1089 |
+
# use_container_width=True,
|
| 1090 |
)
|
| 1091 |
+
# st.write(target)
|
| 1092 |
+
|
| 1093 |
|
| 1094 |
_columns2 = st.columns((2, 2, 2))
|
| 1095 |
if st.session_state["optimization_key"] == "Media Spends":
|
|
|
|
| 1125 |
# key="total_spends_change_abs_slider",
|
| 1126 |
# on_change=update_all_spends_abs_slider,
|
| 1127 |
# )
|
| 1128 |
+
|
| 1129 |
elif st.session_state["optimization_key"] == target:
|
| 1130 |
+
# st.write(target)
|
| 1131 |
with _columns2[0]:
|
| 1132 |
sales_input = st.text_input(
|
| 1133 |
"Absolute",
|
|
|
|
| 1147 |
with _columns2[2]:
|
| 1148 |
min_value = round(_scenario.actual_total_sales * 0.5)
|
| 1149 |
max_value = round(_scenario.actual_total_sales * 1.5)
|
| 1150 |
+
st.write(min_value)
|
| 1151 |
+
st.write(max_value)
|
| 1152 |
+
# for value in range(min_value, max_value + 1, int(100)):
|
| 1153 |
+
# st.write(numerize(value, 1))
|
| 1154 |
st.session_state["total_sales_change_abs_slider_options"] = [
|
| 1155 |
numerize(value, 1)
|
| 1156 |
+
for value in range(min_value, max_value + 1, int(100))
|
| 1157 |
]
|
| 1158 |
|
| 1159 |
st.select_slider(
|
|
|
|
| 1161 |
options=st.session_state["total_sales_change_abs_slider_options"],
|
| 1162 |
key="total_sales_change_abs_slider",
|
| 1163 |
on_change=update_sales_abs_slider,
|
| 1164 |
+
# value=numerize(min_value, 1)
|
| 1165 |
)
|
| 1166 |
|
| 1167 |
if (
|
|
|
|
| 1186 |
"Optimize",
|
| 1187 |
on_click=optimize,
|
| 1188 |
args=(st.session_state["optimization_key"], status_placeholder),
|
| 1189 |
+
# use_container_width=True,
|
| 1190 |
)
|
| 1191 |
|
| 1192 |
st.markdown("""<hr class="spends-heading-seperator">""", unsafe_allow_html=True)
|
|
|
|
| 1214 |
"Old_sales":[]
|
| 1215 |
}
|
| 1216 |
for i, channel_name in enumerate(channels_list):
|
| 1217 |
+
# st.write(channel_name)
|
| 1218 |
_channel_class = st.session_state["scenario"].channels[channel_name]
|
| 1219 |
_columns = st.columns((2.5, 1.5, 1.5, 1.5, 1))
|
| 1220 |
with _columns[0]:
|
|
|
|
| 1286 |
|
| 1287 |
st.metric(
|
| 1288 |
target,
|
| 1289 |
+
format_numbers_f(current_channel_sales),
|
| 1290 |
delta=numerize(sales_delta, 1),
|
| 1291 |
label_visibility="collapsed",
|
| 1292 |
)
|
|
|
|
| 1319 |
col = channels_list[i]
|
| 1320 |
x_actual = st.session_state["scenario"].channels[col].actual_spends
|
| 1321 |
x_modified = st.session_state["scenario"].channels[col].modified_spends
|
| 1322 |
+
# x_modified_total = 0
|
| 1323 |
+
# for c in channels_list:
|
| 1324 |
+
# # st.write(c)
|
| 1325 |
+
# # st.write(st.session_state["scenario"].channels[c].modified_spends)
|
| 1326 |
+
# x_modified_total = x_modified_total + st.session_state["scenario"].channels[c].modified_spends.sum()
|
| 1327 |
+
# st.write(x_modified_total)
|
| 1328 |
+
|
| 1329 |
x_total = x_modified.sum()
|
| 1330 |
power = np.ceil(np.log(x_actual.max()) / np.log(10)) - 3
|
| 1331 |
|
|
|
|
| 1370 |
)
|
| 1371 |
|
| 1372 |
roi = y / np.maximum(x, np.finfo(float).eps)
|
| 1373 |
+
# roi = (y/np.sum(y))/(x/np.sum(x))
|
| 1374 |
+
# st.write(x)
|
| 1375 |
+
# st.write(y)
|
| 1376 |
+
# st.write(roi)
|
| 1377 |
|
| 1378 |
+
# st.write(roi[-1])
|
| 1379 |
+
|
| 1380 |
roi_current, marginal_roi_current = roi[-1], marginal_roi[-1]
|
| 1381 |
x, y, roi, marginal_roi = (
|
| 1382 |
x[:-1],
|
|
|
|
| 1385 |
marginal_roi[:-1],
|
| 1386 |
) # Drop data for current spends
|
| 1387 |
|
| 1388 |
+
# roi_current =
|
| 1389 |
+
|
| 1390 |
start_value, end_value, left_value, right_value = find_segment_value(
|
| 1391 |
x,
|
| 1392 |
roi,
|
|
|
|
| 1403 |
current_channel_spends,
|
| 1404 |
)
|
| 1405 |
|
| 1406 |
+
summary_df = pd.DataFrame(st.session_state["acutual_predicted"])
|
| 1407 |
+
# st.dataframe(summary_df)
|
| 1408 |
+
summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True)
|
| 1409 |
+
# st.dataframe(summary_df)
|
| 1410 |
+
|
| 1411 |
+
summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False)
|
| 1412 |
+
summary_df_sorted["Delta_percent"] = np.round(
|
| 1413 |
+
((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1)
|
| 1414 |
+
* 100,
|
| 1415 |
+
2,
|
| 1416 |
+
)
|
| 1417 |
+
|
| 1418 |
+
summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
|
| 1419 |
+
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())
|
| 1420 |
+
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())
|
| 1421 |
+
|
| 1422 |
+
a = (summary_df_sorted[summary_df_sorted['Channel_name']== col]).reset_index()['new_efficiency'][0]
|
| 1423 |
+
# st.write(a)
|
| 1424 |
+
|
| 1425 |
with bin_placeholder:
|
| 1426 |
st.markdown(
|
| 1427 |
f"""
|
|
|
|
| 1432 |
text-align: center;
|
| 1433 |
color: #006EC0;
|
| 1434 |
">
|
| 1435 |
+
<p style="margin: 0; font-size: 20px;">Efficiency: {round(a,2)}</p>
|
| 1436 |
+
<!--<p style="margin: 0; font-size: 20px;">Marginal ROI: {round(marginal_roi_current,1)}</p>-->
|
| 1437 |
</div>
|
| 1438 |
""",
|
| 1439 |
unsafe_allow_html=True,
|
| 1440 |
)
|
| 1441 |
|
| 1442 |
+
with st.expander("See Response Curves", expanded=True):
|
| 1443 |
+
fig = plot_response_curves(summary_df_sorted)
|
| 1444 |
+
# st.plotly_chart(rc.response_curves(col))
|
| 1445 |
+
# st.plotly_chart(fig, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1446 |
|
| 1447 |
+
summary_df = pd.DataFrame(st.session_state["acutual_predicted"])
|
| 1448 |
+
# st.dataframe(summary_df)
|
| 1449 |
+
summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True)
|
| 1450 |
+
# st.dataframe(summary_df)
|
| 1451 |
|
| 1452 |
+
summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False)
|
| 1453 |
+
summary_df_sorted["Delta_percent"] = np.round(
|
| 1454 |
+
((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1)
|
| 1455 |
+
* 100,
|
| 1456 |
+
2,
|
| 1457 |
+
)
|
| 1458 |
+
|
| 1459 |
+
|
| 1460 |
+
|
| 1461 |
+
|
| 1462 |
|
| 1463 |
with open("summary_df.pkl", "wb") as f:
|
| 1464 |
pickle.dump(summary_df_sorted, f)
|
|
|
|
| 1474 |
# fig=summary_plot(summary_df_sorted, x='Optimized_spend', y='Channel_name', title='Planned Spend', text_column='Optimized_spend')
|
| 1475 |
# st.plotly_chart(fig,use_container_width=True)
|
| 1476 |
|
| 1477 |
+
scenario_planner_plots()
|
| 1478 |
+
|
| 1479 |
+
_columns = st.columns(2)
|
| 1480 |
+
# with _columns[0]:
|
| 1481 |
+
st.subheader("Save Scenario")
|
| 1482 |
+
scenario_name = st.text_input(
|
| 1483 |
+
"Scenario name",
|
| 1484 |
+
key="scenario_input",
|
| 1485 |
+
placeholder="Scenario name",
|
| 1486 |
+
label_visibility="collapsed",
|
| 1487 |
+
)
|
| 1488 |
+
st.button(
|
| 1489 |
+
"Save",
|
| 1490 |
+
on_click=lambda: save_scenario(scenario_name),
|
| 1491 |
+
disabled=len(st.session_state["scenario_input"]) == 0,#use_container_width=True
|
| 1492 |
+
)
|
| 1493 |
+
|
| 1494 |
+
|
| 1495 |
|
| 1496 |
elif auth_status == False:
|
| 1497 |
st.error("Username/Password is incorrect")
|
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:41027251e75b11465e5cec329b14a8e35d4791aa6fdbbc948a0f32b4c1acc286
|
| 3 |
+
size 1886
|
utilities.py
CHANGED
|
@@ -931,6 +931,11 @@ def format_numbers(value, n_decimals=1, include_indicator=True):
|
|
| 931 |
else:
|
| 932 |
return f"{numerize(value,n_decimals)}"
|
| 933 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 934 |
|
| 935 |
def decimal_formater(num_string, n_decimals=1):
|
| 936 |
parts = num_string.split(".")
|
|
|
|
| 931 |
else:
|
| 932 |
return f"{numerize(value,n_decimals)}"
|
| 933 |
|
| 934 |
+
def format_numbers_f(value, n_decimals=1, include_indicator=False):
|
| 935 |
+
if include_indicator:
|
| 936 |
+
return f"{CURRENCY_INDICATOR} {numerize(value,n_decimals)}"
|
| 937 |
+
else:
|
| 938 |
+
return f"{numerize(value,n_decimals)}"
|
| 939 |
|
| 940 |
def decimal_formater(num_string, n_decimals=1):
|
| 941 |
parts = num_string.split(".")
|
utilities_with_panel.py
CHANGED
|
@@ -82,15 +82,15 @@ def nav_page(page_name, timeout_secs=3):
|
|
| 82 |
# <img src="https://assets-global.website-files.com/64c8fffb0e95cbc525815b79/64df84637f83a891c1473c51_Vector%20(Stroke).svg ">
|
| 83 |
# </div>""", unsafe_allow_html=True)
|
| 84 |
|
| 85 |
-
path = os.path.dirname(__file__)
|
| 86 |
|
| 87 |
-
file_ = open(f"{path}/mastercard_logo.png", "rb")
|
| 88 |
|
| 89 |
-
contents = file_.read()
|
| 90 |
|
| 91 |
-
data_url = base64.b64encode(contents).decode("utf-8")
|
| 92 |
|
| 93 |
-
file_.close()
|
| 94 |
|
| 95 |
|
| 96 |
|
|
@@ -136,7 +136,7 @@ def load_local_css(file_name):
|
|
| 136 |
# </div>""", unsafe_allow_html=True)
|
| 137 |
path1 = os.path.dirname(__file__)
|
| 138 |
|
| 139 |
-
file_1 = open(f"
|
| 140 |
|
| 141 |
contents1 = file_1.read()
|
| 142 |
|
|
@@ -723,9 +723,9 @@ def create_channel_summary(scenario):
|
|
| 723 |
|
| 724 |
actual_summary_df = pd.DataFrame([summary_columns, actual_spends_rows, actual_sales_rows, actual_roi_rows]).T
|
| 725 |
|
| 726 |
-
actual_summary_df.columns = ['Channel', 'Spends', '
|
| 727 |
|
| 728 |
-
actual_summary_df['
|
| 729 |
|
| 730 |
return actual_summary_df
|
| 731 |
|
|
@@ -771,7 +771,7 @@ def create_contribution_pie(scenario):
|
|
| 771 |
light_purple = 'rgba(255, 191, 69, 0.7)'
|
| 772 |
|
| 773 |
colors_map = {col:color for col,color in zip(st.session_state['channels_list'],plotly.colors.n_colors(plotly.colors.hex_to_rgb('#BE6468'), plotly.colors.hex_to_rgb('#E7B8B7'),23))}
|
| 774 |
-
total_contribution_fig = make_subplots(rows=1, cols=2,subplot_titles=['Media Spends','
|
| 775 |
total_contribution_fig.add_trace(
|
| 776 |
go.Pie(labels=[channel_name_formating(channel_name) for channel_name in st.session_state['channels_list']] + ['Non Media'],
|
| 777 |
values= [round(scenario.channels[channel_name].actual_total_spends * scenario.channels[channel_name].conversion_rate,1) for channel_name in st.session_state['channels_list']] + [0],
|
|
@@ -893,7 +893,7 @@ def create_contribution_pie(scenario):
|
|
| 893 |
# return total_contribution_fig
|
| 894 |
|
| 895 |
def create_contribuion_stacked_plot(scenario):
|
| 896 |
-
weekly_contribution_fig = make_subplots(rows=1, cols=2, subplot_titles=['Spends', '
|
| 897 |
raw_df = st.session_state['raw_df']
|
| 898 |
df = raw_df.sort_values(by='Date')
|
| 899 |
x = df.Date
|
|
@@ -916,7 +916,7 @@ def create_contribuion_stacked_plot(scenario):
|
|
| 916 |
x=x,
|
| 917 |
y=scenario.channels[channel_name].actual_sales,
|
| 918 |
name=channel_name_formating(channel_name),
|
| 919 |
-
hovertemplate="Date:%{x}<br>
|
| 920 |
legendgroup=channel_name,
|
| 921 |
showlegend=False,
|
| 922 |
marker_color=color,
|
|
@@ -931,7 +931,7 @@ def create_contribuion_stacked_plot(scenario):
|
|
| 931 |
x=x,
|
| 932 |
y=scenario.constant + scenario.correction,
|
| 933 |
name='Non Media',
|
| 934 |
-
hovertemplate="Date:%{x}<br>
|
| 935 |
marker_color=color_palette[-1],
|
| 936 |
), row=1, col=2)
|
| 937 |
|
|
@@ -950,8 +950,8 @@ def create_channel_spends_sales_plot(channel):
|
|
| 950 |
x=x,
|
| 951 |
y=_sales,
|
| 952 |
marker_color=color_palette[1], # You can choose a color from the palette
|
| 953 |
-
name='
|
| 954 |
-
hovertemplate="Date:%{x}<br>
|
| 955 |
), secondary_y=False)
|
| 956 |
|
| 957 |
channel_sales_spends_fig.add_trace(go.Scatter(
|
|
@@ -962,7 +962,7 @@ def create_channel_spends_sales_plot(channel):
|
|
| 962 |
hovertemplate="Date:%{x}<br>Spend:%{y:$.2s}",
|
| 963 |
), secondary_y=True)
|
| 964 |
|
| 965 |
-
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='
|
| 966 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
| 967 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
| 968 |
else:
|
|
@@ -976,11 +976,11 @@ def create_channel_spends_sales_plot(channel):
|
|
| 976 |
x=x,
|
| 977 |
y=_sales,
|
| 978 |
marker_color=color_palette[0], # You can choose a color from the palette
|
| 979 |
-
name='
|
| 980 |
-
hovertemplate="Date:%{x}<br>
|
| 981 |
), secondary_y=False)
|
| 982 |
|
| 983 |
-
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='
|
| 984 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
| 985 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
| 986 |
|
|
|
|
| 82 |
# <img src="https://assets-global.website-files.com/64c8fffb0e95cbc525815b79/64df84637f83a891c1473c51_Vector%20(Stroke).svg ">
|
| 83 |
# </div>""", unsafe_allow_html=True)
|
| 84 |
|
| 85 |
+
# path = os.path.dirname(__file__)
|
| 86 |
|
| 87 |
+
# file_ = open(f"{path}/mastercard_logo.png", "rb")
|
| 88 |
|
| 89 |
+
# contents = file_.read()
|
| 90 |
|
| 91 |
+
# data_url = base64.b64encode(contents).decode("utf-8")
|
| 92 |
|
| 93 |
+
# file_.close()
|
| 94 |
|
| 95 |
|
| 96 |
|
|
|
|
| 136 |
# </div>""", unsafe_allow_html=True)
|
| 137 |
path1 = os.path.dirname(__file__)
|
| 138 |
|
| 139 |
+
file_1 = open(f"ALDI_2017.png", "rb")
|
| 140 |
|
| 141 |
contents1 = file_1.read()
|
| 142 |
|
|
|
|
| 723 |
|
| 724 |
actual_summary_df = pd.DataFrame([summary_columns, actual_spends_rows, actual_sales_rows, actual_roi_rows]).T
|
| 725 |
|
| 726 |
+
actual_summary_df.columns = ['Channel', 'Spends', 'Prospects', 'ROI']
|
| 727 |
|
| 728 |
+
actual_summary_df['Prospects'] = actual_summary_df['Prospects'].map(lambda x: str(x)[1:])
|
| 729 |
|
| 730 |
return actual_summary_df
|
| 731 |
|
|
|
|
| 771 |
light_purple = 'rgba(255, 191, 69, 0.7)'
|
| 772 |
|
| 773 |
colors_map = {col:color for col,color in zip(st.session_state['channels_list'],plotly.colors.n_colors(plotly.colors.hex_to_rgb('#BE6468'), plotly.colors.hex_to_rgb('#E7B8B7'),23))}
|
| 774 |
+
total_contribution_fig = make_subplots(rows=1, cols=2,subplot_titles=['Media Spends','Prospects Contribution'],specs=[[{"type": "pie"}, {"type": "pie"}]])
|
| 775 |
total_contribution_fig.add_trace(
|
| 776 |
go.Pie(labels=[channel_name_formating(channel_name) for channel_name in st.session_state['channels_list']] + ['Non Media'],
|
| 777 |
values= [round(scenario.channels[channel_name].actual_total_spends * scenario.channels[channel_name].conversion_rate,1) for channel_name in st.session_state['channels_list']] + [0],
|
|
|
|
| 893 |
# return total_contribution_fig
|
| 894 |
|
| 895 |
def create_contribuion_stacked_plot(scenario):
|
| 896 |
+
weekly_contribution_fig = make_subplots(rows=1, cols=2, subplot_titles=['Spends', 'Prospects'], specs=[[{"type": "bar"}, {"type": "bar"}]])
|
| 897 |
raw_df = st.session_state['raw_df']
|
| 898 |
df = raw_df.sort_values(by='Date')
|
| 899 |
x = df.Date
|
|
|
|
| 916 |
x=x,
|
| 917 |
y=scenario.channels[channel_name].actual_sales,
|
| 918 |
name=channel_name_formating(channel_name),
|
| 919 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
| 920 |
legendgroup=channel_name,
|
| 921 |
showlegend=False,
|
| 922 |
marker_color=color,
|
|
|
|
| 931 |
x=x,
|
| 932 |
y=scenario.constant + scenario.correction,
|
| 933 |
name='Non Media',
|
| 934 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
| 935 |
marker_color=color_palette[-1],
|
| 936 |
), row=1, col=2)
|
| 937 |
|
|
|
|
| 950 |
x=x,
|
| 951 |
y=_sales,
|
| 952 |
marker_color=color_palette[1], # You can choose a color from the palette
|
| 953 |
+
name='Prospects',
|
| 954 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
| 955 |
), secondary_y=False)
|
| 956 |
|
| 957 |
channel_sales_spends_fig.add_trace(go.Scatter(
|
|
|
|
| 962 |
hovertemplate="Date:%{x}<br>Spend:%{y:$.2s}",
|
| 963 |
), secondary_y=True)
|
| 964 |
|
| 965 |
+
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='Prospects', yaxis2_title='Spends ($)', title='Channel spends and Prospects week-wise')
|
| 966 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
| 967 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
| 968 |
else:
|
|
|
|
| 976 |
x=x,
|
| 977 |
y=_sales,
|
| 978 |
marker_color=color_palette[0], # You can choose a color from the palette
|
| 979 |
+
name='Prospects',
|
| 980 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
| 981 |
), secondary_y=False)
|
| 982 |
|
| 983 |
+
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='Prospects', yaxis2_title='Spends ($)', title='Channel spends and Prospects week-wise')
|
| 984 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
| 985 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
| 986 |
|