|
|
|
import streamlit as st |
|
|
|
st.set_page_config( |
|
page_title="Saved Scenarios", |
|
page_icon="⚖️", |
|
layout="wide", |
|
initial_sidebar_state="collapsed", |
|
) |
|
|
|
import io |
|
import os |
|
import json |
|
import pickle |
|
import sqlite3 |
|
import zipfile |
|
import numpy as np |
|
import pandas as pd |
|
from classes import numerize |
|
from openpyxl import Workbook |
|
from collections import OrderedDict |
|
from utilities import ( |
|
project_selection, |
|
initialize_data, |
|
set_header, |
|
load_local_css, |
|
name_formating, |
|
) |
|
|
|
|
|
load_local_css("styles.css") |
|
set_header() |
|
|
|
|
|
if "project_dct" not in st.session_state: |
|
|
|
project_selection() |
|
st.stop() |
|
|
|
database_file = r"DB\User.db" |
|
|
|
conn = sqlite3.connect( |
|
database_file, check_same_thread=False |
|
) |
|
c = conn.cursor() |
|
|
|
|
|
col_project_data = st.columns([2, 1]) |
|
with col_project_data[0]: |
|
st.markdown(f"**Welcome {st.session_state['username']}**") |
|
with col_project_data[1]: |
|
st.markdown(f"**Current Project: {st.session_state['project_name']}**") |
|
|
|
|
|
st.title("Saved Scenarios") |
|
scenarios_name_placeholder = st.empty() |
|
|
|
|
|
|
|
def get_saved_scenarios_dict(): |
|
|
|
saved_scenarios_dict_path = os.path.join( |
|
st.session_state["project_path"], "saved_scenarios.pkl" |
|
) |
|
|
|
|
|
if os.path.exists(saved_scenarios_dict_path): |
|
with open(saved_scenarios_dict_path, "rb") as f: |
|
saved_scenarios_dict = pickle.load(f) |
|
else: |
|
saved_scenarios_dict = OrderedDict() |
|
|
|
return saved_scenarios_dict |
|
|
|
|
|
|
|
def format_value(value): |
|
return round(value, 4) if value < 1 else round(value, 1) |
|
|
|
|
|
|
|
def convert_to_serializable(obj): |
|
if isinstance(obj, np.ndarray): |
|
return obj.tolist() |
|
elif isinstance(obj, dict): |
|
return {key: convert_to_serializable(value) for key, value in obj.items()} |
|
elif isinstance(obj, list): |
|
return [convert_to_serializable(element) for element in obj] |
|
elif isinstance(obj, (int, float, str, bool, type(None))): |
|
return obj |
|
else: |
|
|
|
return str(obj) |
|
|
|
|
|
|
|
@st.cache_data(show_spinner=False) |
|
def download_as_zip( |
|
df, |
|
scenario_data, |
|
excel_name="optimization_results.xlsx", |
|
json_name="scenario_params.json", |
|
): |
|
|
|
buffer = io.BytesIO() |
|
|
|
|
|
with zipfile.ZipFile(buffer, "w") as zip_file: |
|
|
|
excel_buffer = io.BytesIO() |
|
workbook = Workbook() |
|
sheet = workbook.active |
|
sheet.title = "Results" |
|
|
|
|
|
for col_num, column_title in enumerate(df.columns, 1): |
|
sheet.cell(row=1, column=col_num, value=column_title) |
|
|
|
|
|
for row_num, row_data in enumerate(df.values, 2): |
|
for col_num, cell_value in enumerate(row_data, 1): |
|
sheet.cell(row=row_num, column=col_num, value=cell_value) |
|
|
|
|
|
workbook.save(excel_buffer) |
|
excel_buffer.seek(0) |
|
zip_file.writestr(excel_name, excel_buffer.getvalue()) |
|
|
|
|
|
json_buffer = io.BytesIO() |
|
json_buffer.write( |
|
json.dumps(convert_to_serializable(scenario_data), indent=4).encode("utf-8") |
|
) |
|
json_buffer.seek(0) |
|
zip_file.writestr(json_name, json_buffer.getvalue()) |
|
|
|
buffer.seek(0) |
|
|
|
return buffer |
|
|
|
|
|
|
|
def delete_selected_scenarios(selected_scenario): |
|
|
|
saved_scenarios_dict_path = os.path.join( |
|
st.session_state["project_path"], "saved_scenarios.pkl" |
|
) |
|
|
|
|
|
if os.path.exists(saved_scenarios_dict_path): |
|
with open(saved_scenarios_dict_path, "rb") as f: |
|
saved_scenarios_dict = pickle.load(f) |
|
else: |
|
saved_scenarios_dict = OrderedDict() |
|
|
|
try: |
|
|
|
del saved_scenarios_dict[selected_scenario] |
|
|
|
|
|
with open(saved_scenarios_dict_path, "wb") as f: |
|
pickle.dump(saved_scenarios_dict, f) |
|
|
|
except KeyError: |
|
|
|
pass |
|
|
|
|
|
|
|
saved_scenarios_dict = get_saved_scenarios_dict() |
|
scenarios_list = list(saved_scenarios_dict.keys()) |
|
|
|
|
|
if len(scenarios_list) == 0: |
|
|
|
st.warning("No scenarios saved. Please save a scenario to load.", icon="⚠️") |
|
st.stop() |
|
|
|
|
|
selected_scenario = st.selectbox( |
|
"Pick a Scenario", sorted(scenarios_list), key="selected_scenario" |
|
) |
|
selected_scenario_data = saved_scenarios_dict[selected_scenario] |
|
|
|
|
|
metrics_name = selected_scenario_data["metrics_selected"] |
|
panel_name = selected_scenario_data["panel_selected"] |
|
optimization_name = selected_scenario_data["optimization"] |
|
|
|
|
|
scenarios_name_placeholder.markdown( |
|
f"**Metric**: {name_formating(metrics_name)}; **Panel**: {name_formating(panel_name)}; **Optimization**: {name_formating(optimization_name)}" |
|
) |
|
|
|
|
|
download_col, delete_col = st.columns(2) |
|
|
|
|
|
channels_list = list(selected_scenario_data["channels"].keys()) |
|
|
|
|
|
channels_data = [] |
|
|
|
|
|
for channel in channels_list: |
|
channel_conversion_rate = selected_scenario_data["channels"][channel][ |
|
"conversion_rate" |
|
] |
|
channel_actual_spends = ( |
|
selected_scenario_data["channels"][channel]["actual_total_spends"] |
|
* channel_conversion_rate |
|
) |
|
channel_optimized_spends = ( |
|
selected_scenario_data["channels"][channel]["modified_total_spends"] |
|
* channel_conversion_rate |
|
) |
|
|
|
channel_actual_metrics = selected_scenario_data["channels"][channel][ |
|
"actual_total_sales" |
|
] |
|
channel_optimized_metrics = selected_scenario_data["channels"][channel][ |
|
"modified_total_sales" |
|
] |
|
|
|
channel_roi_mroi_data = selected_scenario_data["channel_roi_mroi"][channel] |
|
|
|
|
|
actual_roi = channel_roi_mroi_data["actual_roi"] |
|
optimized_roi = channel_roi_mroi_data["optimized_roi"] |
|
actual_mroi = channel_roi_mroi_data["actual_mroi"] |
|
optimized_mroi = channel_roi_mroi_data["optimized_mroi"] |
|
|
|
|
|
spends_per_metrics_actual = channel_actual_spends / channel_actual_metrics |
|
spends_per_metrics_optimized = channel_optimized_spends / channel_optimized_metrics |
|
|
|
|
|
channels_data.append( |
|
{ |
|
"Channel Name": channel, |
|
"Spends Actual": numerize(channel_actual_spends), |
|
"Spends Optimized": numerize(channel_optimized_spends), |
|
f"{name_formating(metrics_name)} Actual": numerize(channel_actual_metrics), |
|
f"{name_formating(metrics_name)} Optimized": numerize( |
|
channel_optimized_metrics |
|
), |
|
"ROI Actual": format_value(actual_roi), |
|
"ROI Optimized": format_value(optimized_roi), |
|
"MROI Actual": format_value(actual_mroi), |
|
"MROI Optimized": format_value(optimized_mroi), |
|
f"Spends per {name_formating(metrics_name)} Actual": round( |
|
spends_per_metrics_actual, 2 |
|
), |
|
f"Spends per {name_formating(metrics_name)} Optimized": round( |
|
spends_per_metrics_optimized, 2 |
|
), |
|
} |
|
) |
|
|
|
|
|
df = pd.DataFrame(channels_data) |
|
|
|
|
|
st.dataframe(df, hide_index=True) |
|
|
|
|
|
buffer = download_as_zip( |
|
df, |
|
selected_scenario_data, |
|
excel_name="optimization_results.xlsx", |
|
json_name="scenario_params.json", |
|
) |
|
|
|
|
|
download_col.download_button( |
|
label="Download", |
|
data=buffer, |
|
file_name=f"{selected_scenario}_scenario_data.zip", |
|
mime="application/zip", |
|
use_container_width=True, |
|
) |
|
|
|
|
|
delete_col.button( |
|
"Delete", |
|
use_container_width=True, |
|
on_click=delete_selected_scenarios, |
|
args=(selected_scenario,), |
|
) |
|
|