Skip to content

Commit cda793a

Browse files
authored
Feat: Add filters and map (#69)
1 parent d2ec4d7 commit cda793a

File tree

3 files changed

+111
-38
lines changed

3 files changed

+111
-38
lines changed

app.py

Lines changed: 105 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import os
2+
import folium
23
import tempfile
34
import subprocess
45
import pandas as pd
56
import streamlit as st
7+
from streamlit_folium import st_folium
68

79
#Page Setup
810
st.set_page_config(
@@ -13,12 +15,28 @@
1315
initial_sidebar_state="expanded",
1416
)
1517

18+
# Session setup
19+
if 'calculate_clicked' not in st.session_state:
20+
st.session_state.calculate_clicked = False
21+
if 'calculation_completed' not in st.session_state:
22+
st.session_state.calculation_completed = False
23+
if 'calculated_data' not in st.session_state:
24+
st.session_state.calculated_data = {}
25+
if 'filter_type' not in st.session_state:
26+
st.session_state.filter_type = None
27+
if 'filter_value' not in st.session_state:
28+
st.session_state.filter_value = None
29+
30+
31+
#Maps setup
32+
m = folium.Map(location=[27.7007, 85.3001], zoom_start=12, )
33+
fg = folium.FeatureGroup(name="Allocated Centers")
34+
1635
#Sidebar
1736
with st.sidebar:
1837

19-
add_side_header = st.sidebar.title(
20-
"Random Center Calculator"
21-
)
38+
add_side_header = st.sidebar.title("Random Center Calculator")
39+
2240
schools_file = st.sidebar.file_uploader("Upload School/College file", type="tsv")
2341
centers_file = st.sidebar.file_uploader("Upload Centers file", type="tsv")
2442
prefs_file = st.sidebar.file_uploader("Upload Preferences file", type="tsv")
@@ -65,50 +83,99 @@ def run_center_randomizer(schools_tsv, centers_tsv, prefs_tsv):
6583
cmd = f"python school_center.py {schools_tsv} {centers_tsv} {prefs_tsv}"
6684
subprocess.run(cmd, shell=True)
6785

86+
#Function to filter the data
87+
def filter_data(df, filter_type, filter_value):
88+
if filter_type in df.columns:
89+
df = df[df[filter_type] == filter_value]
90+
return df
91+
else:
92+
st.error(f"{filter_type} is not a valid column in the DataFrame.")
93+
return pd.DataFrame()
94+
6895
# Run logic after the button is clicked
6996
if calculate:
70-
97+
st.session_state.calculate_clicked = True
98+
7199
def save_file_to_temp(file_obj):
72100
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
73101
file_obj.seek(0) # Go to the start of the file
74102
temp_file.write(file_obj.read())
75103
return temp_file.name
76104

77-
# Ensure all files are uploaded
78-
if schools_file and centers_file and prefs_file:
79-
schools_path = save_file_to_temp(schools_file)
80-
centers_path = save_file_to_temp(centers_file)
81-
prefs_path = save_file_to_temp(prefs_file)
82-
83-
# Run the program with the temporary file paths
84-
run_center_randomizer(schools_path, centers_path, prefs_path)
85-
86-
# Set the paths for the output files
87-
school_center_file = "results/school-center.tsv"
88-
school_center_distance_file = "results/school-center-distance.tsv"
89-
90-
# Delete the temporary files after use
91-
os.unlink(schools_path)
92-
os.unlink(centers_path)
93-
os.unlink(prefs_path)
94-
95-
# Display data in the specified tabs
96-
if school_center_file:
97-
df = pd.read_csv(school_center_file, sep="\t")
98-
tab1.dataframe(df)
99-
else:
100-
tab1.error("School Center file not found.")
101-
102-
if school_center_distance_file:
103-
df = pd.read_csv(school_center_distance_file, sep="\t")
104-
tab2.dataframe(df)
105+
if st.session_state.calculate_clicked:
106+
# Ensure all files are uploaded
107+
if schools_file and centers_file and prefs_file:
108+
schools_path = save_file_to_temp(schools_file)
109+
centers_path = save_file_to_temp(centers_file)
110+
prefs_path = save_file_to_temp(prefs_file)
111+
112+
# Run the program with the temporary file paths
113+
run_center_randomizer(schools_path, centers_path, prefs_path)
114+
st.toast("Calculation successful!", icon="🎉")
115+
st.session_state.calculation_completed = True
116+
117+
# Delete the temporary files after use
118+
os.unlink(schools_path)
119+
os.unlink(centers_path)
120+
os.unlink(prefs_path)
121+
122+
# Set the paths for the output files[UPDATE LATER TO BE FLEXIBLE]
123+
school_center_file = "results/school-center.tsv"
124+
school_center_distance_file = "results/school-center-distance.tsv"
125+
126+
# Store calculated data in session state
127+
if school_center_file and school_center_distance_file:
128+
st.session_state.calculated_data['school_center'] = school_center_file
129+
st.session_state.calculated_data['school_center_distance'] = school_center_distance_file
130+
else:
131+
tab1.error("Calculated data not found", icon="🚨")
132+
105133
else:
106-
tab2.error("School Center Distance file not found.")
134+
st.sidebar.error("Please upload all required files.", icon="🚨")
107135

108-
st.toast("Calculation successful!", icon="🎉")
109-
110-
else:
111-
st.sidebar.error("Please upload all required files.", icon="🚨")
112-
else:
136+
elif not st.session_state.calculate_clicked:
113137
tab1_msg = tab1.info("Results will be shown only after the calculation is completed.", icon="ℹ️")
114138
tab2_msg = tab2.info("Results will be shown only after the calculation is completed.", icon="ℹ️")
139+
140+
if st.session_state.calculate_clicked and st.session_state.calculation_completed:
141+
# Display data from session state
142+
if 'school_center' in st.session_state.calculated_data:
143+
df_school_center = pd.read_csv(st.session_state.calculated_data['school_center'], sep="\t")
144+
allowed_filter_types = ['scode', 'school', 'cscode', 'center']
145+
st.session_state.filter_type = tab1.radio("Choose a filter type:", allowed_filter_types)
146+
147+
# Display an input field based on the selected filter type
148+
if st.session_state.filter_type:
149+
st.session_state.filter_value = tab1.selectbox(f"Select a value for {st.session_state.filter_type}:", df_school_center[st.session_state.filter_type].unique())
150+
# Filter the DataFrame based on the selected filter type and value
151+
if st.session_state.filter_value:
152+
filtered_df = filter_data(df_school_center, st.session_state.filter_type, st.session_state.filter_value)
153+
tab1.dataframe(filtered_df)
154+
tab1.subheader('Map')
155+
tab1.divider()
156+
for index, center in filtered_df.iterrows():
157+
fg.add_child(
158+
folium.Marker(
159+
location=[center.center_lat, center.center_long],
160+
popup=f"{(center.center).title()}\nAllocation: {center.allocation}",
161+
tooltip=f"{center.center}",
162+
icon=folium.Icon(color="red")
163+
)
164+
)
165+
m.add_child(fg)
166+
with tab1:
167+
st_folium( m, width=1200, height=400 )
168+
169+
tab1.divider()
170+
tab1.subheader('All Data')
171+
tab1.dataframe(df_school_center)
172+
else:
173+
tab1.info("No calculated data available.", icon="ℹ️")
174+
175+
if 'school_center_distance' in st.session_state.calculated_data:
176+
df = pd.read_csv(st.session_state.calculated_data['school_center_distance'], sep="\t")
177+
tab2.dataframe(df)
178+
else:
179+
tab2.error("School Center Distance file not found.")
180+
elif st.session_state.calculate_clicked and not st.session_state.calculated_data:
181+
tab1.error("School Center data not found in session state.")

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ pytest-sugar==1.0.0
55
pre-commit==3.6.0
66
pytest-cov==5.0.0
77
streamlit==1.33.0
8+
streamlit_folium==0.19.1
9+
folium==0.16.0

school_center.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ def get_output_filename():
264264
"cscode",
265265
"center",
266266
"center_address",
267+
"center_lat",
268+
"center_long",
267269
"allocation",
268270
"distance_km"])
269271

@@ -321,6 +323,8 @@ def get_output_filename():
321323
c['cscode'],
322324
c['name'],
323325
c['address'],
326+
c['lat'],
327+
c['long'],
324328
allocations[s['scode']][c['cscode']],
325329
c['distance_km']])
326330

0 commit comments

Comments
 (0)