Update app.py
Browse files
app.py
CHANGED
|
@@ -93,8 +93,8 @@ with gr.Blocks() as demo:
|
|
| 93 |
generate_btn = gr.Button("Generate Model Points", variant="primary")
|
| 94 |
|
| 95 |
with gr.Column(scale=2):
|
| 96 |
-
model_points_display = gr.Dataframe(label="Generated Model Points", wrap=True
|
| 97 |
-
download_excel_btn = gr.DownloadButton(label="Download Excel", variant="secondary")
|
| 98 |
gr.Markdown("---")
|
| 99 |
gr.Markdown("## 📊 Data Summary & Analysis")
|
| 100 |
with gr.Tabs():
|
|
@@ -104,8 +104,6 @@ with gr.Blocks() as demo:
|
|
| 104 |
gr.Markdown("Distribution of **Sum Assured**. Data is generated uniformly; a normal curve is fitted for illustration.")
|
| 105 |
distribution_plot_display = gr.Plot()
|
| 106 |
with gr.TabItem("Categorical Summary"):
|
| 107 |
-
# For simplicity, we'll display sex distribution here.
|
| 108 |
-
# You might want to add another Dataframe for policy_term or combine them.
|
| 109 |
sex_summary_display = gr.Dataframe(label="Sex Distribution", wrap=True)
|
| 110 |
policy_term_summary_display = gr.Dataframe(label="Policy Term Distribution", wrap=True)
|
| 111 |
|
|
@@ -119,7 +117,6 @@ with gr.Blocks() as demo:
|
|
| 119 |
no_data_df_num = pd.DataFrame({'Message': ["No data generated or summary failed."]})
|
| 120 |
no_data_df_cat = pd.DataFrame({'Message': ["No data generated or summary failed."]})
|
| 121 |
|
| 122 |
-
|
| 123 |
current_df = df_state.value if df_state.value is not None else pd.DataFrame()
|
| 124 |
|
| 125 |
if int(age_m) >= int(age_mx):
|
|
@@ -130,28 +127,27 @@ with gr.Blocks() as demo:
|
|
| 130 |
return current_df, df_state.value, pd.DataFrame({'Error': ["Minimum Sum Assured must be less than Maximum Sum Assured."]}), empty_plot, pd.DataFrame({'Error': ["Minimum Sum Assured must be less than Maximum Sum Assured."]}), pd.DataFrame({'Error': ["Minimum Sum Assured must be less than Maximum Sum Assured."]})
|
| 131 |
if not p_terms:
|
| 132 |
gr.Warning("At least one Policy Term must be selected. Using defaults.")
|
| 133 |
-
p_terms = [10, 15, 20]
|
| 134 |
|
| 135 |
gr.Info("Generating model points... Please wait.")
|
| 136 |
try:
|
| 137 |
df = generate_custom_model_points(mp_c, s, age_m, age_mx, sa_m, sa_mx, p_terms, incl_sex, pc_fixed)
|
| 138 |
gr.Info(f"{len(df)} model points generated successfully!")
|
| 139 |
|
| 140 |
-
# Numerical Summary
|
| 141 |
-
numerical_cols = ['age_at_entry', 'sum_assured', 'duration_mth', 'policy_count']
|
| 142 |
-
existing_numerical_cols = [col for col in numerical_cols if col in df.columns]
|
| 143 |
desc_stats_df = no_data_df_num
|
| 144 |
-
if
|
| 145 |
-
|
| 146 |
-
if
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
elif df.empty:
|
| 151 |
desc_stats_df = pd.DataFrame({'Message': ["DataFrame is empty, no numerical data to describe."]})
|
| 152 |
|
| 153 |
-
|
| 154 |
-
# Distribution Plot
|
| 155 |
fig = empty_plot
|
| 156 |
if 'sum_assured' in df.columns and not df['sum_assured'].empty:
|
| 157 |
fig, ax = plt.subplots(figsize=(8, 5))
|
|
@@ -167,9 +163,7 @@ with gr.Blocks() as demo:
|
|
| 167 |
ax.legend()
|
| 168 |
ax.grid(axis='y', linestyle='--', alpha=0.7)
|
| 169 |
plt.tight_layout()
|
| 170 |
-
# Removed plot_object = fig, fig is directly returned
|
| 171 |
|
| 172 |
-
# Categorical Summary
|
| 173 |
sex_counts_df = no_data_df_cat
|
| 174 |
term_counts_df = no_data_df_cat
|
| 175 |
|
|
@@ -177,7 +171,7 @@ with gr.Blocks() as demo:
|
|
| 177 |
if 'sex' in df.columns:
|
| 178 |
sex_counts = df['sex'].value_counts().reset_index()
|
| 179 |
sex_counts.columns = ['Sex', 'Count']
|
| 180 |
-
sex_counts['Percentage'] = (sex_counts['Count'] / sex_counts['Count'].sum() * 100).round(2)
|
| 181 |
sex_counts_df = sex_counts
|
| 182 |
else:
|
| 183 |
sex_counts_df = pd.DataFrame({'Message': ["'sex' column not found or data is empty."]})
|
|
@@ -185,7 +179,7 @@ with gr.Blocks() as demo:
|
|
| 185 |
if 'policy_term' in df.columns:
|
| 186 |
term_counts = df['policy_term'].value_counts().sort_index().reset_index()
|
| 187 |
term_counts.columns = ['Policy Term (Years)', 'Count']
|
| 188 |
-
term_counts['Percentage'] = (term_counts['Count'] / term_counts['Count'].sum() * 100).round(2)
|
| 189 |
term_counts_df = term_counts
|
| 190 |
else:
|
| 191 |
term_counts_df = pd.DataFrame({'Message': ["'policy_term' column not found or data is empty."]})
|
|
@@ -193,7 +187,6 @@ with gr.Blocks() as demo:
|
|
| 193 |
sex_counts_df = pd.DataFrame({'Message': ["DataFrame is empty, no categorical data for 'sex'."]})
|
| 194 |
term_counts_df = pd.DataFrame({'Message': ["DataFrame is empty, no categorical data for 'policy_term'."]})
|
| 195 |
|
| 196 |
-
|
| 197 |
return df, df, desc_stats_df, fig, sex_counts_df, term_counts_df
|
| 198 |
|
| 199 |
except Exception as e:
|
|
@@ -205,18 +198,13 @@ with gr.Blocks() as demo:
|
|
| 205 |
def handle_download_button_click(current_df_to_download):
|
| 206 |
if current_df_to_download is None or not isinstance(current_df_to_download, pd.DataFrame) or current_df_to_download.empty:
|
| 207 |
gr.Warning("No data available to download. Generate model points first.")
|
| 208 |
-
|
| 209 |
-
# For safety, returning a named file path that won't be created avoids errors.
|
| 210 |
-
return gr.DownloadButton.update(interactive=False) # Or simply return None if that works for your Gradio version.
|
| 211 |
|
| 212 |
excel_output = io.BytesIO()
|
| 213 |
-
# Ensure 'Statistic' column from describe().transpose().reset_index() is handled if it exists
|
| 214 |
-
# The main df (current_df_to_download) should be fine as is.
|
| 215 |
current_df_to_download.to_excel(excel_output, sheet_name='ModelPoints', engine='xlsxwriter', index=False)
|
| 216 |
excel_output.seek(0)
|
| 217 |
-
#
|
| 218 |
-
#
|
| 219 |
-
# The function should return the file object.
|
| 220 |
return gr.File(file_path=excel_output, file_name="model_points.xlsx", visible=True)
|
| 221 |
|
| 222 |
|
|
@@ -235,13 +223,10 @@ with gr.Blocks() as demo:
|
|
| 235 |
]
|
| 236 |
)
|
| 237 |
|
| 238 |
-
# The DownloadButton's click function should return the file object to the button itself.
|
| 239 |
-
# The `value` parameter in gr.DownloadButton is for the initial filename,
|
| 240 |
-
# but the actual file content comes from the function's return.
|
| 241 |
download_excel_btn.click(
|
| 242 |
fn=handle_download_button_click,
|
| 243 |
inputs=[df_state],
|
| 244 |
-
outputs=[download_excel_btn]
|
| 245 |
)
|
| 246 |
|
| 247 |
if __name__ == "__main__":
|
|
|
|
| 93 |
generate_btn = gr.Button("Generate Model Points", variant="primary")
|
| 94 |
|
| 95 |
with gr.Column(scale=2):
|
| 96 |
+
model_points_display = gr.Dataframe(label="Generated Model Points", wrap=True) # CORRECTED: Removed height=400
|
| 97 |
+
download_excel_btn = gr.DownloadButton(label="Download Excel", variant="secondary")
|
| 98 |
gr.Markdown("---")
|
| 99 |
gr.Markdown("## 📊 Data Summary & Analysis")
|
| 100 |
with gr.Tabs():
|
|
|
|
| 104 |
gr.Markdown("Distribution of **Sum Assured**. Data is generated uniformly; a normal curve is fitted for illustration.")
|
| 105 |
distribution_plot_display = gr.Plot()
|
| 106 |
with gr.TabItem("Categorical Summary"):
|
|
|
|
|
|
|
| 107 |
sex_summary_display = gr.Dataframe(label="Sex Distribution", wrap=True)
|
| 108 |
policy_term_summary_display = gr.Dataframe(label="Policy Term Distribution", wrap=True)
|
| 109 |
|
|
|
|
| 117 |
no_data_df_num = pd.DataFrame({'Message': ["No data generated or summary failed."]})
|
| 118 |
no_data_df_cat = pd.DataFrame({'Message': ["No data generated or summary failed."]})
|
| 119 |
|
|
|
|
| 120 |
current_df = df_state.value if df_state.value is not None else pd.DataFrame()
|
| 121 |
|
| 122 |
if int(age_m) >= int(age_mx):
|
|
|
|
| 127 |
return current_df, df_state.value, pd.DataFrame({'Error': ["Minimum Sum Assured must be less than Maximum Sum Assured."]}), empty_plot, pd.DataFrame({'Error': ["Minimum Sum Assured must be less than Maximum Sum Assured."]}), pd.DataFrame({'Error': ["Minimum Sum Assured must be less than Maximum Sum Assured."]})
|
| 128 |
if not p_terms:
|
| 129 |
gr.Warning("At least one Policy Term must be selected. Using defaults.")
|
| 130 |
+
p_terms = [10, 15, 20]
|
| 131 |
|
| 132 |
gr.Info("Generating model points... Please wait.")
|
| 133 |
try:
|
| 134 |
df = generate_custom_model_points(mp_c, s, age_m, age_mx, sa_m, sa_mx, p_terms, incl_sex, pc_fixed)
|
| 135 |
gr.Info(f"{len(df)} model points generated successfully!")
|
| 136 |
|
|
|
|
|
|
|
|
|
|
| 137 |
desc_stats_df = no_data_df_num
|
| 138 |
+
if not df.empty:
|
| 139 |
+
numerical_cols = ['age_at_entry', 'sum_assured', 'duration_mth', 'policy_count']
|
| 140 |
+
existing_numerical_cols = [col for col in numerical_cols if col in df.columns]
|
| 141 |
+
if existing_numerical_cols:
|
| 142 |
+
desc_stats = df[existing_numerical_cols].describe().transpose()
|
| 143 |
+
if 'count' in desc_stats.columns:
|
| 144 |
+
desc_stats['count'] = desc_stats['count'].astype(int)
|
| 145 |
+
desc_stats_df = desc_stats.reset_index().rename(columns={'index': 'Statistic'})
|
| 146 |
+
else:
|
| 147 |
+
desc_stats_df = pd.DataFrame({'Message': ["No numerical columns found for summary."]})
|
| 148 |
elif df.empty:
|
| 149 |
desc_stats_df = pd.DataFrame({'Message': ["DataFrame is empty, no numerical data to describe."]})
|
| 150 |
|
|
|
|
|
|
|
| 151 |
fig = empty_plot
|
| 152 |
if 'sum_assured' in df.columns and not df['sum_assured'].empty:
|
| 153 |
fig, ax = plt.subplots(figsize=(8, 5))
|
|
|
|
| 163 |
ax.legend()
|
| 164 |
ax.grid(axis='y', linestyle='--', alpha=0.7)
|
| 165 |
plt.tight_layout()
|
|
|
|
| 166 |
|
|
|
|
| 167 |
sex_counts_df = no_data_df_cat
|
| 168 |
term_counts_df = no_data_df_cat
|
| 169 |
|
|
|
|
| 171 |
if 'sex' in df.columns:
|
| 172 |
sex_counts = df['sex'].value_counts().reset_index()
|
| 173 |
sex_counts.columns = ['Sex', 'Count']
|
| 174 |
+
sex_counts['Percentage'] = (sex_counts['Count'] / sex_counts['Count'].sum() * 100).round(2)
|
| 175 |
sex_counts_df = sex_counts
|
| 176 |
else:
|
| 177 |
sex_counts_df = pd.DataFrame({'Message': ["'sex' column not found or data is empty."]})
|
|
|
|
| 179 |
if 'policy_term' in df.columns:
|
| 180 |
term_counts = df['policy_term'].value_counts().sort_index().reset_index()
|
| 181 |
term_counts.columns = ['Policy Term (Years)', 'Count']
|
| 182 |
+
term_counts['Percentage'] = (term_counts['Count'] / term_counts['Count'].sum() * 100).round(2)
|
| 183 |
term_counts_df = term_counts
|
| 184 |
else:
|
| 185 |
term_counts_df = pd.DataFrame({'Message': ["'policy_term' column not found or data is empty."]})
|
|
|
|
| 187 |
sex_counts_df = pd.DataFrame({'Message': ["DataFrame is empty, no categorical data for 'sex'."]})
|
| 188 |
term_counts_df = pd.DataFrame({'Message': ["DataFrame is empty, no categorical data for 'policy_term'."]})
|
| 189 |
|
|
|
|
| 190 |
return df, df, desc_stats_df, fig, sex_counts_df, term_counts_df
|
| 191 |
|
| 192 |
except Exception as e:
|
|
|
|
| 198 |
def handle_download_button_click(current_df_to_download):
|
| 199 |
if current_df_to_download is None or not isinstance(current_df_to_download, pd.DataFrame) or current_df_to_download.empty:
|
| 200 |
gr.Warning("No data available to download. Generate model points first.")
|
| 201 |
+
return gr.DownloadButton.update(interactive=False)
|
|
|
|
|
|
|
| 202 |
|
| 203 |
excel_output = io.BytesIO()
|
|
|
|
|
|
|
| 204 |
current_df_to_download.to_excel(excel_output, sheet_name='ModelPoints', engine='xlsxwriter', index=False)
|
| 205 |
excel_output.seek(0)
|
| 206 |
+
# Returning a BytesIO object directly for file download
|
| 207 |
+
# Provide a filename for the browser
|
|
|
|
| 208 |
return gr.File(file_path=excel_output, file_name="model_points.xlsx", visible=True)
|
| 209 |
|
| 210 |
|
|
|
|
| 223 |
]
|
| 224 |
)
|
| 225 |
|
|
|
|
|
|
|
|
|
|
| 226 |
download_excel_btn.click(
|
| 227 |
fn=handle_download_button_click,
|
| 228 |
inputs=[df_state],
|
| 229 |
+
outputs=[download_excel_btn]
|
| 230 |
)
|
| 231 |
|
| 232 |
if __name__ == "__main__":
|