|
import pandas as pd |
|
import plotly.express as px |
|
import streamlit as st |
|
|
|
from process_kpi.process_gsm_capacity import analyze_gsm_data |
|
from utils.convert_to_excel import ( |
|
convert_gsm_dfs, |
|
save_dataframe, |
|
) |
|
from utils.kpi_analysis_utils import GsmCapacity |
|
|
|
st.title(" 📊 GSM Capacity Analysis") |
|
doc_col, image_col = st.columns(2) |
|
|
|
with doc_col: |
|
st.write( |
|
""" |
|
The report should be run with a minimum of 3 days of data. |
|
- Dump file required |
|
- Daily Cell level KPI report in CSV format |
|
- BH Cell level KPI report in CSV format |
|
""" |
|
) |
|
|
|
with image_col: |
|
st.image("./assets/gsm_capacity.png", width=250) |
|
|
|
file1, file2, file3 = st.columns(3) |
|
|
|
with file1: |
|
uploaded_dump = st.file_uploader("Upload Dump file in xlsb format", type="xlsb") |
|
with file2: |
|
uploaded_daily_report = st.file_uploader( |
|
"Upload Daily Report in CSV format", type="csv" |
|
) |
|
with file3: |
|
uploaded_bh_report = st.file_uploader( |
|
"Upload Busy Hour Report in CSV format", type="csv" |
|
) |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
threshold_col1, threshold_col2 = st.columns(2) |
|
threshold_col3, threshold_col4 = st.columns(2) |
|
max_traffic_threshold_col1, operational_neighbours_distance_col1 = st.columns(2) |
|
|
|
|
|
if ( |
|
uploaded_dump is not None |
|
and uploaded_daily_report is not None |
|
and uploaded_bh_report is not None |
|
): |
|
|
|
with col1: |
|
number_of_kpi_days = st.number_input( |
|
"Number of days for analysis", |
|
min_value=3, |
|
max_value=30, |
|
value=7, |
|
) |
|
with col2: |
|
number_of_threshold_days = st.number_input( |
|
"Number of days for threshold", |
|
min_value=1, |
|
max_value=30, |
|
value=3, |
|
) |
|
|
|
with threshold_col1: |
|
availability_threshold = st.number_input( |
|
"Availability Threshold", min_value=1, max_value=100, value=95 |
|
) |
|
with threshold_col2: |
|
tch_abis_fails_threshold = st.number_input( |
|
"TCH ABIS Fails Threshold", min_value=0, value=10 |
|
) |
|
with threshold_col3: |
|
sdcch_blocking_threshold = st.number_input( |
|
"SDDCH Blocking Threshold", min_value=0.1, value=0.5 |
|
) |
|
with threshold_col4: |
|
tch_blocking_threshold = st.number_input( |
|
"TCH Blocking Threshold", min_value=0.1, value=0.5 |
|
) |
|
with max_traffic_threshold_col1: |
|
max_traffic_threshold = st.number_input( |
|
"TCH Utilization Max Traffic Threshold", min_value=0, value=90 |
|
) |
|
with operational_neighbours_distance_col1: |
|
operational_neighbours_distance = st.number_input( |
|
"Operational Neighbours Distance", min_value=0, value=1 |
|
) |
|
|
|
if st.button("Analyze Data", type="primary"): |
|
dfs = analyze_gsm_data( |
|
dump_path=uploaded_dump, |
|
daily_report_path=uploaded_daily_report, |
|
bh_report_path=uploaded_bh_report, |
|
number_of_kpi_days=number_of_kpi_days, |
|
number_of_threshold_days=number_of_threshold_days, |
|
availability_threshold=availability_threshold, |
|
tch_abis_fails_threshold=tch_abis_fails_threshold, |
|
sdcch_blocking_threshold=sdcch_blocking_threshold, |
|
tch_blocking_threshold=tch_blocking_threshold, |
|
max_traffic_threshold=max_traffic_threshold, |
|
operational_neighbours_distance=operational_neighbours_distance, |
|
) |
|
|
|
if dfs is not None: |
|
gsm_analysis_df: pd.DataFrame = dfs[0] |
|
bh_kpi_df: pd.DataFrame = dfs[1] |
|
daily_kpi_df: pd.DataFrame = dfs[2] |
|
distance_df: pd.DataFrame = dfs[3] |
|
GsmCapacity.final_results = convert_gsm_dfs( |
|
[gsm_analysis_df, distance_df, bh_kpi_df, daily_kpi_df], |
|
["GSM_Analysis", "Distance", "BH_KPI_Analysis", "Daily_KPI_Analysis"], |
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
if GsmCapacity.final_results is not None: |
|
st.download_button( |
|
on_click="ignore", |
|
type="primary", |
|
label="Download the Analysis Report", |
|
data=GsmCapacity.final_results, |
|
file_name="GSM_Analysis_Report.xlsx", |
|
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
|
) |
|
|
|
st.write(daily_kpi_df) |
|
|
|
|
|
final_comments_df = ( |
|
gsm_analysis_df.groupby("Final comment").size().reset_index(name="count") |
|
) |
|
fig = px.bar( |
|
final_comments_df, |
|
x="Final comment", |
|
y="count", |
|
title="Final comment distribution", |
|
) |
|
fig.update_layout(height=1000) |
|
fig.update_traces(texttemplate="%{value}", textposition="outside") |
|
st.plotly_chart(fig, use_container_width=True) |
|
st.write(final_comments_df) |
|
|
|
|
|
final_comments_summary_df = ( |
|
gsm_analysis_df.groupby("Final comment summary") |
|
.size() |
|
.reset_index(name="count") |
|
) |
|
|
|
st.markdown("***") |
|
st.markdown(":blue[**Final comment summary distribution**]") |
|
final_comments_summary_col1, final_comments_summary_col2 = st.columns((1, 3)) |
|
with final_comments_summary_col1: |
|
st.write(final_comments_summary_df) |
|
with final_comments_summary_col2: |
|
fig = px.pie( |
|
final_comments_summary_df, |
|
names="Final comment summary", |
|
values="count", |
|
hover_name="Final comment summary", |
|
hover_data=["count"], |
|
title="GSM Analysis comment distribution", |
|
) |
|
fig.update_layout(height=800) |
|
fig.update_traces( |
|
texttemplate="%{label}: %{value}", |
|
textfont_size=15, |
|
textposition="outside", |
|
) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
st.markdown("***") |
|
st.markdown(":blue[**BH Congestion status distribution**]") |
|
bh_congestion_status_df = ( |
|
gsm_analysis_df.groupby("BH Congestion status") |
|
.size() |
|
.reset_index(name="count") |
|
) |
|
|
|
bh_congestion_status_df["BH Congestion status"] = bh_congestion_status_df[ |
|
"BH Congestion status" |
|
].replace("", "No Congestion") |
|
|
|
bh_congestion_status_df["BH Congestion status"] = bh_congestion_status_df[ |
|
"BH Congestion status" |
|
].replace("nan, nan", "No KPI") |
|
|
|
bh_congestion_status_col1, bh_congestion_status_col2 = st.columns((2, 1)) |
|
with bh_congestion_status_col2: |
|
st.write(bh_congestion_status_df) |
|
with bh_congestion_status_col1: |
|
fig = px.pie( |
|
bh_congestion_status_df, |
|
names="BH Congestion status", |
|
values="count", |
|
hover_name="BH Congestion status", |
|
hover_data=["count"], |
|
title="BH Congestion status distribution", |
|
) |
|
fig.update_layout(height=800) |
|
fig.update_traces( |
|
texttemplate="%{label}: %{value}", |
|
textfont_size=15, |
|
textposition="outside", |
|
) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
st.markdown("***") |
|
st.markdown(":blue[**Operational comments distribution**]") |
|
operational_comments_df = ( |
|
gsm_analysis_df.groupby("operational_comment") |
|
.size() |
|
.reset_index(name="count") |
|
) |
|
operational_comments_col1, operational_comments_col2 = st.columns((1, 2)) |
|
with operational_comments_col1: |
|
st.write(operational_comments_df) |
|
with operational_comments_col2: |
|
fig = px.pie( |
|
operational_comments_df, |
|
names="operational_comment", |
|
values="count", |
|
hover_name="operational_comment", |
|
hover_data=["count"], |
|
title="Operational comments distribution", |
|
) |
|
fig.update_layout(height=600) |
|
fig.update_traces( |
|
texttemplate="%{label}: %{value}", |
|
textfont_size=15, |
|
textposition="outside", |
|
) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
st.markdown("***") |
|
st.markdown(":blue[**Max TCH Call Blocking BH distribution**]") |
|
|
|
|
|
map_df = gsm_analysis_df[ |
|
["code", "max_tch_call_blocking_bh", "Latitude", "Longitude"] |
|
].dropna(subset=["code", "max_tch_call_blocking_bh", "Latitude", "Longitude"]) |
|
|
|
|
|
map_df = ( |
|
map_df.groupby("code") |
|
.agg( |
|
{ |
|
"max_tch_call_blocking_bh": "max", |
|
"Latitude": "first", |
|
"Longitude": "first", |
|
} |
|
) |
|
.reset_index() |
|
) |
|
|
|
|
|
map_df["color"] = map_df["max_tch_call_blocking_bh"].apply( |
|
lambda x: ( |
|
"Above Threshold" if x > tch_blocking_threshold else "Below Threshold" |
|
) |
|
) |
|
|
|
|
|
min_bubble_size = 5 |
|
max_bubble_size = 30 |
|
|
|
|
|
size_scale = max_bubble_size / map_df["max_tch_call_blocking_bh"].max() |
|
map_df["scaled_size"] = map_df["max_tch_call_blocking_bh"].apply( |
|
lambda x: max(x * size_scale, min_bubble_size) |
|
) |
|
|
|
fig = px.scatter_map( |
|
map_df, |
|
lat="Latitude", |
|
lon="Longitude", |
|
color="color", |
|
color_discrete_map={"Above Threshold": "red", "Below Threshold": "green"}, |
|
size="scaled_size", |
|
size_max=max_bubble_size, |
|
hover_data={ |
|
"code": True, |
|
"max_tch_call_blocking_bh": ":.2f", |
|
"scaled_size": False, |
|
}, |
|
hover_name="code", |
|
zoom=10, |
|
height=600, |
|
title="Max TCH Call Blocking BH distribution", |
|
) |
|
|
|
|
|
fig.update_traces( |
|
text=map_df["code"], |
|
textposition="middle center", |
|
textfont=dict(size=18, color="black"), |
|
|
|
|
|
) |
|
|
|
|
|
fig.update_layout( |
|
mapbox_style="open-street-map", |
|
showlegend=True, |
|
margin=dict(l=10, r=10, t=40, b=10), |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|