diff --git "a/pages/2_Scenario_Planner.py" "b/pages/2_Scenario_Planner.py" new file mode 100644--- /dev/null +++ "b/pages/2_Scenario_Planner.py" @@ -0,0 +1,2355 @@ +import streamlit as st +from numerize.numerize import numerize +import numpy as np +from functools import partial +from collections import OrderedDict +from plotly.subplots import make_subplots +import plotly.graph_objects as go +from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta +import time +import Streamlit_functions as sf +from utilities import ( + format_numbers,format_numbers_f, + load_local_css, + set_header, + initialize_data, + load_authenticator, + send_email, + channel_name_formating, +) +from io import BytesIO +# import xlsxwriter +import warnings +# Suppress specific warnings if necessary +warnings.filterwarnings("ignore") +warnings.filterwarnings("ignore", category=UserWarning, message="The widget with key") +# for i in : + # warnings.filterwarnings("ignore",) +from classes import class_from_dict, class_to_dict +import pickle +import streamlit_authenticator as stauth +import yaml +from yaml import SafeLoader +import re +import pandas as pd +import plotly.express as px +import response_curves_model_quality as rc + +st.set_page_config(layout="wide") +load_local_css("styles.css") +set_header() + +from pptx import Presentation +from pptx.util import Inches +from io import BytesIO +import plotly.io as pio + + +for k, v in st.session_state.items(): + if k not in ["logout", "login", "config"] and not k.startswith("FormSubmitter"): + st.session_state[k] = v +# ======================================================== # +# ======================= Functions ====================== # +# ======================================================== # + +def save_report_forecast(forecasted_table_df,forecasted_table_df2): + # Convert the DataFrame to an Excel file in memory + excel_file = BytesIO() + with pd.ExcelWriter(excel_file, engine='openpyxl') as writer: + forecasted_table_df.to_excel(writer, index=True, sheet_name='Forecasted Spends') + forecasted_table_df2.to_excel(writer, sheet_name='Monthly Breakdown',index = True) + # Seek to the beginning of the BytesIO buffer + excel_file.seek(0) + return excel_file + +def save_ppt_file(summary_df_sorted,fig1,fig2,fig3): + summary_df_sorted.index = summary_df_sorted["Channel_name"] + # Initialize PowerPoint presentation + prs = Presentation() + # Helper function to add Plotly figure to slide + def add_plotly_chart_to_slide(slide, fig, left, top, width, height): + img_stream = BytesIO() + pio.write_image(fig, img_stream, format='png') + slide.shapes.add_picture(img_stream, left, top, width, height) + + for i in range(0,len(channels_list)): + # # print(channels_list[i]) + slide_1 = prs.slides.add_slide(prs.slide_layouts[6]) + fig = rc.response_curves(channels_list[i], summary_df_sorted["Optimized_spend"][channels_list[i]], summary_df_sorted["New_sales"][channels_list[i]]) + add_plotly_chart_to_slide(slide_1, fig, Inches(0.1), Inches(0.1), width=Inches(9), height=Inches(7)) + + # Update layout + fig1.update_layout( + legend=dict( + orientation="h", # Horizontal orientation + yanchor="top", # Anchor the legend at the top + y=-0.4, # Position the legend below the plot area + xanchor="center", # Center the legend horizontally + x=0.5 # Center the legend on the x-axis + ) + ) + # Update layout + fig2.update_layout( + legend=dict( + orientation="h", # Horizontal orientation + yanchor="top", # Anchor the legend at the top + y=-0.4, # Position the legend below the plot area + xanchor="center", # Center the legend horizontally + x=0.5 # Center the legend on the x-axis + ) + ) + # Update layout + fig3.update_layout( + legend=dict( + orientation="h", # Horizontal orientation + yanchor="top", # Anchor the legend at the top + y=-0.4, # Position the legend below the plot area + xanchor="center", # Center the legend horizontally + x=0.5 # Center the legend on the x-axis + ) + ) + + + + slide_1 = prs.slides.add_slide(prs.slide_layouts[6]) + + add_plotly_chart_to_slide(slide_1, fig1, Inches(0.1), Inches(1), width=Inches(9.5), height=Inches(6)) + slide_1 = prs.slides.add_slide(prs.slide_layouts[6]) + add_plotly_chart_to_slide(slide_1, fig2, Inches(0.1), Inches(1), width=Inches(9.5), height=Inches(6)) + slide_1 = prs.slides.add_slide(prs.slide_layouts[6]) + add_plotly_chart_to_slide(slide_1, fig3, Inches(0.1), Inches(1), width=Inches(9.5), height=Inches(6)) + + + + # Save to a BytesIO object + ppt_stream = BytesIO() + prs.save(ppt_stream) + ppt_stream.seek(0) + + return ppt_stream.getvalue() + +def first_day_of_next_year(date): + next_year = date.year + 1 + first_day = datetime(next_year, 1, 1).date() + + # Calculate the last day of the next year + last_day = (first_day + relativedelta(years=1, days=-1)) + + return first_day, last_day + +def first_day_of_next_quarter(date): + current_quarter = (date.month - 1) // 3 + 1 + next_quarter_first_month = ((current_quarter % 4) * 3) + 1 + next_quarter_year = date.year if next_quarter_first_month > 1 else date.year + 1 + # Ensure month is within valid range + if next_quarter_first_month < 1 or next_quarter_first_month > 12: + raise ValueError("Calculated month is out of range: {}".format(next_quarter_first_month)) + # st.write(next_quarter_first_month) + first_day_next_quarter = datetime(next_quarter_year, next_quarter_first_month, 1).date() + last_day_next_quarter = (first_day_next_quarter + relativedelta(months=3)) - relativedelta(days=1) + + return first_day_next_quarter, last_day_next_quarter + + +def first_day_of_next_month(date): + next_month_date = date + relativedelta(months=1) + first_day_next_month = next_month_date.replace(day=1) + last_day_next_month = (first_day_next_month + relativedelta(months=1)) - relativedelta(days=1) + return first_day_next_month, last_day_next_month + +def optimize(key, status_placeholder): + """ + Optimize the spends for the sales + """ + + channel_list = [ + key for key, value in st.session_state["optimization_channels"].items() if value + ] + + if len(channel_list) > 0: + scenario = st.session_state["scenario"] + if key.lower() == "media spends": + with status_placeholder: + with st.spinner("Optimizing"): + # # # # print(channel_list) + # # # # print(st.session_state["total_spends_change"]) + result = st.session_state["scenario"].optimize( + st.session_state["total_spends_change"], channel_list + # result = st.session_state["scenario"].spends_optimisation( + # st.session_state["total_spends_change"], channel_list + ) + # # print("") + # # print(list(zip(*result))) + + + + # elif key.lower() == "revenue": + else: + with status_placeholder: + with st.spinner("Optimizing"): + + result = st.session_state["scenario"].optimize_spends( + st.session_state["total_sales_change"], channel_list + ) + for channel_name, modified_spends in result: + + st.session_state[channel_name] = numerize( + modified_spends * 1.0, + 1, + ) + prev_spends = ( + st.session_state["scenario"].channels[channel_name].actual_total_spends + ) + st.session_state[f"{channel_name}_change"] = round( + 100 * (modified_spends - prev_spends) / prev_spends, 2 + ) + + +def save_scenario(scenario_name): + """ + Save the current scenario with the mentioned name in the session state + + Parameters + ---------- + scenario_name + Name of the scenario to be saved + """ + if "saved_scenarios" not in st.session_state: + st.session_state = OrderedDict() + + # st.session_state['saved_scenarios'][scenario_name] = st.session_state['scenario'].save() + st.session_state["saved_scenarios"][scenario_name] = class_to_dict( + st.session_state["scenario"] + ) + st.session_state["scenario_input"] = "" + # # # # print(type(st.session_state['saved_scenarios'])) + with open("../saved_scenarios.pkl", "wb") as f: + pickle.dump(st.session_state["saved_scenarios"], f) + + +if "allow_spends_update" not in st.session_state: + st.session_state["allow_spends_update"] = True + +if "allow_sales_update" not in st.session_state: + st.session_state["allow_sales_update"] = True + + +def update_sales_abs_slider(): + actual_sales = _scenario.actual_total_sales + if validate_input(st.session_state["total_sales_change_abs_slider"]): + modified_sales = extract_number_for_string( + st.session_state["total_sales_change_abs_slider"] + ) + st.session_state["total_sales_change"] = round( + ((modified_sales / actual_sales) - 1) * 100 + ) + st.session_state["total_sales_change_abs"] = numerize(modified_sales, 1) + + +def update_sales_abs(): + # if ( + # st.session_state["total_sales_change_abs"] + # in st.session_state["total_sales_change_abs_slider_options"] + # ): + # st.session_state["allow_sales_update"] = True + # else: + # st.session_state["allow_sales_update"] = False + + actual_sales = _scenario.actual_total_sales + # if ( + # validate_input(st.session_state["total_sales_change_abs"]) + # and st.session_state["allow_sales_update"] + # ): + modified_sales = extract_number_for_string( + st.session_state["total_sales_change_abs"] + ) + st.session_state["total_sales_change"] = round( + ((modified_sales / actual_sales) - 1) * 100 + ) + st.session_state["total_sales_change_abs_slider"] = numerize(modified_sales, 1) + + +def update_sales(): + st.session_state["total_sales_change_abs"] = numerize( + (1 + st.session_state["total_sales_change"] / 100) + * _scenario.actual_total_sales, + 1, + ) + st.session_state["total_sales_change_abs_slider"] = numerize( + (1 + st.session_state["total_sales_change"] / 100) + * _scenario.actual_total_sales, + 1, + ) + + +# def update_all_spends_abs_slider(): +# actual_spends = _scenario.actual_total_spends +# if validate_input(st.session_state["total_spends_change_abs_slider"]): +# modified_spends = extract_number_for_string( +# st.session_state["total_spends_change_abs_slider"] +# ) +# st.session_state["total_spends_change"] = round( +# ((modified_spends / actual_spends) - 1) * 100 +# ) +# st.session_state["total_spends_change_abs"] = numerize(modified_spends, 1) + +# update_all_spends() + + +# def update_all_spends_abs_slider(): +# actual_spends = _scenario.actual_total_spends +# if validate_input(st.session_state["total_spends_change_abs_slider"]): +# # # # print("#" * 100) +# # # # print(st.session_state["total_spends_change_abs_slider"])C:\Users\PragyaJatav\Downloads\Untitled Folder 2\simulatorAldi\pages\8_Scenario_Planner.py +# # # # print("#" * 100) + +# modified_spends = extract_number_for_string( +# st.session_state["total_spends_change_abs_slider"] +# ) +# st.session_state["total_spends_change"] = ( +# (modified_spends / actual_spends) - 1 +# ) * 100 +# st.session_state["total_spends_change_abs"] = st.session_state[ +# "total_spends_change_abs_slider" +# ] + +# update_all_spends() + + +def update_all_spends_abs(): + # st.write("aon update spends abs") + # if ( + # st.session_state["total_spends_change_abs"] + # in st.session_state["total_spends_change_abs_slider_options"] + # ): + # st.session_state["allow_spends_update"] = True + # # print st.session_state["total_spends_change_abs_slider_options"] + # # print("not allowed") + # else: + # st.session_state["allow_spends_update"] = False + # # st.warning("Invalid Input") + + actual_spends = _scenario.actual_total_spends + if ( + validate_input(st.session_state["total_spends_change_abs"]) + and st.session_state["allow_spends_update"] + ): + modified_spends = extract_number_for_string( + st.session_state["total_spends_change_abs"] + ) + st.session_state["total_spends_change"] = ( + (modified_spends / actual_spends) - 1 + ) * 100 + st.session_state["total_spends_change_abs_slider"] = st.session_state[ + "total_spends_change_abs" + ] + + update_all_spends() + + +def update_spends(): + st.session_state["total_spends_change_abs"] = numerize( + (1 + st.session_state["total_spends_change"] / 100) + * _scenario.actual_total_spends, + 1, + ) + st.session_state["total_spends_change_abs_slider"] = numerize( + (1 + st.session_state["total_spends_change"] / 100) + * _scenario.actual_total_spends, + 1, + ) + + update_all_spends() + + +def update_all_spends(): + """ + Updates spends for all the channels with the given overall spends change + """ + percent_change = st.session_state["total_spends_change"] + + for channel_name in st.session_state["channels_list"]: + channel = st.session_state["scenario"].channels[channel_name] + current_spends = channel.actual_total_spends + modified_spends = (1 + percent_change / 100) * current_spends + st.session_state["scenario"].update(channel_name, modified_spends) + st.session_state[channel_name] = numerize( + modified_spends * channel.conversion_rate, 1 + ) + st.session_state[f"{channel_name}_change"] = percent_change + + +def extract_number_for_string(string_input): + string_input = string_input.upper() + if string_input.endswith("K"): + return float(string_input[:-1]) * 10**3 + elif string_input.endswith("M"): + return float(string_input[:-1]) * 10**6 + elif string_input.endswith("B"): + return float(string_input[:-1]) * 10**9 + + +def validate_input(string_input): + pattern = r"\d+\.?\d*[K|M|B]$" + match = re.match(pattern, string_input) + if match is None: + return False + return True + +def validate_input_lb(string_input): + pattern = r"\d+\.?\d*[K|M|B]$" + match = re.match(pattern, string_input) + if match is None: + return False + response_curve_params = pd.read_excel("response_curves_parameters.xlsx",index_col = "channel") + param_dicts = {col: response_curve_params[col].to_dict() for col in response_curve_params.columns} + if float(string_input) < round(param_dicts["x_min"][channel_name]*10400/param_dicts["current_spends"][channel_name]): + return False + + return True + +def update_data_bound_min(channel_name): + """ + Updates the bounds for the given channel + """ + if validate_input_lb(st.session_state[f"{channel_name}_lower_bound"]): + modified_bounds = st.session_state[f"{channel_name}_lower_bound"] + + # st.session_state['scenario']['channels'][channel_name].channel_bounds_min = st.session_state[f"{channel_name}_lower_bound"] + st.session_state['scenario'].update_bounds_min(channel_name,modified_bounds) + st.write(st.session_state["scenario"].channels[channel_name].channel_bounds_min) + # st.write(st.session_state["scenario"].channels[channel_name] + + +def update_data_bound_max(channel_name): + """ + Updates the bounds for the given channel + """ + modified_bounds = st.session_state[f"{channel_name}_upper_bound"] + + # st.session_state['scenario']['channels'][channel_name].channel_bounds_min = st.session_state[f"{channel_name}_lower_bound"] + st.session_state['scenario'].update_bounds_max(channel_name,modified_bounds) + # st.write(st.session_state["scenario"].channels[channel_name].channel_bounds_max) + # st.write(st.session_state["scenario"].channels[channel_name]) + +def update_data_by_percent(channel_name): + prev_spends = ( + st.session_state["scenario"].channels[channel_name].actual_total_spends + * st.session_state["scenario"].channels[channel_name].conversion_rate + ) + modified_spends = prev_spends * ( + 1 + st.session_state[f"{channel_name}_change"] / 100 + ) + st.session_state[channel_name] = numerize(modified_spends, 1) + st.session_state["scenario"].update( + channel_name, + modified_spends + / st.session_state["scenario"].channels[channel_name].conversion_rate, + ) + + +def update_data(channel_name): + """ + Updates the spends for the given channel + """ + + if validate_input(st.session_state[channel_name]): + modified_spends = extract_number_for_string(st.session_state[channel_name]) + prev_spends = ( + st.session_state["scenario"].channels[channel_name].actual_total_spends + * st.session_state["scenario"].channels[channel_name].conversion_rate + ) + st.session_state[f"{channel_name}_change"] = round( + 100 * (modified_spends - prev_spends) / prev_spends, 2 + ) + st.session_state["scenario"].update( + channel_name, + modified_spends + / st.session_state["scenario"].channels[channel_name].conversion_rate, + ) +# st.write(hasattr(st.session_state["scenario"], 'update_bounds_min')) + # st.session_state['scenario'].update(channel_name, modified_spends) + # else: + # try: + # modified_spends = float(st.session_state[channel_name]) + # prev_spends = st.session_state['scenario'].channels[channel_name].actual_total_spends * st.session_state['scenario'].channels[channel_name].conversion_rate + # st.session_state[f'{channel_name}_change'] = round(100*(modified_spends - prev_spends) / prev_spends,2) + # st.session_state['scenario'].update(channel_name, modified_spends/st.session_state['scenario'].channels[channel_name].conversion_rate) + # st.session_state[f'{channel_name}'] = numerize(modified_spends,1) + # except ValueError: + # st.write('Invalid input') + + + + +def select_channel_for_optimization(channel_name): + """ + Marks the given channel for optimization + """ + st.session_state["optimization_channels"][channel_name] = st.session_state[ + f"{channel_name}_selected" + ] + + # if not all(st.session_state["optimization_channels"].values()): + # st.session_state["optimize_all_channels"] = False + +def select_all_channels_for_optimization(): + """ + Marks all the channel for optimization + """ + for channel_name in st.session_state["optimization_channels"].keys(): + st.session_state[f"{channel_name}_selected"] = st.session_state[ + "optimze_all_channels" + ] + st.session_state["optimization_channels"][channel_name] = st.session_state[ + "optimze_all_channels" + ] + + + +def update_penalty(): + """ + Updates the penalty flag for sales calculation + """ + st.session_state["scenario"].update_penalty(st.session_state["apply_penalty"]) + + +def reset_scenario(panel_selected, file_selected, updated_rcs): + # ## # # print(st.session_state['default_scenario_dict']) + # st.session_state['scenario'] = class_from_dict(st.session_state['default_scenario_dict']) + # for channel in st.session_state['scenario'].channels.values(): + # st.session_state[channel.name] = float(channel.actual_total_spends * channel.conversion_rate) + # initialize_data() + + if panel_selected == "Total Market": + initialize_data( + + target_file=file_selected, + panel=panel_selected, + updated_rcs=updated_rcs, + metrics=metrics_selected, + ) + panel = None + else: + initialize_data( + + target_file=file_selected, + panel=panel_selected, + updated_rcs=updated_rcs, + metrics=metrics_selected, + ) + + for channel_name in st.session_state["channels_list"]: + st.session_state[f"{channel_name}_selected"] = False + st.session_state[f"{channel_name}_change"] = 0 + st.session_state["optimze_all_channels"] = False + + st.session_state["total_sales_change"] = 0 + + update_spends() + update_sales() + + reset_inputs() + + # st.rerun() + + +def format_number(num): + if num >= 1_000_000: + return f"{num / 1_000_000:.2f}M" + elif num >= 1_000: + return f"{num / 1_000:.0f}K" + else: + return f"{num:.2f}" + + +def summary_plot(data, x, y, title, text_column): + fig = px.bar( + data, + x=x, + y=y, + orientation="h", + title=title, + text=text_column, + color="Channel_name", + ) + + # Convert text_column to numeric values + data[text_column] = pd.to_numeric(data[text_column], errors="coerce") + + # Update the format of the displayed text based on magnitude + fig.update_traces( + texttemplate="%{text:.2s}", + textposition="outside", + hovertemplate="%{x:.2s}", + ) + + fig.update_layout(xaxis_title=x, yaxis_title="Channel Name", showlegend=False) + return fig + + +def s_curve(x, K, b, a, x0): + return K / (1 + b * np.exp(-a * (x - x0))) + + +def find_segment_value(x, roi, mroi): + start_value = x[0] + end_value = x[len(x) - 1] + + # Condition for green region: Both MROI and ROI > 1 + green_condition = (roi > 1) & (mroi > 1) + left_indices = np.where(green_condition)[0] + left_value = x[left_indices[0]] if left_indices.size > 0 else x[0] + + right_indices = np.where(green_condition)[0] + right_value = x[right_indices[-1]] if right_indices.size > 0 else x[0] + + return start_value, end_value, left_value, right_value + + +def calculate_rgba( + start_value, end_value, left_value, right_value, current_channel_spends +): + # Initialize alpha to None for clarity + alpha = None + + # Determine the color and calculate relative_position and alpha based on the point's position + if start_value <= current_channel_spends <= left_value: + color = "yellow" + relative_position = (current_channel_spends - start_value) / ( + left_value - start_value + ) + alpha = 0.8 - (0.6 * relative_position) # Alpha decreases from start to end + + elif left_value < current_channel_spends <= right_value: + color = "green" + relative_position = (current_channel_spends - left_value) / ( + right_value - left_value + ) + alpha = 0.8 - (0.6 * relative_position) # Alpha decreases from start to end + + elif right_value < current_channel_spends <= end_value: + color = "red" + relative_position = (current_channel_spends - right_value) / ( + end_value - right_value + ) + alpha = 0.2 + (0.6 * relative_position) # Alpha increases from start to end + + else: + # Default case, if the spends are outside the defined ranges + return "rgba(136, 136, 136, 0.5)" # Grey for values outside the range + + # Ensure alpha is within the intended range in case of any calculation overshoot + alpha = max(0.2, min(alpha, 0.8)) + + # Define color codes for RGBA + color_codes = { + "yellow": "255, 255, 0", # RGB for yellow + "green": "0, 128, 0", # RGB for green + "red": "255, 0, 0", # RGB for red + } + + rgba = f"rgba({color_codes[color]}, {alpha})" + return rgba + + +def debug_temp(x_test, power, K, b, a, x0): + # # # # print("*" * 100) + # Calculate the count of bins + count_lower_bin = sum(1 for x in x_test if x <= 2524) + count_center_bin = sum(1 for x in x_test if x > 2524 and x <= 3377) + count_ = sum(1 for x in x_test if x > 3377) + + # # # # print( + # f""" + # lower : {count_lower_bin} + # center : {count_center_bin} + # upper : {count_} + # """ + # ) + + +# @st.cache +def plot_response_curves(summary_df_sorted): + # rows = ( + # len(channels_list) // cols + # if len(channels_list) % cols == 0 + # else len(channels_list) // cols + 1 + # ) + # rcs = st.session_state["rcs"] + # shapes = [] + # fig = make_subplots(rows=rows, cols=cols, subplot_titles=channels_list) + channel_cols = [ + 'BroadcastTV', + 'CableTV', + 'Connected&OTTTV', + 'DisplayProspecting', + 'DisplayRetargeting', + 'Video', + 'SocialProspecting', + 'SocialRetargeting', + 'SearchBrand', + 'SearchNon-brand', + 'DigitalPartners', + 'Audio', + 'Email'] + summary_df_sorted.index = summary_df_sorted["Channel_name"] + figures = [rc.response_curves(channels_list[i], summary_df_sorted["Optimized_spend"][channels_list[i]], summary_df_sorted["New_sales"][channels_list[i]]) for i in range(13)] + + # for i in range() + + # Display figures in a grid layout + cols = st.columns(3) # 4 columns for the grid + + for idx, fig in enumerate(figures): + col = cols[idx % 3] + with col: + st.plotly_chart(fig, use_container_width=True) + +# ======================================================== # +# ==================== HTML Components =================== # +# ======================================================== # + + +def generate_spending_header(heading): + return st.markdown( + f"""

