Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -207,6 +207,141 @@ def plot_model_results(results_df, average_value, title, model_type):
|
|
| 207 |
logger.error("Error plotting model results: %s", e)
|
| 208 |
raise
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
def plot_bucket_fullness(driver_df, title):
|
| 211 |
# Determine required trust buckets
|
| 212 |
buckets = [
|
|
@@ -657,7 +792,7 @@ def analyze_excel_single(file_path):
|
|
| 657 |
results_df_nps = pd.read_csv(csv_output_path_nps)
|
| 658 |
results_df_nps["Importance_percent"] = results_df_nps["Importance"] * 100
|
| 659 |
average_value_nps = results_df_nps["Importance_percent"].mean()
|
| 660 |
-
img_nps =
|
| 661 |
results_df_nps,
|
| 662 |
average_value_nps,
|
| 663 |
f"NPS Drivers: {file_name}",
|
|
|
|
| 207 |
logger.error("Error plotting model results: %s", e)
|
| 208 |
raise
|
| 209 |
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def plot_model(results_df, average_value, title, model_type):
|
| 214 |
+
"""
|
| 215 |
+
Plot model results with specific orders and colors for Trust and NPS models.
|
| 216 |
+
Args:
|
| 217 |
+
results_df (DataFrame): DataFrame containing predictor names and their importance.
|
| 218 |
+
average_value (float): Average importance value.
|
| 219 |
+
title (str): Title of the plot.
|
| 220 |
+
model_type (str): Type of model (either "Trust" or "NPS").
|
| 221 |
+
Returns:
|
| 222 |
+
Image: Image object containing the plot.
|
| 223 |
+
"""
|
| 224 |
+
|
| 225 |
+
logger.info(
|
| 226 |
+
"Plotting model results for %s model with title '%s'.", model_type, title
|
| 227 |
+
)
|
| 228 |
+
try:
|
| 229 |
+
# Define color scheme
|
| 230 |
+
color_map = {
|
| 231 |
+
"Stability": "#375570",
|
| 232 |
+
"Development": "#E3B05B",
|
| 233 |
+
"Relationship": "#C63F48",
|
| 234 |
+
"Benefit": "#418387",
|
| 235 |
+
"Vision": "#DF8859",
|
| 236 |
+
"Competence": "#6D93AB",
|
| 237 |
+
"Trust": "#f5918a",
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
# Define the order for each model
|
| 241 |
+
if model_type == "Trust":
|
| 242 |
+
order = [
|
| 243 |
+
"Stability",
|
| 244 |
+
"Development",
|
| 245 |
+
"Relationship",
|
| 246 |
+
"Benefit",
|
| 247 |
+
"Vision",
|
| 248 |
+
"Competence",
|
| 249 |
+
]
|
| 250 |
+
else: # "NPS"
|
| 251 |
+
order = [
|
| 252 |
+
"Trust",
|
| 253 |
+
"Stability",
|
| 254 |
+
"Development",
|
| 255 |
+
"Relationship",
|
| 256 |
+
"Benefit",
|
| 257 |
+
"Vision",
|
| 258 |
+
"Competence",
|
| 259 |
+
]
|
| 260 |
+
|
| 261 |
+
# Apply the categorical ordering to the 'Predictor' column
|
| 262 |
+
results_df["Predictor"] = pd.Categorical(
|
| 263 |
+
results_df["Predictor"], categories=order, ordered=True
|
| 264 |
+
)
|
| 265 |
+
results_df.sort_values("Predictor", ascending=False, inplace=True)
|
| 266 |
+
|
| 267 |
+
# Create the figure and axis
|
| 268 |
+
fig, ax = plt.subplots(figsize=(10, 8))
|
| 269 |
+
|
| 270 |
+
# Set the x-axis labels with "%" using FuncFormatter
|
| 271 |
+
formatter = FuncFormatter(lambda x, _: f"{x:.0f}%")
|
| 272 |
+
ax.xaxis.set_major_formatter(formatter)
|
| 273 |
+
|
| 274 |
+
# Determine the dynamic range of the X-axis
|
| 275 |
+
actual_min = results_df["Importance_percent"].min()
|
| 276 |
+
actual_max = results_df["Importance_percent"].max()
|
| 277 |
+
|
| 278 |
+
# Calculate the x-axis limits
|
| 279 |
+
half_range = max(average_value - actual_min, actual_max - average_value)
|
| 280 |
+
x_min = 0 # start from zero
|
| 281 |
+
x_max = actual_max + 5 # a bit beyond max
|
| 282 |
+
plt.xlim(x_min, x_max)
|
| 283 |
+
|
| 284 |
+
# Set the x-axis ticks at every 5% interval and add dotted lines
|
| 285 |
+
x_ticks = np.arange(
|
| 286 |
+
np.floor(x_min), np.ceil(x_max) + 5, 5
|
| 287 |
+
) # Ensures complete coverage
|
| 288 |
+
ax.set_xticks(x_ticks) # Set the ticks on the axis
|
| 289 |
+
for tick in x_ticks:
|
| 290 |
+
ax.axvline(
|
| 291 |
+
x=tick, color="grey", linestyle="--", linewidth=0.5, zorder=2
|
| 292 |
+
) # Add dotted lines
|
| 293 |
+
|
| 294 |
+
# Create bars: all from 0 → value (left-to-right only)
|
| 295 |
+
for i, row in enumerate(results_df.itertuples(index=False)):
|
| 296 |
+
color = color_map[row.Predictor]
|
| 297 |
+
|
| 298 |
+
ax.barh(
|
| 299 |
+
row.Predictor,
|
| 300 |
+
row.Importance_percent,
|
| 301 |
+
left=0,
|
| 302 |
+
color=color,
|
| 303 |
+
edgecolor="white",
|
| 304 |
+
height=0.6,
|
| 305 |
+
zorder=3,
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
ax.text(
|
| 309 |
+
row.Importance_percent + 0.5,
|
| 310 |
+
i,
|
| 311 |
+
f"{row.Importance_percent:.1f}%",
|
| 312 |
+
va="center",
|
| 313 |
+
ha="left",
|
| 314 |
+
color="#8c8b8c",
|
| 315 |
+
)
|
| 316 |
+
|
| 317 |
+
# Draw the average line and set the title
|
| 318 |
+
ax.axvline(average_value, color="black", linewidth=1, linestyle="-", zorder=3)
|
| 319 |
+
plt.title(title, fontsize=14)
|
| 320 |
+
|
| 321 |
+
# Remove plot borders
|
| 322 |
+
ax.spines[["left", "top", "right"]].set_color("none")
|
| 323 |
+
|
| 324 |
+
# Change the colour of y-axis text
|
| 325 |
+
ax.tick_params(axis="y", colors="#8c8b8c", length=0)
|
| 326 |
+
|
| 327 |
+
# Send axes to background and tighten the layout
|
| 328 |
+
ax.set_axisbelow(True)
|
| 329 |
+
plt.tight_layout()
|
| 330 |
+
|
| 331 |
+
# Save the figure to a bytes buffer and then to an image
|
| 332 |
+
img_data = io.BytesIO()
|
| 333 |
+
plt.savefig(
|
| 334 |
+
img_data, format="png", facecolor=fig.get_facecolor(), edgecolor="none"
|
| 335 |
+
)
|
| 336 |
+
img_data.seek(0)
|
| 337 |
+
img = Image.open(img_data)
|
| 338 |
+
plt.close(fig)
|
| 339 |
+
|
| 340 |
+
return img
|
| 341 |
+
|
| 342 |
+
except Exception as e:
|
| 343 |
+
logger.error("Error plotting model results: %s", e)
|
| 344 |
+
raise
|
| 345 |
def plot_bucket_fullness(driver_df, title):
|
| 346 |
# Determine required trust buckets
|
| 347 |
buckets = [
|
|
|
|
| 792 |
results_df_nps = pd.read_csv(csv_output_path_nps)
|
| 793 |
results_df_nps["Importance_percent"] = results_df_nps["Importance"] * 100
|
| 794 |
average_value_nps = results_df_nps["Importance_percent"].mean()
|
| 795 |
+
img_nps = plot_model(
|
| 796 |
results_df_nps,
|
| 797 |
average_value_nps,
|
| 798 |
f"NPS Drivers: {file_name}",
|