Update app.py
Browse files
app.py
CHANGED
|
@@ -110,13 +110,11 @@ def map_designations(df, column_name="designation_title"):
|
|
| 110 |
def handle_new_designations(df, column_name="designation_title"):
|
| 111 |
"""Handle new designations and update the CADRE_MAPPINGS dictionary."""
|
| 112 |
try:
|
| 113 |
-
# Get current designations that aren't in our mapping
|
| 114 |
current_designations = set(df[df['Cadre'] == 'Unmapped'][column_name].unique())
|
| 115 |
|
| 116 |
if current_designations:
|
| 117 |
st.warning(f"π Found {len(current_designations)} new designation(s) that need mapping!")
|
| 118 |
|
| 119 |
-
# Available cadre levels (predefined options only)
|
| 120 |
CADRE_LEVELS = [
|
| 121 |
"District Level",
|
| 122 |
"Federal Level",
|
|
@@ -125,7 +123,6 @@ def handle_new_designations(df, column_name="designation_title"):
|
|
| 125 |
"UC Level"
|
| 126 |
]
|
| 127 |
|
| 128 |
-
# Create a container for new mappings
|
| 129 |
new_mappings = {}
|
| 130 |
|
| 131 |
with st.expander("Map New Designations", expanded=True):
|
|
@@ -133,7 +130,7 @@ def handle_new_designations(df, column_name="designation_title"):
|
|
| 133 |
st.markdown("Please assign appropriate cadres to the following designations:")
|
| 134 |
|
| 135 |
# Create a form for mapping new designations
|
| 136 |
-
for designation in current_designations:
|
| 137 |
col1, col2 = st.columns([2, 1])
|
| 138 |
with col1:
|
| 139 |
st.text(designation)
|
|
@@ -141,7 +138,7 @@ def handle_new_designations(df, column_name="designation_title"):
|
|
| 141 |
selected_cadre = st.selectbox(
|
| 142 |
"Select Cadre",
|
| 143 |
options=CADRE_LEVELS,
|
| 144 |
-
key=f"new_designation_{
|
| 145 |
)
|
| 146 |
new_mappings[designation] = selected_cadre
|
| 147 |
|
|
@@ -180,7 +177,8 @@ def show_interactive_preview(df):
|
|
| 180 |
cols = st.multiselect(
|
| 181 |
"Select columns to display:",
|
| 182 |
df.columns.tolist(),
|
| 183 |
-
default=df.columns.tolist()
|
|
|
|
| 184 |
)
|
| 185 |
|
| 186 |
# Row count slider
|
|
@@ -188,19 +186,24 @@ def show_interactive_preview(df):
|
|
| 188 |
"Number of rows to display:",
|
| 189 |
min_value=5,
|
| 190 |
max_value=len(df),
|
| 191 |
-
value=min(50, len(df))
|
|
|
|
| 192 |
)
|
| 193 |
|
| 194 |
# Index visibility
|
| 195 |
-
hide_index = st.checkbox("Hide index", value=True)
|
| 196 |
|
| 197 |
# Search and filter in an expander
|
| 198 |
with st.expander("π Search & Filters", expanded=False):
|
| 199 |
# Global search
|
| 200 |
-
search = st.text_input("Search in all columns:", "")
|
| 201 |
|
| 202 |
# Column-specific filters
|
| 203 |
-
filter_col = st.selectbox(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
|
| 205 |
if filter_col != "None":
|
| 206 |
if df[filter_col].dtype in ['int64', 'float64']:
|
|
@@ -209,7 +212,8 @@ def show_interactive_preview(df):
|
|
| 209 |
f"Range for {filter_col}:",
|
| 210 |
float(df[filter_col].min()),
|
| 211 |
float(df[filter_col].max()),
|
| 212 |
-
(float(df[filter_col].min()), float(df[filter_col].max()))
|
|
|
|
| 213 |
)
|
| 214 |
else:
|
| 215 |
# Category filter
|
|
@@ -217,7 +221,8 @@ def show_interactive_preview(df):
|
|
| 217 |
selected_vals = st.multiselect(
|
| 218 |
f"Select values for {filter_col}:",
|
| 219 |
unique_vals,
|
| 220 |
-
default=unique_vals
|
|
|
|
| 221 |
)
|
| 222 |
|
| 223 |
# Apply filters
|
|
@@ -226,11 +231,11 @@ def show_interactive_preview(df):
|
|
| 226 |
# Apply search
|
| 227 |
if search:
|
| 228 |
mask = filtered_df.astype(str).apply(
|
| 229 |
-
lambda x: x.str.contains(search, case=False)
|
| 230 |
).any(axis=1)
|
| 231 |
filtered_df = filtered_df[mask]
|
| 232 |
-
|
| 233 |
-
#
|
| 234 |
if filter_col != "None":
|
| 235 |
if df[filter_col].dtype in ['int64', 'float64']:
|
| 236 |
filtered_df = filtered_df[
|
|
@@ -239,7 +244,7 @@ def show_interactive_preview(df):
|
|
| 239 |
]
|
| 240 |
else:
|
| 241 |
filtered_df = filtered_df[filtered_df[filter_col].isin(selected_vals)]
|
| 242 |
-
|
| 243 |
# Show the filtered dataframe
|
| 244 |
st.dataframe(
|
| 245 |
filtered_df[cols].head(row_count),
|
|
@@ -276,7 +281,8 @@ def show_visualizations(df):
|
|
| 276 |
with st.expander("Numeric Distributions", expanded=False):
|
| 277 |
selected_column = st.selectbox(
|
| 278 |
"Select numeric column for distribution",
|
| 279 |
-
numeric_cols
|
|
|
|
| 280 |
)
|
| 281 |
fig_dist = px.histogram(
|
| 282 |
df,
|
|
@@ -471,22 +477,23 @@ def main():
|
|
| 471 |
with st.spinner('Cleaning data...'):
|
| 472 |
df = clean_data(df)
|
| 473 |
|
| 474 |
-
# Map designations to cadres
|
| 475 |
-
|
| 476 |
-
|
|
|
|
| 477 |
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 482 |
|
| 483 |
if app_mode == "Data Processing":
|
| 484 |
-
# Handle new designations if any are unmapped
|
| 485 |
-
if len(unmapped) > 0:
|
| 486 |
-
df = handle_new_designations(df)
|
| 487 |
-
# Reapply mapping after handling new designations
|
| 488 |
-
df = map_designations(df)
|
| 489 |
-
|
| 490 |
# Show interactive preview
|
| 491 |
filtered_df = show_interactive_preview(df)
|
| 492 |
|
|
@@ -516,11 +523,12 @@ def main():
|
|
| 516 |
|
| 517 |
question_type = st.selectbox(
|
| 518 |
"Choose a question type:",
|
| 519 |
-
suggested_questions
|
|
|
|
| 520 |
)
|
| 521 |
|
| 522 |
if question_type == "Custom Question":
|
| 523 |
-
question = st.text_input("Enter your question about the data:")
|
| 524 |
else:
|
| 525 |
question = question_type
|
| 526 |
|
|
@@ -539,7 +547,7 @@ def main():
|
|
| 539 |
st.text("Raw AI Response:")
|
| 540 |
st.code(st.session_state['last_response'])
|
| 541 |
|
| 542 |
-
if st.button("Generate Follow-up Questions"):
|
| 543 |
follow_up_prompt = f"Based on the previous analysis about '{question}', what are 3 relevant follow-up questions we could ask about this data?"
|
| 544 |
follow_up_response = query_gemini(df, follow_up_prompt)
|
| 545 |
st.markdown("### Suggested Follow-up Questions")
|
|
|
|
| 110 |
def handle_new_designations(df, column_name="designation_title"):
|
| 111 |
"""Handle new designations and update the CADRE_MAPPINGS dictionary."""
|
| 112 |
try:
|
|
|
|
| 113 |
current_designations = set(df[df['Cadre'] == 'Unmapped'][column_name].unique())
|
| 114 |
|
| 115 |
if current_designations:
|
| 116 |
st.warning(f"π Found {len(current_designations)} new designation(s) that need mapping!")
|
| 117 |
|
|
|
|
| 118 |
CADRE_LEVELS = [
|
| 119 |
"District Level",
|
| 120 |
"Federal Level",
|
|
|
|
| 123 |
"UC Level"
|
| 124 |
]
|
| 125 |
|
|
|
|
| 126 |
new_mappings = {}
|
| 127 |
|
| 128 |
with st.expander("Map New Designations", expanded=True):
|
|
|
|
| 130 |
st.markdown("Please assign appropriate cadres to the following designations:")
|
| 131 |
|
| 132 |
# Create a form for mapping new designations
|
| 133 |
+
for idx, designation in enumerate(current_designations):
|
| 134 |
col1, col2 = st.columns([2, 1])
|
| 135 |
with col1:
|
| 136 |
st.text(designation)
|
|
|
|
| 138 |
selected_cadre = st.selectbox(
|
| 139 |
"Select Cadre",
|
| 140 |
options=CADRE_LEVELS,
|
| 141 |
+
key=f"new_designation_{idx}"
|
| 142 |
)
|
| 143 |
new_mappings[designation] = selected_cadre
|
| 144 |
|
|
|
|
| 177 |
cols = st.multiselect(
|
| 178 |
"Select columns to display:",
|
| 179 |
df.columns.tolist(),
|
| 180 |
+
default=df.columns.tolist(),
|
| 181 |
+
key="preview_columns" # Added unique key
|
| 182 |
)
|
| 183 |
|
| 184 |
# Row count slider
|
|
|
|
| 186 |
"Number of rows to display:",
|
| 187 |
min_value=5,
|
| 188 |
max_value=len(df),
|
| 189 |
+
value=min(50, len(df)),
|
| 190 |
+
key="row_count_slider" # Added unique key
|
| 191 |
)
|
| 192 |
|
| 193 |
# Index visibility
|
| 194 |
+
hide_index = st.checkbox("Hide index", value=True, key="hide_index_checkbox") # Added unique key
|
| 195 |
|
| 196 |
# Search and filter in an expander
|
| 197 |
with st.expander("π Search & Filters", expanded=False):
|
| 198 |
# Global search
|
| 199 |
+
search = st.text_input("Search in all columns:", "", key="search_input") # Added unique key
|
| 200 |
|
| 201 |
# Column-specific filters
|
| 202 |
+
filter_col = st.selectbox(
|
| 203 |
+
"Filter by column:",
|
| 204 |
+
["None"] + df.columns.tolist(),
|
| 205 |
+
key="filter_column_selectbox" # Added unique key
|
| 206 |
+
)
|
| 207 |
|
| 208 |
if filter_col != "None":
|
| 209 |
if df[filter_col].dtype in ['int64', 'float64']:
|
|
|
|
| 212 |
f"Range for {filter_col}:",
|
| 213 |
float(df[filter_col].min()),
|
| 214 |
float(df[filter_col].max()),
|
| 215 |
+
(float(df[filter_col].min()), float(df[filter_col].max())),
|
| 216 |
+
key=f"filter_{filter_col}_range_slider" # Added unique key
|
| 217 |
)
|
| 218 |
else:
|
| 219 |
# Category filter
|
|
|
|
| 221 |
selected_vals = st.multiselect(
|
| 222 |
f"Select values for {filter_col}:",
|
| 223 |
unique_vals,
|
| 224 |
+
default=unique_vals,
|
| 225 |
+
key=f"filter_{filter_col}_multiselect" # Added unique key
|
| 226 |
)
|
| 227 |
|
| 228 |
# Apply filters
|
|
|
|
| 231 |
# Apply search
|
| 232 |
if search:
|
| 233 |
mask = filtered_df.astype(str).apply(
|
| 234 |
+
lambda x: x.str.contains(search, case=False, na=False)
|
| 235 |
).any(axis=1)
|
| 236 |
filtered_df = filtered_df[mask]
|
| 237 |
+
|
| 238 |
+
# Fix the filter logic
|
| 239 |
if filter_col != "None":
|
| 240 |
if df[filter_col].dtype in ['int64', 'float64']:
|
| 241 |
filtered_df = filtered_df[
|
|
|
|
| 244 |
]
|
| 245 |
else:
|
| 246 |
filtered_df = filtered_df[filtered_df[filter_col].isin(selected_vals)]
|
| 247 |
+
|
| 248 |
# Show the filtered dataframe
|
| 249 |
st.dataframe(
|
| 250 |
filtered_df[cols].head(row_count),
|
|
|
|
| 281 |
with st.expander("Numeric Distributions", expanded=False):
|
| 282 |
selected_column = st.selectbox(
|
| 283 |
"Select numeric column for distribution",
|
| 284 |
+
numeric_cols,
|
| 285 |
+
key="numeric_column"
|
| 286 |
)
|
| 287 |
fig_dist = px.histogram(
|
| 288 |
df,
|
|
|
|
| 477 |
with st.spinner('Cleaning data...'):
|
| 478 |
df = clean_data(df)
|
| 479 |
|
| 480 |
+
# Map designations to cadres (if applicable)
|
| 481 |
+
if "designation_title" in df.columns:
|
| 482 |
+
with st.spinner('Mapping designations to cadres...'):
|
| 483 |
+
df = map_designations(df)
|
| 484 |
|
| 485 |
+
# Show the unique designations that weren't mapped
|
| 486 |
+
unmapped = df[df['Cadre'] == 'Unmapped']['designation_title'].unique()
|
| 487 |
+
if len(unmapped) > 0:
|
| 488 |
+
st.warning(f"Found {len(unmapped)} unmapped designations!")
|
| 489 |
+
|
| 490 |
+
# Handle new designations if any are unmapped
|
| 491 |
+
if len(unmapped) > 0:
|
| 492 |
+
df = handle_new_designations(df)
|
| 493 |
+
# Reapply mapping after handling new designations
|
| 494 |
+
df = map_designations(df)
|
| 495 |
|
| 496 |
if app_mode == "Data Processing":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
# Show interactive preview
|
| 498 |
filtered_df = show_interactive_preview(df)
|
| 499 |
|
|
|
|
| 523 |
|
| 524 |
question_type = st.selectbox(
|
| 525 |
"Choose a question type:",
|
| 526 |
+
suggested_questions,
|
| 527 |
+
key="analysis_question_type"
|
| 528 |
)
|
| 529 |
|
| 530 |
if question_type == "Custom Question":
|
| 531 |
+
question = st.text_input("Enter your question about the data:", key="custom_question")
|
| 532 |
else:
|
| 533 |
question = question_type
|
| 534 |
|
|
|
|
| 547 |
st.text("Raw AI Response:")
|
| 548 |
st.code(st.session_state['last_response'])
|
| 549 |
|
| 550 |
+
if st.button("Generate Follow-up Questions", key="followup_questions"):
|
| 551 |
follow_up_prompt = f"Based on the previous analysis about '{question}', what are 3 relevant follow-up questions we could ask about this data?"
|
| 552 |
follow_up_response = query_gemini(df, follow_up_prompt)
|
| 553 |
st.markdown("### Suggested Follow-up Questions")
|