{heading}

""", unsafe_allow_html=True + ) + + +# ======================================================== # +# =================== Session variables ================== # +# ======================================================== # + +with open("config.yaml") as file: + config = yaml.load(file, Loader=SafeLoader) + st.session_state["config"] = config + +authenticator = stauth.Authenticate( + config["credentials"], + config["cookie"]["name"], + config["cookie"]["key"], + config["cookie"]["expiry_days"], + config["preauthorized"], +) +st.session_state["authenticator"] = authenticator +name, authentication_status, username = authenticator.login("Login", "main") +auth_status = st.session_state.get("authentication_status") + +import os +import glob + +def upload_file_prospects_calc(df): + df["Prospects"] = 0 + + params = pd.read_excel(r"response_curves_parameters.xlsx",index_col = "channel") + param_dicts = {col: params[col].to_dict() for col in params.columns} + df.index = df.channel +# # # # print(param_dicts) + for col in df.channel: + x = df["Spends"][col] + dividing_rate = 104 + # st.write(x) + x_inp = ( x/dividing_rate- param_dicts["x_min"][col]) / (param_dicts["x_max"][col] - param_dicts["x_min"][col]) + x_out = x_inp**param_dicts["n"][col] / (param_dicts["Kd"][col]**param_dicts["n"][col] + x_inp**param_dicts["n"][col]) #self.hill_equation(x_inp,Kd, n) + # # # # print("x_out",x_out) + + + x_val_inv = (x_out*param_dicts["x_max"][col] + (1 - x_out) * param_dicts["x_min"][col]) + sales = (x_val_inv*param_dicts["y_min"][col]/param_dicts["y_max"][col])*dividing_rate + # sales = ((x_max - x_min)*x_out + x_min)*dividing_rate + + # x = (df["Spends"][col]/104 - param_dicts["x_min"][col])/(param_dicts["x_max"][col]-param_dicts["x_min"][col]) + # x_out = x**param_dicts["n"][col]/(param_dicts["Kd"][col]**param_dicts["n"][col]+ x**param_dicts["n"][col]) + # x_out_inv = (x_out*(param_dicts["y_max"][col]-param_dicts["y_min"][col])+param_dicts["y_min"][col])*104 + df["Prospects"][col] = sales + # # # # print(df) + return df + + +def upload_file_format(df): + # key_df = pd.DataFrame() + # key_df["channel"] = ["Broadcast TV","Cable TV","Connected & OTT TV","Display Prospecting","Display Retargeting","Video","Social Prospecting","Social Retargeting","Search Brand","Search Non-brand","Digital Partners","Audio","Email"] + + # key_df["channels"] = ["BroadcastTV","CableTV","Connected&OTTTV","DisplayProspecting","DisplayRetargeting","\xa0Video","SocialProspecting","SocialRetargeting","SearchBrand","SearchNon-brand","DigitalPartners","Audio","Email"] + # df = df.merge(key_df,on = "channel", how = "inner") + # # st.dataframe(df) + # df["channel"] = df["channels"] + # df.drop(columns = ["channel"]) + + df1 = df.transpose() + df1.reset_index(inplace = True) + df1.columns = df1.iloc[0] + df1 = df1[1:] + df1["channel"] = pd.to_datetime('1999-08-06').date() + df1.rename(columns = {"channel":"Date"},inplace = True) + + df2 = df1.rename(columns = {"Date":"Week"}) + + df3 =upload_file_prospects_calc(df) + df3 = df3[["Prospects"]].transpose().reset_index() + df3["index"] = pd.to_datetime('1999-08-06').date() + df3.rename(columns = {"index":"Date"},inplace = True) + df3.insert(1, 'const', [0]) + + # st.dataframe(df3) + + # Create a buffer to hold the Excel file + import io + output = io.BytesIO() + + # Write the dataframes to an Excel file + with pd.ExcelWriter(output, engine='openpyxl') as writer: + df1.to_excel(writer, index=False, sheet_name='RAW DATA MMM') + df2.to_excel(writer, index=False, sheet_name='SPEND INPUT') + df3.to_excel(writer, index=False, sheet_name='CONTRIBUTION MMM') + + # Seek to the beginning of the stream + output.seek(0) + + with open('Overview_data_uploaded.xlsx', 'wb') as f: + f.write(output.getvalue()) + + return + +def get_excel_names(directory): + # Create a list to hold the final parts of the filenames + last_portions = [] + + # Patterns to match Excel files (.xlsx and .xls) that contain @# + patterns = [ + os.path.join(directory, "*@#*.xlsx"), + os.path.join(directory, "*@#*.xls"), + ] + + # Process each pattern + for pattern in patterns: + files = glob.glob(pattern) + + # Extracting the last portion after @# for each file + for file in files: + base_name = os.path.basename(file) + last_portion = base_name.split("@#")[-1] + last_portion = last_portion.replace(".xlsx", "").replace( + ".xls", "" + ) # Removing extensions + last_portions.append(last_portion) + + return last_portions + + +def name_formating(channel_name): + # Replace underscores with spaces + name_mod = channel_name.replace("_", " ") + + # Capitalize the first letter of each word + name_mod = name_mod.title() + + return name_mod + + +@st.cache_data(show_spinner=False) +def panel_fetch(file_selected): + raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM") + + # if "Panel" in raw_data_mmm_df.columns: + # panel = list(set(raw_data_mmm_df["Panel"])) + # else: + # raw_data_mmm_df = None + # panel = None + # raw_data_mmm_df = None + panel = None + return panel + + +def reset_inputs(): + if "total_spends_change_abs" in st.session_state: + del st.session_state.total_spends_change_abs + if "total_spends_change" in st.session_state: + del st.session_state.total_spends_change + if "total_spends_change_abs_slider" in st.session_state: + del st.session_state.total_spends_change_abs_slider + + if "total_sales_change_abs" in st.session_state: + del st.session_state.total_sales_change_abs + if "total_sales_change" in st.session_state: + del st.session_state.total_sales_change + if "total_sales_change_abs_slider" in st.session_state: + del st.session_state.total_sales_change_abs_slider + + st.session_state["initialized"] = False + +def scenario_planner_plots2(): + import plotly.graph_objects as go + from plotly.subplots import make_subplots + + + with open('summary_df.pkl', 'rb') as file: + summary_df_sorted = pickle.load(file) + #st.write(summary_df_sorted) + + # selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2']) + summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False) + 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()) + 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()) + summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend'] + summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend'] + + total_actual_spend = summary_df_sorted['Actual_spend'].sum() + total_optimized_spend = summary_df_sorted['Optimized_spend'].sum() + actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100 + optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100 + + + + light_blue = 'rgba(0, 31, 120, 0.7)' + light_orange = 'rgba(0, 181, 219, 0.7)' + light_green = 'rgba(240, 61, 20, 0.7)' + light_red = 'rgba(250, 110, 10, 0.7)' + light_purple = 'rgba(255, 191, 69, 0.7)' + + fig1 = go.Figure() + # Add actual vs optimized spend bars + + + fig1.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['Actual_spend'], name='Actual', + text=summary_df_sorted['Actual_spend'].apply(format_number) + ' ' + # + + # ' '+ + # '
(' + actual_spend_percentage.astype(int).astype(str) + '%)' + ,textposition='outside',#textfont=dict(size=30), + marker_color=light_blue)) + + + fig1.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['Optimized_spend'], name='Optimized', + text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' ' + # + + # '
(' + optimized_spend_percentage.astype(int).astype(str) + '%)' + ,textposition='outside',#textfont=dict(size=30), + marker_color=light_orange)) + + fig1.update_xaxes(title_text="Channels") + fig1.update_yaxes(title_text="Spends ($)") + fig1.update_layout( + title = "Actual vs. Optimized Spends", + margin=dict(t=40, b=40, l=40, r=40) + ) + + # st.plotly_chart(fig1,use_container_width=True) + + # Add actual vs optimized Contribution + fig2 = go.Figure() + fig2.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['Old_sales'], + name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),textposition='outside', + marker_color=light_blue,showlegend=True)) + + fig2.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['New_sales'], + name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),textposition='outside', + marker_color=light_orange, showlegend=True)) + + + + fig2.update_yaxes(title_text="Contribution") + fig2.update_xaxes(title_text="Channels") + fig2.update_layout( + title = "Actual vs. Optimized Contributions", + margin=dict(t=40, b=40, l=40, r=40) + # yaxis=dict(range=[0, 0.002]), + ) + # st.plotly_chart(fig2,use_container_width=True) + + # Add actual vs optimized Efficiency bars + fig3 = go.Figure() + summary_df_sorted_p = summary_df_sorted[summary_df_sorted['Channel_name']!="Panel"] + fig3.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'].apply(channel_name_formating), y=summary_df_sorted_p['old_efficiency'], + name='Actual Efficiency', text=summary_df_sorted_p['old_efficiency'].apply(format_number) ,textposition='outside', + marker_color=light_blue,showlegend=True)) + fig3.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'].apply(channel_name_formating), y=summary_df_sorted_p['new_efficiency'], + name='Optimized Efficiency',text=summary_df_sorted_p['new_efficiency'].apply(format_number),textposition='outside' , + marker_color=light_orange,showlegend=True)) + + fig3.update_xaxes(title_text="Channels") + fig3.update_yaxes(title_text="Efficiency") + fig3.update_layout( + title = "Actual vs. Optimized Efficiency", + margin=dict(t=40, b=40, l=40, r=40), + # yaxis=dict(range=[0, 0.002]), + ) + + # st.plotly_chart(fig3,use_container_width=True) + return fig1,fig2,fig3 +def scenario_planner_plots(): + with st.expander('Optimized Spends Overview'): + # if st.button('Refresh'): + # st.experimental_rerun() + + import plotly.graph_objects as go + from plotly.subplots import make_subplots + + # Define light colors for bars + import plotly.graph_objects as go + from plotly.subplots import make_subplots + + st.empty() + #st.header('Model Result Analysis') + spends_data=pd.read_excel('Overview_data_test.xlsx') + + with open('summary_df.pkl', 'rb') as file: + summary_df_sorted = pickle.load(file) + #st.write(summary_df_sorted) + + # selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2']) + summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False) + 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()) + 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()) + + summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend'] + summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend'] + + total_actual_spend = summary_df_sorted['Actual_spend'].sum() + total_optimized_spend = summary_df_sorted['Optimized_spend'].sum() + + actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100 + optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100 + + + + light_blue = 'rgba(0, 31, 120, 0.7)' + light_orange = 'rgba(0, 181, 219, 0.7)' + light_green = 'rgba(240, 61, 20, 0.7)' + light_red = 'rgba(250, 110, 10, 0.7)' + light_purple = 'rgba(255, 191, 69, 0.7)' + + fig1 = go.Figure() + # Add actual vs optimized spend bars + + + fig1.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['Actual_spend'], name='Actual', + text=summary_df_sorted['Actual_spend'].apply(format_number) + ' ' + # + + # ' '+ + # '
(' + actual_spend_percentage.astype(int).astype(str) + '%)' + ,textposition='outside',#textfont=dict(size=30), + marker_color=light_blue)) + + + fig1.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['Optimized_spend'], name='Optimized', + text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' ' + # + + # '
(' + optimized_spend_percentage.astype(int).astype(str) + '%)' + ,textposition='outside',#textfont=dict(size=30), + marker_color=light_orange)) + + fig1.update_xaxes(title_text="Channels") + fig1.update_yaxes(title_text="Spends ($)") + fig1.update_layout( + title = "Actual vs. Optimized Spends", + margin=dict(t=40, b=40, l=40, r=40) + ) + + st.plotly_chart(fig1,use_container_width=True) + + # Add actual vs optimized Contribution + fig2 = go.Figure() + fig2.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['Old_sales'], + name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),textposition='outside', + marker_color=light_blue,showlegend=True)) + + fig2.add_trace(go.Bar(x=summary_df_sorted['Channel_name'].apply(channel_name_formating), y=summary_df_sorted['New_sales'], + name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),textposition='outside', + marker_color=light_orange, showlegend=True)) + + + + fig2.update_yaxes(title_text="Contribution") + fig2.update_xaxes(title_text="Channels") + fig2.update_layout( + title = "Actual vs. Optimized Contributions", + margin=dict(t=40, b=40, l=40, r=40) + # yaxis=dict(range=[0, 0.002]), + ) + st.plotly_chart(fig2,use_container_width=True) + + # Add actual vs optimized Efficiency bars + fig3 = go.Figure() + summary_df_sorted_p = summary_df_sorted[summary_df_sorted['Channel_name']!="Panel"] + fig3.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'].apply(channel_name_formating), y=summary_df_sorted_p['old_efficiency'], + name='Actual Efficiency', text=summary_df_sorted_p['old_efficiency'].apply(format_number) ,textposition='outside', + marker_color=light_blue,showlegend=True)) + fig3.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'].apply(channel_name_formating), y=summary_df_sorted_p['new_efficiency'], + name='Optimized Efficiency',text=summary_df_sorted_p['new_efficiency'].apply(format_number),textposition='outside' , + marker_color=light_orange,showlegend=True)) + + fig3.update_xaxes(title_text="Channels") + fig3.update_yaxes(title_text="Efficiency") + fig3.update_layout( + title = "Actual vs. Optimized Efficiency", + margin=dict(t=40, b=40, l=40, r=40), + # yaxis=dict(range=[0, 0.002]), + ) + + st.plotly_chart(fig3,use_container_width=True) + return fig1,fig2,fig3 + +def give_demo(): + def get_file_bytes(file_path): + with open(file_path, 'rb') as file: + return file.read() + + # Path to the existing Excel file + file_path = 'input_data_example.xlsx' + + # Create a download button + st.download_button( + label="Download Input File Format", + data=get_file_bytes(file_path), + file_name=file_path, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) +if auth_status == True: + authenticator.logout("Logout", "main") + st.header("Scenario Planner") + + data_selected = st.selectbox( + "Select base data for optimisation", options=["Optimise Actual Spends", "Optimise Uploaded Spends"], + key = "data_upload_key",index = 1) + # st.text_input("") + + + + + # Response Metrics + directory = "metrics_level_data" + metrics_list = get_excel_names(directory) + + # metrics_selected = col1.selectbox( + # "Response Metrics", + # metrics_list, + # format_func=name_formating, + # index=0, + # on_change=reset_inputs, + # ) + + metrics_selected='prospects' + # Target + target = name_formating(metrics_selected) + + # file_selected = ( + # f"Overview_data_test_panel@#{metrics_selected}.xlsx" + # ) + file_selected = None + if data_selected == "Optimise Uploaded Spends": + give_demo() + st.write("Select a file to upload") + + uploaded_file = st.file_uploader("Choose an Excel file", type=["xlsx", "xls"]) + # give_demo() + if uploaded_file: + try: + # Read the Excel file using pandas + df = pd.read_excel(uploaded_file, engine='openpyxl') + upload_file_format(df) + file_selected = "Overview_data_uploaded.xlsx" + + # initialize_data( + + # target_file=file_selected, + # panel="Total Market", + # updated_rcs=None, + # metrics=metrics_selected, + # ) + except Exception as e: + st.error(f"Error reading the file: {e}") + + elif data_selected == "Optimise Actual Spends": + file_selected = ( + f"Overview_data_test_panel@#{metrics_selected}.xlsx" + ) + # initialize_data( + + # target_file=file_selected, + # panel="Total Market", + # updated_rcs=None, + # metrics=metrics_selected, + # ) + + else : + st.write("") + + if file_selected: + st.session_state['file_selected']=file_selected + # Panel List + panel_list = panel_fetch(file_selected) + + # # Panel Selected + # panel_selected = st.selectbox( + # "Markets", + # ["Total Market"] + panel_list, + # index=0, + # on_change=reset_inputs, + # ) + + # st.write(panel_selected) + panel_selected = "Total Market" + st.session_state['selected_markets']=panel_selected + + if "update_rcs" in st.session_state: + updated_rcs = st.session_state["update_rcs"] + else: + updated_rcs = None + + if "first_time" not in st.session_state: + st.session_state["first_time"] = True + + # Check if state is initiaized + is_state_initiaized = st.session_state.get("initialized", False) + if not is_state_initiaized or st.session_state["first_time"]: + initialize_data( + + target_file=file_selected, + panel=panel_selected, + updated_rcs=updated_rcs, + metrics=metrics_selected, + ) + st.session_state["initialized"] = True + st.session_state["first_time"] = False + save_scenario("current scenario") + + + + # initialize_data( + # panel=panel_selected, + # target_file=file_selected, + # updated_rcs=updated_rcs, + # metrics=metrics_selected, + # ) + # st.session_state["initialized"] = True + # st.session_state["first_time"] = False + + # Channels List + channels_list = st.session_state["channels_list"] + + # ======================================================== # + # ========================== UI ========================== # + # ======================================================== # + + # # # # print(list(st.session_state.keys())) + main_header = st.columns((2, 2)) + sub_header = st.columns((1, 1, 1, 1)) + _scenario = st.session_state["scenario"] + + if "total_spends_change" not in st.session_state: + st.session_state.total_spends_change = 0 + + if "total_sales_change" not in st.session_state: + st.session_state.total_sales_change = 0 + + if "total_spends_change_abs" not in st.session_state: + st.session_state["total_spends_change_abs"] = numerize( + _scenario.actual_total_spends, 1 + ) + + # st.write(_scenario.actual_total_sales) + if "total_sales_change_abs" not in st.session_state: + st.session_state["total_sales_change_abs"] = numerize( + _scenario.actual_total_sales, 1 + ) + + if "total_spends_change_abs_slider" not in st.session_state: + st.session_state.total_spends_change_abs_slider = numerize( + _scenario.actual_total_spends, 1 + ) + + if "total_sales_change_abs_slider" not in st.session_state: + st.session_state.total_sales_change_abs_slider = numerize( + _scenario.actual_total_sales, 1 + ) + + if "lower_bound_key" not in st.session_state: + st.session_state["lower_bound_key"] = 10 + + if "upper_bound_key" not in st.session_state: + st.session_state["upper_bound_key"] = 100 + + # st.write(_scenario.modified_total_sales) + header_df = pd.DataFrame(index=["Actual","Simulated","Change","Percent Change"],columns=["Spends","Prospects"]) + header_df["Spends"]["Actual"] = format_numbers(_scenario.actual_total_spends) + header_df["Spends"]["Simulated"] = format_numbers(_scenario.modified_total_spends) + header_df["Spends"]["Change"] = format_numbers(_scenario.delta_spends) #_scenario.modified_total_spends -_scenario.actual_total_spends + header_df["Spends"]["Percent Change"] = numerize(100*(_scenario.delta_spends/_scenario.actual_total_spends))+'%' + + header_df["Prospects"]["Actual"] = format_numbers_f(float(_scenario.actual_total_sales)) + header_df["Prospects"]["Simulated"] = format_numbers_f(float(_scenario.modified_total_sales)) + header_df["Prospects"]["Change"] = format_numbers_f(_scenario.delta_sales) + header_df["Prospects"]["Percent Change"] = numerize(100*(_scenario.delta_sales/_scenario.actual_total_sales),1)+'%' + + st.markdown("""
""", unsafe_allow_html=True) + _columns = st.columns((1, 1, 1, 1, 1)) + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + with _columns[0]: + st.markdown(f'

{"Metrics"}

', unsafe_allow_html=True) + # generate_spending_header("Metric") + with _columns[1]: + st.markdown(f'

{"Actual"}

', unsafe_allow_html=True) + # generate_spending_header("Actual") + with _columns[2]: + st.markdown(f'

{"Simulated"}

', unsafe_allow_html=True) + # generate_spending_header("Optimised") + with _columns[3]: + st.markdown(f'

{"Change"}

', unsafe_allow_html=True) + # generate_spending_header("Change") + with _columns[4]: + st.markdown(f'

{"Change Percent"}

', unsafe_allow_html=True) + # generate_spending_header("Change Percent") + st.markdown("""
""", unsafe_allow_html=True) + + _columns = st.columns((1, 1, 1, 1, 1)) + with _columns[0]: + st.markdown("""

