add KML generation options
Browse files- Changelog.md +5 -0
- README.md +1 -0
- app.py +1 -1
- apps/database_page.py +62 -5
- queries/process_gsm.py +34 -0
- queries/process_invunit.py +5 -0
- queries/process_lte.py +43 -0
- queries/process_wcdma.py +38 -0
- requirements.txt +0 -0
- test.py +1 -1
- utils/kml_creator.py +79 -0
- utils/utils_vars.py +21 -0
Changelog.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
| 1 |
|
| 2 |
# CHANGELOGS
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
## [0.2.3] - 2024-09-30
|
| 5 |
|
| 6 |
- Moving physical database to github storage repository
|
|
|
|
| 1 |
|
| 2 |
# CHANGELOGS
|
| 3 |
|
| 4 |
+
## [0.2.5] - 2024-09-30
|
| 5 |
+
|
| 6 |
+
- Add option to download KML file For 2G, 3G, and LTE
|
| 7 |
+
- Fix bug when LTE name is empty
|
| 8 |
+
|
| 9 |
## [0.2.3] - 2024-09-30
|
| 10 |
|
| 11 |
- Moving physical database to github storage repository
|
README.md
CHANGED
|
@@ -44,6 +44,7 @@ You can access the hosted version of the app at [https://davmelchi-db-query.hf.s
|
|
| 44 |
- [x] Add MRBTS with code
|
| 45 |
- [x] Check TCH from MAL sheet
|
| 46 |
- [x] Add Analitic dashboards for each database (Count of NE)
|
|
|
|
| 47 |
- [ ] Improve Dashboard
|
| 48 |
- [ ] Add the ability to select columns
|
| 49 |
- [ ] Error handling
|
|
|
|
| 44 |
- [x] Add MRBTS with code
|
| 45 |
- [x] Check TCH from MAL sheet
|
| 46 |
- [x] Add Analitic dashboards for each database (Count of NE)
|
| 47 |
+
- [x] Add kml generation
|
| 48 |
- [ ] Improve Dashboard
|
| 49 |
- [ ] Add the ability to select columns
|
| 50 |
- [ ] Error handling
|
app.py
CHANGED
|
@@ -6,7 +6,7 @@ st.set_page_config(
|
|
| 6 |
layout="wide",
|
| 7 |
initial_sidebar_state="expanded",
|
| 8 |
menu_items={
|
| 9 |
-
"About": "**📡 NPO DB Query v0.2.
|
| 10 |
},
|
| 11 |
)
|
| 12 |
|
|
|
|
| 6 |
layout="wide",
|
| 7 |
initial_sidebar_state="expanded",
|
| 8 |
menu_items={
|
| 9 |
+
"About": "**📡 NPO DB Query v0.2.5**",
|
| 10 |
},
|
| 11 |
)
|
| 12 |
|
apps/database_page.py
CHANGED
|
@@ -6,16 +6,16 @@ from st_aggrid import AgGrid, ColumnsAutoSizeMode
|
|
| 6 |
|
| 7 |
from apps.dump_analysis import dump_analysis_space
|
| 8 |
from queries.process_all_db import process_all_tech_db, process_all_tech_db_with_stats
|
| 9 |
-
from queries.process_gsm import process_gsm_data_to_excel
|
| 10 |
from queries.process_invunit import process_invunit_data_to_excel
|
| 11 |
-
from queries.process_lte import process_lte_data_to_excel
|
| 12 |
|
| 13 |
# from queries.process_mal import process_mal_data_to_excel
|
| 14 |
from queries.process_mrbts import process_mrbts_data_to_excel
|
| 15 |
from queries.process_neighbors import process_neighbors_data_to_excel
|
| 16 |
|
| 17 |
# from queries.process_trx import process_trx_with_bts_name_data_to_excel
|
| 18 |
-
from queries.process_wcdma import process_wcdma_data_to_excel
|
| 19 |
from utils.check_sheet_exist import DumpType, Technology, execute_checks_sheets_exist
|
| 20 |
from utils.utils_vars import GsmAnalysisData, UtilsVars, WcdmaAnalysisData
|
| 21 |
|
|
@@ -67,6 +67,37 @@ def download_button(database_type):
|
|
| 67 |
)
|
| 68 |
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
def execute_process_all_tech_db(uploaded_file):
|
| 71 |
if uploaded_file is not None:
|
| 72 |
start_time = time.time()
|
|
@@ -94,8 +125,8 @@ def execute_process_all_tech_db_with_stats(uploaded_file: str):
|
|
| 94 |
download_button("All")
|
| 95 |
|
| 96 |
|
| 97 |
-
col1, col2, col3, col4 = st.columns(
|
| 98 |
-
|
| 99 |
if uploaded_file is not None:
|
| 100 |
# UtilsVars.file_path = uploaded_file
|
| 101 |
|
|
@@ -183,6 +214,32 @@ if uploaded_file is not None:
|
|
| 183 |
process_neighbors_data_to_excel, "NEI"
|
| 184 |
),
|
| 185 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
|
| 187 |
except Exception as e:
|
| 188 |
st.error(f"Error: {e}")
|
|
|
|
| 6 |
|
| 7 |
from apps.dump_analysis import dump_analysis_space
|
| 8 |
from queries.process_all_db import process_all_tech_db, process_all_tech_db_with_stats
|
| 9 |
+
from queries.process_gsm import process_gsm_data_to_excel, process_gsm_data_to_kml
|
| 10 |
from queries.process_invunit import process_invunit_data_to_excel
|
| 11 |
+
from queries.process_lte import process_lte_data_to_excel, process_lte_data_to_kml
|
| 12 |
|
| 13 |
# from queries.process_mal import process_mal_data_to_excel
|
| 14 |
from queries.process_mrbts import process_mrbts_data_to_excel
|
| 15 |
from queries.process_neighbors import process_neighbors_data_to_excel
|
| 16 |
|
| 17 |
# from queries.process_trx import process_trx_with_bts_name_data_to_excel
|
| 18 |
+
from queries.process_wcdma import process_wcdma_data_to_excel, process_wcdma_data_to_kml
|
| 19 |
from utils.check_sheet_exist import DumpType, Technology, execute_checks_sheets_exist
|
| 20 |
from utils.utils_vars import GsmAnalysisData, UtilsVars, WcdmaAnalysisData
|
| 21 |
|
|
|
|
| 67 |
)
|
| 68 |
|
| 69 |
|
| 70 |
+
def process_kml_database(process_func, database_type):
|
| 71 |
+
if uploaded_file is not None:
|
| 72 |
+
start_time = time.time()
|
| 73 |
+
process_func(uploaded_file)
|
| 74 |
+
execution_time = time.time() - start_time
|
| 75 |
+
st.write(
|
| 76 |
+
f"{database_type} database is generated. Execution time: {execution_time:.2f} seconds"
|
| 77 |
+
)
|
| 78 |
+
kml_download_button(database_type)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
@st.fragment()
|
| 82 |
+
def kml_download_button(database_type):
|
| 83 |
+
if database_type == "2G":
|
| 84 |
+
data = UtilsVars.gsm_kml_file
|
| 85 |
+
file_name = f"2G kml_{datetime.now()}.kml"
|
| 86 |
+
elif database_type == "3G":
|
| 87 |
+
data = UtilsVars.wcdma_kml_file
|
| 88 |
+
file_name = f"3G kml_{datetime.now()}.kml"
|
| 89 |
+
elif database_type == "LTE":
|
| 90 |
+
data = UtilsVars.lte_kml_file
|
| 91 |
+
file_name = f"LTE kml_{datetime.now()}.kml"
|
| 92 |
+
st.download_button(
|
| 93 |
+
type="primary",
|
| 94 |
+
label=f"Download {database_type} KML File",
|
| 95 |
+
data=data,
|
| 96 |
+
file_name=file_name,
|
| 97 |
+
mime="application/vnd.google-earth.kml+xml",
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
def execute_process_all_tech_db(uploaded_file):
|
| 102 |
if uploaded_file is not None:
|
| 103 |
start_time = time.time()
|
|
|
|
| 125 |
download_button("All")
|
| 126 |
|
| 127 |
|
| 128 |
+
col1, col2, col3, col4, col5 = st.columns(5)
|
| 129 |
+
col6, col7, col8, col9, col10 = st.columns(5)
|
| 130 |
if uploaded_file is not None:
|
| 131 |
# UtilsVars.file_path = uploaded_file
|
| 132 |
|
|
|
|
| 214 |
process_neighbors_data_to_excel, "NEI"
|
| 215 |
),
|
| 216 |
)
|
| 217 |
+
if Technology.gsm == True:
|
| 218 |
+
with col8:
|
| 219 |
+
st.button(
|
| 220 |
+
"Generate 2G KML",
|
| 221 |
+
on_click=lambda: process_kml_database(
|
| 222 |
+
process_gsm_data_to_kml, "2G"
|
| 223 |
+
),
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
if Technology.wcdma == True:
|
| 227 |
+
with col9:
|
| 228 |
+
st.button(
|
| 229 |
+
"Generate 3G KML",
|
| 230 |
+
on_click=lambda: process_kml_database(
|
| 231 |
+
process_wcdma_data_to_kml, "3G"
|
| 232 |
+
),
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
if Technology.lte == True:
|
| 236 |
+
with col10:
|
| 237 |
+
st.button(
|
| 238 |
+
"Generate LTE KML",
|
| 239 |
+
on_click=lambda: process_kml_database(
|
| 240 |
+
process_lte_data_to_kml, "LTE"
|
| 241 |
+
),
|
| 242 |
+
)
|
| 243 |
|
| 244 |
except Exception as e:
|
| 245 |
st.error(f"Error: {e}")
|
queries/process_gsm.py
CHANGED
|
@@ -4,6 +4,7 @@ from queries.process_mal import process_mal_data, process_mal_with_bts_name
|
|
| 4 |
from queries.process_trx import process_trx_data, process_trx_with_bts_name
|
| 5 |
from utils.config_band import config_band
|
| 6 |
from utils.convert_to_excel import convert_dfs, save_dataframe
|
|
|
|
| 7 |
from utils.utils_vars import GsmAnalysisData, UtilsVars, get_physical_db
|
| 8 |
|
| 9 |
BTS_COLUMNS = [
|
|
@@ -56,6 +57,23 @@ BCF_COLUMNS = [
|
|
| 56 |
"site_name",
|
| 57 |
]
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
def compare_trx_tch_versus_mal(tch1, tch2):
|
| 61 |
# Split the strings by commas, convert to sets, and compare
|
|
@@ -185,6 +203,22 @@ def process_gsm_data_to_excel(file_path: str):
|
|
| 185 |
UtilsVars.final_gsm_database = convert_dfs(gsm_dfs, ["GSM", "MAL", "TRX"])
|
| 186 |
|
| 187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
#############################GSM ANALYSIS#################################
|
| 189 |
|
| 190 |
|
|
|
|
| 4 |
from queries.process_trx import process_trx_data, process_trx_with_bts_name
|
| 5 |
from utils.config_band import config_band
|
| 6 |
from utils.convert_to_excel import convert_dfs, save_dataframe
|
| 7 |
+
from utils.kml_creator import generate_kml_from_df
|
| 8 |
from utils.utils_vars import GsmAnalysisData, UtilsVars, get_physical_db
|
| 9 |
|
| 10 |
BTS_COLUMNS = [
|
|
|
|
| 57 |
"site_name",
|
| 58 |
]
|
| 59 |
|
| 60 |
+
GSM_KML_COLUMNS = [
|
| 61 |
+
"code",
|
| 62 |
+
"name",
|
| 63 |
+
"Longitude",
|
| 64 |
+
"Latitude",
|
| 65 |
+
"Azimut",
|
| 66 |
+
"Hauteur",
|
| 67 |
+
"BSIC",
|
| 68 |
+
"cellId",
|
| 69 |
+
"locationAreaIdLAC",
|
| 70 |
+
"band",
|
| 71 |
+
"BCCH",
|
| 72 |
+
"TRX_TCH",
|
| 73 |
+
"number_trx_per_cell",
|
| 74 |
+
"number_trx_per_site",
|
| 75 |
+
]
|
| 76 |
+
|
| 77 |
|
| 78 |
def compare_trx_tch_versus_mal(tch1, tch2):
|
| 79 |
# Split the strings by commas, convert to sets, and compare
|
|
|
|
| 203 |
UtilsVars.final_gsm_database = convert_dfs(gsm_dfs, ["GSM", "MAL", "TRX"])
|
| 204 |
|
| 205 |
|
| 206 |
+
############################# KML CREATION #################################
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def process_gsm_data_to_kml(file_path: str):
|
| 210 |
+
gsm_kml_df = process_gsm_data(file_path)
|
| 211 |
+
gsm_kml_df = gsm_kml_df[GSM_KML_COLUMNS]
|
| 212 |
+
# Add colors column base on "band" column
|
| 213 |
+
gsm_kml_df["color"] = gsm_kml_df["band"].map(UtilsVars.color_mapping)
|
| 214 |
+
# Add size column base on "band" column
|
| 215 |
+
gsm_kml_df["size"] = gsm_kml_df["band"].map(UtilsVars.size_mapping)
|
| 216 |
+
# Remove empty rows
|
| 217 |
+
gsm_kml_df = gsm_kml_df.dropna(subset=["Longitude", "Latitude", "Azimut"])
|
| 218 |
+
# Generate kml
|
| 219 |
+
UtilsVars.gsm_kml_file = generate_kml_from_df(gsm_kml_df)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
#############################GSM ANALYSIS#################################
|
| 223 |
|
| 224 |
|
queries/process_invunit.py
CHANGED
|
@@ -76,6 +76,11 @@ def process_invunit_data(file_path: str) -> pd.DataFrame:
|
|
| 76 |
df_invunit = create_invunit_summary(df_invunit)
|
| 77 |
df_invunit["CODE"] = df_invunit["MRBTS"].apply(extract_code_from_mrbts)
|
| 78 |
df_invunit = df_invunit[["MRBTS", "CODE", "invunit_summary"]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
UtilsVars.all_db_dfs.append(df_invunit)
|
| 81 |
UtilsVars.all_db_dfs_names.append("INVUNIT")
|
|
|
|
| 76 |
df_invunit = create_invunit_summary(df_invunit)
|
| 77 |
df_invunit["CODE"] = df_invunit["MRBTS"].apply(extract_code_from_mrbts)
|
| 78 |
df_invunit = df_invunit[["MRBTS", "CODE", "invunit_summary"]]
|
| 79 |
+
# df_invunit = df_invunit.sort_values(
|
| 80 |
+
# by=["MRBTS", "CODE"],
|
| 81 |
+
# )
|
| 82 |
+
# df_invunit["MRBTS_NUM"] = df_invunit.groupby("CODE").cumcount() + 1
|
| 83 |
+
# df_invunit["MRBTS_NUM"] = "MRBTS_" + df_invunit["MRBTS_NUM"].astype(str)
|
| 84 |
|
| 85 |
UtilsVars.all_db_dfs.append(df_invunit)
|
| 86 |
UtilsVars.all_db_dfs_names.append("INVUNIT")
|
queries/process_lte.py
CHANGED
|
@@ -3,6 +3,7 @@ import pandas as pd
|
|
| 3 |
|
| 4 |
from utils.config_band import config_band
|
| 5 |
from utils.convert_to_excel import convert_dfs, save_dataframe
|
|
|
|
| 6 |
from utils.utils_vars import (
|
| 7 |
LteFddAnalysisData,
|
| 8 |
LteTddAnalysisData,
|
|
@@ -93,6 +94,21 @@ LNCEL_TDD_COLUMNS = [
|
|
| 93 |
"rootSeqIndex",
|
| 94 |
]
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
|
| 97 |
def process_lncel(file_path: str):
|
| 98 |
"""
|
|
@@ -113,6 +129,8 @@ def process_lncel(file_path: str):
|
|
| 113 |
df_lncel = dfs["LNCEL"]
|
| 114 |
df_lncel.columns = df_lncel.columns.str.replace(r"[ ]", "", regex=True)
|
| 115 |
df_lncel["final_name"] = df_lncel["name"].fillna(df_lncel["cellName"])
|
|
|
|
|
|
|
| 116 |
df_lncel["code"] = df_lncel["final_name"].str.split("_").str[0]
|
| 117 |
df_lncel["code"] = (
|
| 118 |
pd.to_numeric(df_lncel["code"], errors="coerce").fillna(0).astype(int)
|
|
@@ -220,6 +238,31 @@ def process_lte_data_to_excel(file_path: str):
|
|
| 220 |
UtilsVars.final_lte_database = convert_dfs(lte_dfs, ["LTE_FDD", "LTE_TDD"])
|
| 221 |
|
| 222 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
#############################LTE ANALYSIS#################################
|
| 224 |
|
| 225 |
|
|
|
|
| 3 |
|
| 4 |
from utils.config_band import config_band
|
| 5 |
from utils.convert_to_excel import convert_dfs, save_dataframe
|
| 6 |
+
from utils.kml_creator import generate_kml_from_df
|
| 7 |
from utils.utils_vars import (
|
| 8 |
LteFddAnalysisData,
|
| 9 |
LteTddAnalysisData,
|
|
|
|
| 94 |
"rootSeqIndex",
|
| 95 |
]
|
| 96 |
|
| 97 |
+
LTE_KML_COLUMNS = [
|
| 98 |
+
"code",
|
| 99 |
+
"final_name",
|
| 100 |
+
"Longitude",
|
| 101 |
+
"Latitude",
|
| 102 |
+
"Azimut",
|
| 103 |
+
"Hauteur",
|
| 104 |
+
"lcrId",
|
| 105 |
+
"pMax",
|
| 106 |
+
"phyCellId",
|
| 107 |
+
"tac",
|
| 108 |
+
"rootSeqIndex",
|
| 109 |
+
"band",
|
| 110 |
+
]
|
| 111 |
+
|
| 112 |
|
| 113 |
def process_lncel(file_path: str):
|
| 114 |
"""
|
|
|
|
| 129 |
df_lncel = dfs["LNCEL"]
|
| 130 |
df_lncel.columns = df_lncel.columns.str.replace(r"[ ]", "", regex=True)
|
| 131 |
df_lncel["final_name"] = df_lncel["name"].fillna(df_lncel["cellName"])
|
| 132 |
+
# Replace empty by 999999_empty
|
| 133 |
+
# df_lncel["final_name"] = df_lncel["final_name"].fillna("999999_empty")
|
| 134 |
df_lncel["code"] = df_lncel["final_name"].str.split("_").str[0]
|
| 135 |
df_lncel["code"] = (
|
| 136 |
pd.to_numeric(df_lncel["code"], errors="coerce").fillna(0).astype(int)
|
|
|
|
| 238 |
UtilsVars.final_lte_database = convert_dfs(lte_dfs, ["LTE_FDD", "LTE_TDD"])
|
| 239 |
|
| 240 |
|
| 241 |
+
############################# KML CREATION #################################
|
| 242 |
+
def process_lte_data_to_kml(file_path: str):
|
| 243 |
+
lte_kml_dfs = process_lte_data(file_path)
|
| 244 |
+
|
| 245 |
+
lte_fdd_klm_df = lte_kml_dfs[0]
|
| 246 |
+
lte_fdd_klm_df = lte_fdd_klm_df[LTE_KML_COLUMNS]
|
| 247 |
+
|
| 248 |
+
lte_tdd_klm_df = lte_kml_dfs[1]
|
| 249 |
+
lte_tdd_klm_df = lte_tdd_klm_df[LTE_KML_COLUMNS]
|
| 250 |
+
|
| 251 |
+
# Merge FDD and TDD dataframes
|
| 252 |
+
lte_kml_df = pd.concat([lte_fdd_klm_df, lte_tdd_klm_df], ignore_index=True)
|
| 253 |
+
|
| 254 |
+
# Rename "final_name" to "name"
|
| 255 |
+
lte_kml_df.rename(columns={"final_name": "name"}, inplace=True)
|
| 256 |
+
# Add colors column base on "band" column
|
| 257 |
+
lte_kml_df["color"] = lte_kml_df["band"].map(UtilsVars.color_mapping)
|
| 258 |
+
# Add size column base on "band" column
|
| 259 |
+
lte_kml_df["size"] = lte_kml_df["band"].map(UtilsVars.size_mapping)
|
| 260 |
+
# Remove empty rows
|
| 261 |
+
lte_kml_df = lte_kml_df.dropna(subset=["Longitude", "Latitude", "Azimut"])
|
| 262 |
+
# Generate kml
|
| 263 |
+
UtilsVars.lte_kml_file = generate_kml_from_df(lte_kml_df)
|
| 264 |
+
|
| 265 |
+
|
| 266 |
#############################LTE ANALYSIS#################################
|
| 267 |
|
| 268 |
|
queries/process_wcdma.py
CHANGED
|
@@ -3,6 +3,7 @@ import pandas as pd
|
|
| 3 |
from utils.config_band import config_band
|
| 4 |
from utils.convert_to_excel import convert_dfs, save_dataframe
|
| 5 |
from utils.extract_code import extract_code_from_mrbts
|
|
|
|
| 6 |
from utils.utils_vars import UtilsVars, WcdmaAnalysisData, get_physical_db
|
| 7 |
|
| 8 |
WCEL_COLUMNS = [
|
|
@@ -76,6 +77,21 @@ WNCEL_COLUMNS = [
|
|
| 76 |
"maxCarrierPower",
|
| 77 |
]
|
| 78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
def process_wcdma_data(file_path: str):
|
| 81 |
"""
|
|
@@ -183,6 +199,28 @@ def process_wcdma_data_to_excel(file_path: str):
|
|
| 183 |
UtilsVars.final_wcdma_database = convert_dfs([wcdma_dfs], ["WCDMA"])
|
| 184 |
|
| 185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
############################ANALYTICSS AND STATISTICS############################
|
| 187 |
|
| 188 |
|
|
|
|
| 3 |
from utils.config_band import config_band
|
| 4 |
from utils.convert_to_excel import convert_dfs, save_dataframe
|
| 5 |
from utils.extract_code import extract_code_from_mrbts
|
| 6 |
+
from utils.kml_creator import generate_kml_from_df
|
| 7 |
from utils.utils_vars import UtilsVars, WcdmaAnalysisData, get_physical_db
|
| 8 |
|
| 9 |
WCEL_COLUMNS = [
|
|
|
|
| 77 |
"maxCarrierPower",
|
| 78 |
]
|
| 79 |
|
| 80 |
+
WCDMA_KML_COLUMNS = [
|
| 81 |
+
"code",
|
| 82 |
+
"name",
|
| 83 |
+
"Longitude",
|
| 84 |
+
"Latitude",
|
| 85 |
+
"Azimut",
|
| 86 |
+
"Hauteur",
|
| 87 |
+
"LAC",
|
| 88 |
+
"CId",
|
| 89 |
+
"LAC",
|
| 90 |
+
"UARFCN",
|
| 91 |
+
"PriScrCode",
|
| 92 |
+
"band",
|
| 93 |
+
]
|
| 94 |
+
|
| 95 |
|
| 96 |
def process_wcdma_data(file_path: str):
|
| 97 |
"""
|
|
|
|
| 199 |
UtilsVars.final_wcdma_database = convert_dfs([wcdma_dfs], ["WCDMA"])
|
| 200 |
|
| 201 |
|
| 202 |
+
############################# KML CREATION #################################
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def process_wcdma_data_to_kml(file_path: str):
|
| 206 |
+
"""
|
| 207 |
+
Process WCDMA data from the specified file path and convert it to KML format
|
| 208 |
+
|
| 209 |
+
Args:
|
| 210 |
+
file_path (str): The path to the file.
|
| 211 |
+
"""
|
| 212 |
+
wcdma_kml_df = process_wcdma_data(file_path)
|
| 213 |
+
wcdma_kml_df = wcdma_kml_df[WCDMA_KML_COLUMNS]
|
| 214 |
+
# Add colors column base on "band" column
|
| 215 |
+
wcdma_kml_df["color"] = wcdma_kml_df["band"].map(UtilsVars.color_mapping)
|
| 216 |
+
# Add size column base on "band" column
|
| 217 |
+
wcdma_kml_df["size"] = wcdma_kml_df["band"].map(UtilsVars.size_mapping)
|
| 218 |
+
# Remove empty rows
|
| 219 |
+
wcdma_kml_df = wcdma_kml_df.dropna(subset=["Longitude", "Latitude", "Azimut"])
|
| 220 |
+
# Generate kml
|
| 221 |
+
UtilsVars.wcdma_kml_file = generate_kml_from_df(wcdma_kml_df)
|
| 222 |
+
|
| 223 |
+
|
| 224 |
############################ANALYTICSS AND STATISTICS############################
|
| 225 |
|
| 226 |
|
requirements.txt
CHANGED
|
Binary files a/requirements.txt and b/requirements.txt differ
|
|
|
test.py
CHANGED
|
@@ -19,7 +19,7 @@ class TestProcessAllDB:
|
|
| 19 |
def test_all_dbs(self):
|
| 20 |
filepath = r"C:\Users\David\Documents\PROJECTS\2023\PROJET 2023\DUMP\DUMP\NOVEMBRE\20241127_21145_27112024_Dump.xml.gz.xlsb"
|
| 21 |
all_dbs(filepath)
|
| 22 |
-
assert len(UtilsVars.all_db_dfs) ==
|
| 23 |
assert isinstance(UtilsVars.all_db_dfs[0], pd.DataFrame)
|
| 24 |
|
| 25 |
def test_process_all_tech_db(self):
|
|
|
|
| 19 |
def test_all_dbs(self):
|
| 20 |
filepath = r"C:\Users\David\Documents\PROJECTS\2023\PROJET 2023\DUMP\DUMP\NOVEMBRE\20241127_21145_27112024_Dump.xml.gz.xlsb"
|
| 21 |
all_dbs(filepath)
|
| 22 |
+
assert len(UtilsVars.all_db_dfs) == 8
|
| 23 |
assert isinstance(UtilsVars.all_db_dfs[0], pd.DataFrame)
|
| 24 |
|
| 25 |
def test_process_all_tech_db(self):
|
utils/kml_creator.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import io
|
| 2 |
+
import math
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import simplekml
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def create_sector(kml: simplekml.Kml, row, arc_angle=65):
|
| 10 |
+
"""Create a sector shape for the telecom antenna in KML with sector details."""
|
| 11 |
+
code, name, azimuth, lon, lat, size, color = (
|
| 12 |
+
row["code"],
|
| 13 |
+
row["name"],
|
| 14 |
+
row["Azimut"],
|
| 15 |
+
row["Longitude"],
|
| 16 |
+
row["Latitude"],
|
| 17 |
+
row["size"],
|
| 18 |
+
row["color"],
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
num_points = 20 # Number of points for smooth arc
|
| 22 |
+
start_angle = azimuth - (arc_angle / 2)
|
| 23 |
+
end_angle = azimuth + (arc_angle / 2)
|
| 24 |
+
|
| 25 |
+
coords = [(lon, lat)] # Start with the site location (center point)
|
| 26 |
+
|
| 27 |
+
# Generate points for the sector arc
|
| 28 |
+
for angle in np.linspace(start_angle, end_angle, num_points):
|
| 29 |
+
angle_rad = math.radians(angle)
|
| 30 |
+
arc_lon = lon + (size / 111320) * math.sin(angle_rad)
|
| 31 |
+
arc_lat = lat + (size / 111320) * math.cos(angle_rad)
|
| 32 |
+
coords.append((arc_lon, arc_lat))
|
| 33 |
+
|
| 34 |
+
coords.append((lon, lat)) # Close the polygon
|
| 35 |
+
|
| 36 |
+
# Create the sector polygon
|
| 37 |
+
pol = kml.newpolygon(name=name, outerboundaryis=coords)
|
| 38 |
+
|
| 39 |
+
# Dynamically create the description from all DataFrame columns
|
| 40 |
+
description = "<b>Sector Details:</b><br>"
|
| 41 |
+
for column, value in row.items():
|
| 42 |
+
description += f"<b>{column}:</b> {value}<br>"
|
| 43 |
+
|
| 44 |
+
pol.description = description
|
| 45 |
+
pol.style.polystyle.color = color # Set color from DataFrame
|
| 46 |
+
pol.style.polystyle.outline = 1 # Outline enabled
|
| 47 |
+
pol.style.linestyle.color = "ff000000" # Black outline
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def generate_kml_from_df(df: pd.DataFrame):
|
| 51 |
+
"""Generate a KML file from a Pandas DataFrame for telecom sectors."""
|
| 52 |
+
kml = simplekml.Kml()
|
| 53 |
+
site_added = set() # Keep track of sites already added to avoid duplicates
|
| 54 |
+
|
| 55 |
+
# Sort the DataFrame to ensure 900 MHz (smaller) is drawn last (on top)
|
| 56 |
+
df_sorted = df.sort_values(
|
| 57 |
+
by="size", ascending=False
|
| 58 |
+
) # Larger first, smaller on top
|
| 59 |
+
|
| 60 |
+
for _, row in df_sorted.iterrows():
|
| 61 |
+
code, lon, lat = row["code"], row["Longitude"], row["Latitude"]
|
| 62 |
+
|
| 63 |
+
# Add site name as a point only once
|
| 64 |
+
if code not in site_added:
|
| 65 |
+
pnt = kml.newpoint(name=code, coords=[(lon, lat)])
|
| 66 |
+
pnt.style.iconstyle.icon.href = (
|
| 67 |
+
"http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png"
|
| 68 |
+
)
|
| 69 |
+
pnt.style.labelstyle.scale = 1.2 # Adjust label size
|
| 70 |
+
pnt.description = f"Site: {code}<br>Location: {lat}, {lon}"
|
| 71 |
+
site_added.add(code)
|
| 72 |
+
|
| 73 |
+
create_sector(kml, row)
|
| 74 |
+
|
| 75 |
+
kml_data = io.BytesIO()
|
| 76 |
+
kml_str = kml.kml() # Get KML as string
|
| 77 |
+
kml_data.write(kml_str.encode("utf-8")) # Write KML to BytesIO
|
| 78 |
+
kml_data.seek(0) # Move to beginning of BytesIO
|
| 79 |
+
return kml_data
|
utils/utils_vars.py
CHANGED
|
@@ -33,6 +33,24 @@ class UtilsVars:
|
|
| 33 |
10787: "OML UTRA Band I",
|
| 34 |
10837: "OML UTRA Band I",
|
| 35 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
wcdma_band = {
|
| 37 |
3004: "U900",
|
| 38 |
3006: "U900",
|
|
@@ -65,6 +83,9 @@ class UtilsVars:
|
|
| 65 |
final_all_database = None
|
| 66 |
neighbors_database = ""
|
| 67 |
file_path = ""
|
|
|
|
|
|
|
|
|
|
| 68 |
# physisal_db = get_physical_db()
|
| 69 |
|
| 70 |
|
|
|
|
| 33 |
10787: "OML UTRA Band I",
|
| 34 |
10837: "OML UTRA Band I",
|
| 35 |
}
|
| 36 |
+
color_mapping = {
|
| 37 |
+
"U900": "7fff0000",
|
| 38 |
+
"U2100": "7f00ff00",
|
| 39 |
+
"G900": "7fff0000",
|
| 40 |
+
"G1800": "7f00ff00",
|
| 41 |
+
"L800": "7fff0000",
|
| 42 |
+
"L1800": "7f00ff00",
|
| 43 |
+
"L2300": "7f00ffff",
|
| 44 |
+
}
|
| 45 |
+
size_mapping = {
|
| 46 |
+
"U900": 100,
|
| 47 |
+
"U2100": 120,
|
| 48 |
+
"G900": 100,
|
| 49 |
+
"G1800": 120,
|
| 50 |
+
"L800": 100,
|
| 51 |
+
"L1800": 120,
|
| 52 |
+
"L2300": 90,
|
| 53 |
+
}
|
| 54 |
wcdma_band = {
|
| 55 |
3004: "U900",
|
| 56 |
3006: "U900",
|
|
|
|
| 83 |
final_all_database = None
|
| 84 |
neighbors_database = ""
|
| 85 |
file_path = ""
|
| 86 |
+
gsm_kml_file = None
|
| 87 |
+
wcdma_kml_file = None
|
| 88 |
+
lte_kml_file = None
|
| 89 |
# physisal_db = get_physical_db()
|
| 90 |
|
| 91 |
|