Spends

""",unsafe_allow_html=True) + # st.write("Spends") + with _columns[1]: + st.markdown(f"""

{header_df["Spends"]["Actual"]}

""",unsafe_allow_html=True) + # st.metric(label="", value=header_df["Spends"]["Actual"]) + with _columns[2]: + st.markdown(f"""

{header_df["Spends"]["Simulated"]}

""",unsafe_allow_html=True) + if _scenario.delta_spends < 0: + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + else: + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + # st.metric(label="", value=header_df["Spends"]["Simulated"]) + with _columns[3]: + + # Apply custom styles to text + st.markdown(f'

{header_df["Spends"]["Change"]}

', unsafe_allow_html=True) + with _columns[4]: + # Apply custom styles to text + # st.markdown(f'

', unsafe_allow_html=True) + st.markdown(f'

{header_df["Spends"]["Percent Change"]}

', unsafe_allow_html=True) + st.markdown( + """
""", + unsafe_allow_html=True, + ) + _columns = st.columns((1, 1, 1, 1, 1)) + with _columns[0]: + # st.header("Prospects") + st.markdown("""

Prospects

""",unsafe_allow_html=True) + with _columns[1]: + st.markdown(f"""

{header_df["Prospects"]["Actual"]}

""",unsafe_allow_html=True) + # st.metric(label="", value=header_df["Prospects"]["Actual"]) + with _columns[2]: + st.markdown(f"""

{header_df["Prospects"]["Simulated"]}

""",unsafe_allow_html=True) + # st.metric(label="", value=header_df["Prospects"]["Simulated"]) + + if _scenario.delta_sales >= 0: + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + else: + st.markdown("""""",unsafe_allow_html=True) + with _columns[3]: + # Apply custom styles to text + st.markdown(f'

{header_df["Prospects"]["Change"]}

', unsafe_allow_html=True) + # st.markdown(f'

{st.metric(label="", value=header_df["Prospects"]["Change"])}

', unsafe_allow_html=True) + # st.markdown(f'

{header_df["Prospects"]["Change"]}

', unsafe_allow_html=True) + + with _columns[4]: + # st.markdown(f'

', unsafe_allow_html=True) + # Apply custom styles to text + st.markdown(f'

{header_df["Prospects"]["Percent Change"]}

', unsafe_allow_html=True) + st.markdown( + """
""", + unsafe_allow_html=True, + ) + + _columns = st.columns((1, 1, 1, 1, 1)) + ef1 = (_scenario.actual_total_spends/_scenario.actual_total_sales) + ef2 = (_scenario.modified_total_spends/_scenario.modified_total_sales) + with _columns[0]: + st.markdown("""

Cost Per Prospect

""",unsafe_allow_html=True) + # st.header("Cost Per Prospect") + with _columns[1]: + st.markdown(f"""

{'$ '+numerize(ef1,0)}

""",unsafe_allow_html=True) + # st.metric(label="", value='$ '+numerize(ef1,0)) + with _columns[2]: + st.markdown(f"""

{'$ '+numerize(ef2,0)}

""",unsafe_allow_html=True) + # st.metric(label="", value='$ '+numerize(ef2,0)) + + if ef2 <= ef1: + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + else: + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + + with _columns[3]: + + + # Apply custom styles to text + st.markdown(f'

{"$ "+numerize(ef2-ef1,0)}

', unsafe_allow_html=True) + # st.markdown(f'

{st.metric(label="", value=header_df["Prospects"]["Change"])}

', unsafe_allow_html=True) + # st.markdown(f'

{header_df["Prospects"]["Change"]}

', unsafe_allow_html=True) + + with _columns[4]: + # st.markdown(f'

', unsafe_allow_html=True) + # Apply custom styles to text + st.markdown(f'

{round((ef2-ef1)/ef1*100,2)}%

', unsafe_allow_html=True) + st.markdown("""
""",unsafe_allow_html=True) + + # st.markdown("""
""", unsafe_allow_html=True) + + # header_df.reset_index(inplace=True) + # # Function to color the index + # def highlight_index(s): + # return ['background-color: lightblue' for _ in s] + + # # Function to color the header + # def highlight_header(s): + # return ['background-color: lightgreen' for _ in s] + + # # Applying the styles + # styled_df = header_df.style \ + # .apply(highlight_index, axis=0, subset=pd.IndexSlice[:, :]) \ + # .set_table_styles({ + # 'A': [{'selector': 'th', 'props': [('background-color', 'lightgreen')]}], + # 'B': [{'selector': 'th', 'props': [('background-color', 'lightgreen')]}], + # 'C': [{'selector': 'th', 'props': [('background-color', 'lightgreen')]}] + # }) + + # # Function to apply arrows based on value + # def format_arrows(val): + # if val > 0: + # return '' # Green up arrow + # elif val < 0: + # return '' # Red down arrow + # return '' # No arrow for zero + + # # Function to format specific rows and exclude the first column + # def apply_row_formatting(df, rows): + # def format_cell(val, row_idx, col_idx): + # if row_idx in rows and col_idx > 0: # Exclude the first column (col_idx > 0) + # return format_arrows(val) + # return '' # No formatting for other cells + + # return df.style.apply(lambda x: [format_cell(val, i, col) for i, (val, col) in enumerate(zip(x, range(len(x))))], axis=1) + + # # Apply formatting to 3rd and 4th rows (index 2 and 3) + # styled_df = apply_row_formatting(header_df, [2, 3]) + + # st.markdown(styled_df.to_html(escape=False), unsafe_allow_html=True) + + # st.markdown(header_df.style.set_table_styles + # ([{'selector': 'th', + # 'props': [('background-color', '#D3D3D3'), + # ('font-size', '25px')]}, + # { + # 'selector' : 'td:first-child', + # 'props' : [('background-color', '#D3D3D3'), + # ('font-size', '25px')] + # } + # , + # {'selector': 'tbody td', + # 'props': [('font-size', '20px')]} + + # ]).to_html(),unsafe_allow_html=True) + + + + # styled_df = header_df.style.apply(highlight_first_col, axis=1) + + # st.table(styled_df) + + + # with main_header[0]: + # st.subheader("Actual") + + # with main_header[-1]: + # st.subheader("Simulated") + + # with sub_header[0]: + # st.metric(label="Spends", value=format_numbers(_scenario.actual_total_spends)) + + # with sub_header[1]: + # st.metric( + # label=target, + # value=format_numbers_f( + # float(_scenario.actual_total_sales) + # ), + # ) + + # with sub_header[2]: + # st.metric( + # label="Spends", + # value=format_numbers(_scenario.modified_total_spends), + # delta=numerize(_scenario.delta_spends, 1), + # ) + + # with sub_header[3]: + # st.metric( + # label=target, + # value=format_numbers_f( + # float(_scenario.modified_total_sales) + # ), + # delta=numerize(_scenario.delta_sales, 1), + # ) + + with st.expander("Channel Spends Simulator", expanded=True): + _columns1 = st.columns((1.5, 1.5, 1,1)) + with _columns1[0]: + optimization_selection = st.selectbox( + "Optimize", options=["Media Spends", target], key="optimization_key" + ) + + with _columns1[1]: + # st.markdown("#") + # if st.checkbox( + # label="Optimize all Channels", + # key="optimze_all_channels", + # value=False, + # # on_change=select_all_channels_for_optimization, + # ): + # select_all_channels_for_optimization() + + st.checkbox( + label="Optimize all Channels", + key="optimze_all_channels", + value=False, + on_change=select_all_channels_for_optimization, + ) + + with _columns1[2]: + # + + + + optimize_placeholder = st.empty() + + with _columns1[3]: + # st.markdown("#") + st.button( + "Reset", + on_click=reset_scenario, + args=(panel_selected, file_selected, updated_rcs), + # use_container_width=True, + ) + # st.write(target) + + + _columns2 = st.columns((2, 2, 2,2)) + if st.session_state["optimization_key"] == "Media Spends": + # st.write(overall_lower_bound,overall_upper_bound) + + with _columns2[2]: + overall_lower_bound = st.number_input( + "Overall Lower Bound for Spends", + value = 50.0, + key = "overall_lower_bound", + # on_change=partial(update_data_bound_min_overall) + ) + with _columns2[3]: + overall_upper_bound = st.number_input( + "Overall Upper Bound for Spends", + value = 50.0, + key = "overall_upper_bound", + # on_change=partial(update_data_bound_max_overall) + ) + min_value = round(_scenario.actual_total_spends * (1-overall_lower_bound/100)) + max_value = round(_scenario.actual_total_spends * (1-overall_upper_bound/100)) + with _columns2[0]: + spend_input = st.text_input( + "Absolute", + key="total_spends_change_abs", + # label_visibility="collapsed", + on_change=update_all_spends_abs, + ) + # st.write(min_value,max_value) + # overall_lower_bound = 50.0 + # overall_upper_bound = 50.0 + with _columns2[1]: + st.number_input( + "Percent Change", + key="total_spends_change", + min_value= -1*overall_lower_bound, + max_value= overall_upper_bound, + step=0.01, + value=0.00, + on_change=update_spends, + ) + + + + st.session_state["total_spends_change_abs_slider_options"] = [ + numerize(value, 1) + for value in range(min_value, max_value + 1, int(1e4)) + ] + + # st.select_slider( + # "Absolute Slider", + # options=st.session_state["total_spends_change_abs_slider_options"], + # key="total_spends_change_abs_slider", + # on_change=update_all_spends_abs_slider, + # ) + + elif st.session_state["optimization_key"] == target: + # st.write(target) + with _columns2[0]: + sales_input = st.text_input( + "Absolute", + key="total_sales_change_abs", + on_change=update_sales_abs, + ) + + with _columns2[1]: + st.number_input( + "Percent Change", + key="total_sales_change", + min_value=-50.00, + max_value=50.00, + step=0.01, + + value=0.00, + on_change=update_sales, + ) + with _columns2[2]: + overall_lower_bound = st.number_input( + "Overall Lower Bound for Spends", + value = 50 + ) + with _columns2[3]: + + overall_upper_bound = st.number_input( + "Overall Upper Bound for Spends", + value = 50 + ) + + min_value = round(_scenario.actual_total_sales * (1-overall_lower_bound/100)) + max_value = round(_scenario.actual_total_sales * (1+overall_upper_bound/100)) + # st.write(min_value) + # st.write(max_value) + # for value in range(min_value, max_value + 1, int(100)): + # st.write(numerize(value, 1)) + # st.session_state["total_sales_change_abs_slider_options"] = [ + # numerize(value, 1) + # for value in range(min_value, max_value + 1, int(100)) + # ] + + # st.select_slider( + # "Absolute Slider", + # options=st.session_state["total_sales_change_abs_slider_options"], + # key="total_sales_change_abs_slider", + # on_change=update_sales_abs_slider, + # # value=numerize(min_value, 1) + # ) + + if ( + not st.session_state["allow_sales_update"] + and optimization_selection == target + ): + st.warning("Invalid Input") + + if ( + not st.session_state["allow_spends_update"] + and optimization_selection == "Media Spends" + ): + st.warning("Invalid Input") + + + status_placeholder = st.empty() + + # if optimize_placeholder.button("Optimize", use_container_width=True): + # optimize(st.session_state["optimization_key"], status_placeholder) + # st.rerun() + + optimize_placeholder.button( + "Optimize", + on_click=optimize, + args=(st.session_state["optimization_key"], status_placeholder), + # use_container_width=True, + ) + + st.markdown("""
""", unsafe_allow_html=True) + _columns = st.columns((1.5,2.5,2,2, 1)) + with _columns[0]: + generate_spending_header("Channel") + with _columns[1]: + generate_spending_header("Spends Input") + with _columns[2]: + generate_spending_header("Spends") + with _columns[3]: + generate_spending_header(target) + with _columns[4]: + generate_spending_header("Optimize") + + st.markdown("""
""", unsafe_allow_html=True) + + if "acutual_predicted" not in st.session_state: + st.session_state["acutual_predicted"] = { + "Channel_name": [], + "Actual_spend": [], + "Optimized_spend": [], + "Delta": [], + "New_sales":[], + "Old_sales":[] + } + for i, channel_name in enumerate(channels_list): + # st.write(channel_name) + _channel_class = st.session_state["scenario"].channels[channel_name] + # st.write(st.session_state["scenario"].channels[channel_name]) + # st.write(st.session_state["scenario"].channels[channel_name].actual_total_sales) + # st.write(st.session_state["scenario"].channels[channel_name].actual_total_spends) + # st.write(st.session_state["scenario"].channels[channel_name].modified_total_sales) + # st.write(st.session_state["scenario"].channels[channel_name].modified_total_spends) + # st.write(st.session_state["scenario"].channels[channel_name].bounds) + # st.write(st.session_state["scenario"].channels[channel_name].channel_bounds_min) + + _columns = st.columns((1.5,2.5,2,2, 1)) + response_curve_params = pd.read_excel("response_curves_parameters.xlsx",index_col = "channel") + param_dicts = {col: response_curve_params[col].to_dict() for col in response_curve_params.columns} + + with _columns[0]: + st.write(channel_name_formating(channel_name)) + bin_placeholder = st.container() + + with _columns[1]: + channel_bounds = _channel_class.bounds + # st.write(channel_bounds) + channel_spends = float(_channel_class.actual_total_spends) + channel_bounds_min = float(_channel_class.channel_bounds_min) + channel_bounds_max = float(_channel_class.channel_bounds_max) + min_value = float((1 - channel_bounds_min / 100) * channel_spends) + max_value = float((1 + channel_bounds_max / 100) * channel_spends) + # st.write(channel_spends) + # st.write(min_value) + # st.write(max_value) + ### # # print(st.session_state[channel_name]) + # st.write(_channel_class.channel_bounds_min,channel_bounds_min) + # st.write(_channel_class.channel_bounds_max,channel_bounds_max) + _columns_min = st.columns(2) + with _columns_min[0]: + spend_input = st.text_input( + "Absolute", + key=channel_name, + # label_visibility="collapsed", + on_change=partial(update_data, channel_name), + + ) + channel_name_lower_bound = f"{channel_name}_lower_bound" + + if channel_name_lower_bound not in st.session_state: + st.session_state[channel_name_lower_bound] = str(round(param_dicts["x_min"][channel_name]*10400/param_dicts["current_spends"][channel_name])) + # st.write(st.session_state[channel_name_lower_bound]) + channel_bounds_min = st.text_input( + "Lower Bound Percentage", + key = channel_name_lower_bound, + on_change=partial(update_data_bound_min,channel_name) + ) + # st.write(st.session_state[channel_name_lower_bound]) + # if not validate_input_lb(str(channel_bounds_min)): + # st.error("Invalid input") + if not validate_input(spend_input): + st.error("Invalid input") + def calc_min_value(): + return float(st.session_state[channel_name_upper_bound]) + channel_name_current = f"{channel_name}_change" + with _columns_min[1]: + channel_name_upper_bound = f"{channel_name}_upper_bound" + if channel_name_upper_bound not in st.session_state: + st.session_state[channel_name_upper_bound] = str(100) + # st.write(float(st.session_state[channel_name_lower_bound]),float(st.session_state[channel_name_upper_bound]),) + st.number_input( + "Percent Change", + key=channel_name_current, + step=1.00,value=0.00, + on_change=partial(update_data_by_percent, channel_name), + max_value = calc_min_value(), + min_value = -1*float(st.session_state[channel_name_lower_bound]) + + ) + + channel_bounds_max = st.text_input( + "Upper Bound Percentage", + key = channel_name_upper_bound, + on_change=partial(update_data_bound_max,channel_name) + ) + # if not validate_input(channel_bounds_max): + # st.error("Invalid input") + with _columns[2]: + # spends + current_channel_spends = float( + _channel_class.modified_total_spends + * _channel_class.conversion_rate + ) + actual_channel_spends = float( + _channel_class.actual_total_spends * _channel_class.conversion_rate + ) + spends_delta = float( + _channel_class.delta_spends * _channel_class.conversion_rate + ) + st.session_state["acutual_predicted"]["Channel_name"].append( + channel_name + ) + st.session_state["acutual_predicted"]["Actual_spend"].append( + actual_channel_spends + ) + st.session_state["acutual_predicted"]["Optimized_spend"].append( + current_channel_spends + ) + st.session_state["acutual_predicted"]["Delta"].append(spends_delta) + _spend_cols = st.columns(2) + with _spend_cols[0]: + # st.write("Actual") + st.markdown(f'

Actual

{format_numbers(actual_channel_spends)}

', unsafe_allow_html=True) + # st.metric( + # label="Actual Spends", + # value=format_numbers(actual_channel_spends), + # # delta=numerize(spends_delta, 1), + # # label_visibility="collapsed", + # ) + + # st.write("Actual") + st.markdown(f'

Change

{format_numbers(spends_delta)}

', unsafe_allow_html=True) + # st.markdown(f'

{format_numbers(spends_delta)}%

', unsafe_allow_html=True) + + # st.metric( + # label="Change", + # value= format_numbers_f(spends_delta), + # delta=numerize(spends_delta, 1), + # # label_visibility="collapsed", + # ) + with _spend_cols[1]: + st.markdown(f'

Simulated

{format_numbers(current_channel_spends)}

', unsafe_allow_html=True) + st.markdown(f'

Percent

{numerize(( spends_delta/actual_channel_spends)*100,0) +"%"}

', unsafe_allow_html=True) + # st.metric( + # label="Simulated Spends", + # value=format_numbers(current_channel_spends), + # # delta=numerize(spends_delta, 1), + # # label_visibility="collapsed", + # ) + + # st.metric( + # label="Percent Change", + # value= numerize(( spends_delta/actual_channel_spends)*100,0) +"%", + # delta=numerize(spends_delta, 1), + # # label_visibility="collapsed", + # ) + + + with _columns[3]: + # sales + current_channel_sales = float(_channel_class.modified_total_sales) + actual_channel_sales = float(_channel_class.actual_total_sales) + sales_delta = float(_channel_class.delta_sales) + st.session_state["acutual_predicted"]["Old_sales"].append(actual_channel_sales) + st.session_state["acutual_predicted"]["New_sales"].append(current_channel_sales) + #st.write(actual_channel_sales) + + _prospect_cols = st.columns(2) + with _prospect_cols[0]: + # st.write("Actual") + st.markdown(f'

Actual

{format_numbers_f(actual_channel_sales)}

', unsafe_allow_html=True) + st.markdown(f'

Change

{format_numbers_f(sales_delta)}

', unsafe_allow_html=True) + + # st.metric( + # # target, + # label="Actual Prospects", + # value= format_numbers_f(actual_channel_sales), + # # delta=numerize(sales_delta, 1), + # # label_visibility="collapsed", + # ) + # st.metric( + # label="Change", + # value= format_numbers_f(_channel_class.delta_sales), + # delta=numerize(sales_delta, 1), + # # label_visibility="collapsed", + # ) + with _prospect_cols[1]: + st.markdown(f'

Simulated

{format_numbers_f(current_channel_sales)}

', unsafe_allow_html=True) + st.markdown(f'

Percent

{numerize(( _channel_class.delta_sales/actual_channel_sales)*100,0) +"%"}

', unsafe_allow_html=True) + + # st.metric( + # label="Simulated Prospects", + # value= format_numbers_f(current_channel_sales), + # # delta=numerize(sales_delta, 1), + # # label_visibility="collapsed", + # ) + + # st.metric( + # label="Percent Change", + # value= numerize((_channel_class.delta_sales/actual_channel_sales)*100,0) +"%", + # delta=numerize(sales_delta, 1), + # # label_visibility="collapsed", + # ) + + + + with _columns[4]: + + # if st.checkbox( + # label="select for optimization", + # key=f"{channel_name}_selected", + # value=False, + # # on_change=partial(select_channel_for_optimization, channel_name), + # label_visibility="collapsed", + # ): + # select_channel_for_optimization(channel_name) + + st.checkbox( + label="select for optimization", + key=f"{channel_name}_selected", + value=False, + on_change=partial(select_channel_for_optimization, channel_name), + label_visibility="collapsed", + ) + + st.markdown( + """
""", + unsafe_allow_html=True, + ) + + # Bins + col = channels_list[i] + x_actual = st.session_state["scenario"].channels[col].actual_spends + x_modified = st.session_state["scenario"].channels[col].modified_spends + # x_modified_total = 0 + # for c in channels_list: + # # st.write(c) + # # st.write(st.session_state["scenario"].channels[c].modified_spends) + # x_modified_total = x_modified_total + st.session_state["scenario"].channels[c].modified_spends.sum() + # st.write(x_modified_total) + + x_total = x_modified.sum() + power = np.ceil(np.log(x_actual.max()) / np.log(10)) - 3 + + updated_rcs_key = f"{metrics_selected}#@{panel_selected}#@{channel_name}" + + # if updated_rcs and updated_rcs_key in list(updated_rcs.keys()): + # K = updated_rcs[updated_rcs_key]["K"] + # b = updated_rcs[updated_rcs_key]["b"] + # a = updated_rcs[updated_rcs_key]["a"] + # x0 = updated_rcs[updated_rcs_key]["x0"] + # else: + # K = st.session_state["rcs"][col]["K"] + # b = st.session_state["rcs"][col]["b"] + # a = st.session_state["rcs"][col]["a"] + # x0 = st.session_state["rcs"][col]["x0"] + + # x_plot = np.linspace(0, 5 * x_actual.sum(), 200) + + # # Append current_channel_spends to the end of x_plot + # x_plot = np.append(x_plot, current_channel_spends) + + # x, y, marginal_roi = [], [], [] + # for x_p in x_plot: + # x.append(x_p * x_actual / x_actual.sum()) + + # for index in range(len(x_plot)): + # y.append(s_curve(x[index] / 10**power, K, b, a, x0)) + + # for index in range(len(x_plot)): + # marginal_roi.append( + # a * y[index] * (1 - y[index] / np.maximum(K, np.finfo(float).eps)) + # ) + + # x = ( + # np.sum(x, axis=1) + # * st.session_state["scenario"].channels[col].conversion_rate + # ) + # y = np.sum(y, axis=1) + # marginal_roi = ( + # np.average(marginal_roi, axis=1) + # / st.session_state["scenario"].channels[col].conversion_rate + # ) + + # roi = y / np.maximum(x, np.finfo(float).eps) + # # roi = (y/np.sum(y))/(x/np.sum(x)) + # # st.write(x) + # # st.write(y) + # # st.write(roi) + + # # st.write(roi[-1]) + + # roi_current, marginal_roi_current = roi[-1], marginal_roi[-1] + # x, y, roi, marginal_roi = ( + # x[:-1], + # y[:-1], + # roi[:-1], + # marginal_roi[:-1], + # ) # Drop data for current spends + + # # roi_current = + + # start_value, end_value, left_value, right_value = find_segment_value( + # x, + # roi, + # marginal_roi, + # ) + + #st.write(roi_current) + + # rgba = calculate_rgba( + # start_value, + # end_value, + # left_value, + # right_value, + # current_channel_spends, + # ) + + # # # # print(st.session_state["acutual_predicted"]) + summary_df = pd.DataFrame(st.session_state["acutual_predicted"]) + # (pd.DataFrame(st.session_state["acutual_predicted"])).to_excel("test.xlsx") + # st.dataframe(summary_df) + summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True) + # st.dataframe(summary_df) + + + summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False) + summary_df_sorted["Delta_percent"] = np.round( + ((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1) + * 100, + 2, + ) + + summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False) + 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()) + 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()) + + a = (summary_df_sorted[summary_df_sorted['Channel_name']== col]).reset_index()['new_efficiency'][0] + b = (summary_df_sorted[summary_df_sorted['Channel_name']== col]).reset_index()['old_efficiency'][0] + # st.write(a) + # # print(a) + # # print(summary_df_sorted['Actual_spend'].sum()) + # # print(summary_df_sorted['Actual_spend']) + # # print(col,summary_df_sorted) + # # print(summary_df_sorted['Old_sales']) + # # print(col, "old efficiency ", a) + with bin_placeholder: + if a> 1: + fill_color_box = "#6bbf6b" + elif a <1: + fill_color_box = "#ff6868" + else: + fill_color_box = "#ff6868" + st.markdown( + f""" +
+

Simulated Efficiency: {round(a,2)}
Actual Efficiency: {round(b,2)}

+ +
+ """, + unsafe_allow_html=True, + ) + #

Simulated Efficiency: {round(a,2)}
Actual Efficiency: {round(b,2)}

+ # + + with st.expander("See Response Curves", expanded=True): + fig = plot_response_curves(summary_df_sorted) + # st.plotly_chart(rc.response_curves(col)) + # st.plotly_chart(fig, use_container_width=True) + + summary_df = pd.DataFrame(st.session_state["acutual_predicted"]) + # st.dataframe(summary_df) + summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True) + # st.dataframe(summary_df) + + summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False) + summary_df_sorted["Delta_percent"] = np.round( + ((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1) + * 100, + 2, + ) + + + + + + + + with open("summary_df.pkl", "wb") as f: + pickle.dump(summary_df_sorted, f) + # st.dataframe(summary_df_sorted) + # ___columns=st.columns(3) + # with ___columns[2]: + # fig=summary_plot(summary_df_sorted, x='Delta_percent', y='Channel_name', title='Delta', text_column='Delta_percent') + # st.plotly_chart(fig,use_container_width=True) + # with ___columns[0]: + # fig=summary_plot(summary_df_sorted, x='Actual_spend', y='Channel_name', title='Actual Spend', text_column='Actual_spend') + # st.plotly_chart(fig,use_container_width=True) + # with ___columns[1]: + # fig=summary_plot(summary_df_sorted, x='Optimized_spend', y='Channel_name', title='Planned Spend', text_column='Optimized_spend') + # st.plotly_chart(fig,use_container_width=True) + + scenario_planner_plots() + + with st.expander ("View Forecasted spends"): + # st.write("Select Time Period") + + options = ["Next Month","Next Quarter","Next Year","Custom Time Period"] + + # # Create the radio button + forecast_btn_op = st.radio("Select Time Period", options) + + + # List of 12 months + months_start = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"] + years_start = range(2022,2025) + months_end = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"] + years_end = range(2022,2025) + + if forecast_btn_op == "Custom Time Period": + col1, col2, col3 = st.columns([1,1,0.75]) + + with col1: + from datetime import date + st.write ("Select Start Time Period") + sc1,sc2 = st.columns([1,1]) + + with sc1: + # Create a dropdown (selectbox) for months + start_date_mon = st.selectbox("Select Start Month:", months_start) + with sc2: + start_date_year = st.selectbox("Select Start Year:", years_start,index=2) + start_date1 = date(start_date_year, months_start.index(start_date_mon)+1, 1) + # - relativedelta(years=1) + # st.write(start_date1) + # default_Month = "January" + # start_date_mon = st.text_input("Select Start Month: ",value=default_Month) + + # default_Year = 2024 + # start_date_year = st.number_input("Select Start Year: ",value=default_Year) + + with col2: + st.write ("Select End Time Period") + ec1,ec2 = st.columns([1,1]) + with ec1: + end_date_mon = st.selectbox("Select End Month:", months_end,index=1) + with ec2: + end_date_year = st.selectbox("Select End Year:", years_end,index=2) + end_date1 = date(end_date_year, months_end.index(end_date_mon)+1, 1)+ relativedelta(months=1) - relativedelta(days=1) + # - relativedelta(years=1) + # st.write(end_date1) + # default_Month = "February" + # end_date_mon = st.text_input("Select End Month: ",value=default_Month) + + # default_Year = 2024 + # end_date_year = st.number_input("Select End Year: ",value=default_Year) + # end_date1 = st.date_input("Select End Date: ",value=default_date) - relativedelta(years=1) + elif forecast_btn_op == 'Next Month': + # current_date = datetime.now() + # start_date1 = current_date- relativedelta(years=1) + # end_date1 = current_date + relativedelta(months=1)- relativedelta(years=1) + start_date1,end_date1 = first_day_of_next_month(datetime.now()) + # start_date1 = start_date1- relativedelta(years=1) + # end_date1 = end_date1 - relativedelta(years=1) + elif forecast_btn_op == 'Next Quarter': + # current_date = datetime.now() + # start_date1 = current_date- relativedelta(years=1) + # end_date1 = current_date + relativedelta(months = 3)- relativedelta(years=1) + start_date1,end_date1 = first_day_of_next_quarter(datetime.now()) + # start_date1 = start_date1- relativedelta(years=1) + # end_date1 = end_date1 - relativedelta(years=1) + elif forecast_btn_op == 'Next Year': + # current_date = datetime.now() + # start_date1 = current_date- relativedelta(years=1) + # end_date1 = current_date + relativedelta(months = 12)- relativedelta(years=1) + start_date1,end_date1 = first_day_of_next_year(datetime.now()) + # start_date1 = start_date1- relativedelta(years=1) + # end_date1 = end_date1 - relativedelta(years=1) + if st.button('Generate Forecasts'): + st.write(f"Forecasted Spends Time Period : {start_date1.strftime('%m-%d-%Y')} to {end_date1.strftime('%m-%d-%Y')}") + if end_date1 < start_date1 : + st.error("End date cannot be less than start date") + forecasted_table_df2 = pd.DataFrame() + try: + + st.write("Forecasted Spends wrt. Channels ") + output_df1, output_df2 = sf.scenario_spend_forecasting(summary_df_sorted,start_date1- relativedelta(years=1),end_date1- relativedelta(years=1)) + forecasted_table_df = output_df1.copy() + # forecasted_table_df.iloc[:2] = forecasted_table_df.iloc[:2].applymap(lambda x: "{:,.0f}".format(x)) + # forecasted_table_df.iloc[-1] = forecasted_table_df.iloc[-1].apply(lambda x: "{:.1f}%".format(x)) + st.dataframe(forecasted_table_df) + + st.write("Monthly Breakdown Of Forecasted Spends wrt. Channels ") + # forecasted_table_df2 = output_df2.applymap(lambda x: "{:,.0f}".format(x)) + st.dataframe(output_df2) + + st.subheader("Download Report") + report_name = st.text_input( + "Report name", + key="report_input", + placeholder="Report name", + label_visibility="collapsed", + ) + st.download_button( + "Download Report", + data = save_report_forecast(output_df1,output_df2), + file_name = report_name+".xlsx", + mime="application/vnd.ms-excel", + # on_click=lambda: save_report_forecast(forecasted_table_df,report_name), + disabled=len(st.session_state["report_input"]) == 0,#use_container_width=True + ) + + except: + st.warning("Please make sure the base data is updated") + + + + + + + + + + + + + # filename = st.text_input("Save Report: ",placeholder="Report name") + # if st.button("Download Report",disabled= (filename != "Report name")): + # excel_file_path = filename+ '.xlsx' + # forecasted_table_df.to_excel(excel_file_path, index=False) + # message_container = st.empty() + + + # with message_container: + # st.write(f'
{"Report Saved!"}
', unsafe_allow_html=True) + # time.sleep(0.5) + # st.empty() + + # on_click=lambda: save_scenario(scenario_name), + # disabled=len(st.session_state["scenario_input"]) == 0,#use_container_width=True + + _columns = st.columns(2) + # with _columns[0]: + st.subheader("Save Scenario") + scenario_name = st.text_input( + "Scenario name", + key="scenario_input", + placeholder="Scenario name", + label_visibility="collapsed", + ) + st.button( + "Save", + on_click=lambda: save_scenario(scenario_name), + disabled=len(st.session_state["scenario_input"]) == 0,#use_container_width=True + + ) + # def prepare_download_func(): + + # fig1,fig2,fig3 = scenario_planner_plots() + + # ppt_file = save_ppt_file(summary_df_sorted,fig1,fig2,fig3) + + if st.button("Prepare Analysis Download"): + fig1,fig2,fig3 = scenario_planner_plots2() + ppt_file = save_ppt_file(summary_df_sorted,fig1,fig2,fig3) + # Add a download button + try: + # ppt_file = prepare_download_func() + st.download_button( + label="Download Response Curves And Optimised Spends Overview", + data=ppt_file, + file_name="MMM_Scenario_Planner_Presentation.pptx", + mime="application/vnd.openxmlformats-officedocument.presentationml.presentation", + ) + except: + st.write("") + # ppt_file = save_ppt_file() + # # Add a download button + # st.download_button( + # label="Download Analysis", + # data=ppt_file, + # file_name="MMM_Model_Quality_Presentation.pptx", + # mime="application/vnd.openxmlformats-officedocument.presentationml.presentation" + # ) + + + + + + +elif auth_status == False: + st.error("Username/Password is incorrect") + +if auth_status != True: + try: + username_forgot_pw, email_forgot_password, random_password = ( + authenticator.forgot_password("Forgot password") + ) + if username_forgot_pw: + st.session_state["config"]["credentials"]["usernames"][username_forgot_pw][ + "password" + ] = stauth.Hasher([random_password]).generate()[0] + send_email(email_forgot_password, random_password) + st.success("New password sent securely") + # Random password to be transferred to user securely + elif username_forgot_pw == False: + st.error("Username not found") + except Exception as e: + st.error(e) + + \ No newline at end of file