Wajahat698 commited on
Commit
f4174ca
·
verified ·
1 Parent(s): ea7a0c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -62
app.py CHANGED
@@ -73,6 +73,7 @@ df_builder_pivot_str = ""
73
 
74
 
75
 
 
76
  def plot_model_results(results_df, average_value, title, model_type):
77
  """
78
  Plot model results with specific orders and colors for Trust and NPS models.
@@ -140,8 +141,8 @@ def plot_model_results(results_df, average_value, title, model_type):
140
 
141
  # Calculate the x-axis limits
142
  half_range = max(average_value - actual_min, actual_max - average_value)
143
- x_min = average_value - half_range - 3 # Adding some padding for text
144
- x_max = average_value + half_range + 3 # Adding some padding for text
145
  plt.xlim(x_min, x_max)
146
 
147
  # Set the x-axis ticks at every 5% interval and add dotted lines
@@ -154,37 +155,26 @@ def plot_model_results(results_df, average_value, title, model_type):
154
  x=tick, color="grey", linestyle="--", linewidth=0.5, zorder=2
155
  ) # Add dotted lines
156
 
157
- # Create bars in the bar chart
158
  for i, row in enumerate(results_df.itertuples(index=False)):
159
  color = color_map[row.Predictor]
160
- if row.Importance_percent < average_value:
161
- # For values less than the average, the bar starts at the value and extends to the average
162
- bar_length = average_value - row.Importance_percent
163
- left_edge = row.Importance_percent
164
- text_x = left_edge - 0.5 # Text to the left of the bar
165
- ha = "right"
166
- else:
167
- # For values greater than the average, the bar starts at the average and extends to the value
168
- bar_length = row.Importance_percent - average_value
169
- left_edge = average_value
170
- text_x = row.Importance_percent + 0.5 # Text to the right of the bar
171
- ha = "left"
172
 
173
  ax.barh(
174
  row.Predictor,
175
- bar_length,
176
- left=left_edge,
177
  color=color,
178
  edgecolor="white",
179
  height=0.6,
180
- zorder=3, # Set zorder to a value higher than the default for lines
181
  )
 
182
  ax.text(
183
- text_x,
184
  i,
185
  f"{row.Importance_percent:.1f}%",
186
  va="center",
187
- ha=ha,
188
  color="#8c8b8c",
189
  )
190
 
@@ -212,12 +202,11 @@ def plot_model_results(results_df, average_value, title, model_type):
212
  plt.close(fig)
213
 
214
  return img
 
215
  except Exception as e:
216
  logger.error("Error plotting model results: %s", e)
217
  raise
218
 
219
-
220
-
221
  def plot_bucket_fullness(driver_df, title):
222
  # Determine required trust buckets
223
  buckets = [
@@ -377,84 +366,113 @@ def call_r_script(
377
 
378
 
379
 
380
- def plot_trust_driver_bubbles(trust_df, title):
 
 
 
 
381
  """
382
- Creates a bubble plot for Trust Drivers using preset positions and colors.
383
-
384
  Args:
385
  trust_df (DataFrame): DataFrame containing Trust driver data with an "Importance_percent" column.
386
  title (str): Title of the plot.
387
-
 
 
388
  Returns:
389
  Image: PIL Image of the bubble plot.
390
  """
391
- # Set the background image path
392
  image_path = "./images/image.png"
393
 
394
- # Load background image
395
  try:
396
- img = Image.open(image_path)
397
  except FileNotFoundError:
398
- raise FileNotFoundError(f"❌ Error: Background image '{image_path}' not found!")
399
 
400
- # Define the fixed bubble order (for Trust Drivers)
401
  bubble_order = ["Vision", "Development", "Benefit", "Competence", "Stability", "Relationship"]
402
 
403
  # Colors for each bubble (in the same order)
404
  colors = ["#DF8859", "#E3B05B", "#418387", "#6D93AB", "#375570", "#C63F48"]
405
 
406
- # Bubble positions (aligned with the background image)
407
- bubble_positions = [
408
- (0.66, 1.20), # Vision Trust (Moved Up)
409
- (1.43, -0.08), # Development Trust (Kept Similar)
410
- (0.66, -1.10), # Benefit Trust (Kept Similar)
411
- (-0.70, -1.20), # Competence Trust (Kept Similar)
412
- (-1.30, -0.08), # Stability Trust (Kept Similar)
413
- (-0.70, 1.15) # Relationship Trust (Shifted Left)
414
- ]
415
-
416
- # Extract importance percentages for each predictor.
417
- # If a predictor is missing, default to 0.
418
  values_dict = trust_df.set_index("Predictor")["Importance_percent"].to_dict()
419
  percentages = [values_dict.get(pred, 0) for pred in bubble_order]
420
 
421
- # Scale bubble sizes dynamically based on the percentages
422
- max_size = 0.30 # Maximum bubble size
423
- min_size = 0.23 # Minimum bubble size
424
- min_value, max_value = min(percentages), max(percentages)
425
- bubble_sizes = [
426
- min_size + (max_size - min_size) * ((p - min_value) / (max_value - min_value + 1e-5))
427
- for p in percentages
428
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
 
430
  # Create the figure and axis
431
- fig, ax = plt.subplots(figsize=(8, 8))
432
  ax.set_xlim(-2, 2)
433
  ax.set_ylim(-2, 2)
434
- ax.set_aspect('equal') # Lock the aspect ratio
435
  ax.axis("off")
436
 
437
- # Display the background image (ensure the extent aligns with your coordinate system)
438
- ax.imshow(img, extent=[-1.5, 1.5, -1.5, 1.5])
 
439
 
440
- # Draw bubbles and add centered percentage text
441
- for i, (x, y) in enumerate(bubble_positions):
442
- size = bubble_sizes[i]
443
- circle = patches.Circle((x, y), size, facecolor=colors[i], alpha=1.0, lw=1.5)
 
444
  ax.add_patch(circle)
445
  ax.text(
446
- x, y, f"{percentages[i]:.1f}%", fontsize=12, fontweight="bold",
447
  ha="center", va="center", color="white"
448
  )
449
 
450
- # Optionally, add a title (if desired)
451
- plt.title(title, fontsize=14)
452
 
453
  # Save the plot to a bytes buffer and return a PIL Image
454
  img_buffer = io.BytesIO()
455
  plt.savefig(img_buffer, format="png", bbox_inches="tight", facecolor=fig.get_facecolor())
456
  img_buffer.seek(0)
457
  plt.close(fig)
 
458
  return Image.open(img_buffer)
459
 
460
 
 
73
 
74
 
75
 
76
+
77
  def plot_model_results(results_df, average_value, title, model_type):
78
  """
79
  Plot model results with specific orders and colors for Trust and NPS models.
 
141
 
142
  # Calculate the x-axis limits
143
  half_range = max(average_value - actual_min, actual_max - average_value)
144
+ x_min = 0 # start from zero
145
+ x_max = actual_max + 5 # a bit beyond max
146
  plt.xlim(x_min, x_max)
147
 
148
  # Set the x-axis ticks at every 5% interval and add dotted lines
 
155
  x=tick, color="grey", linestyle="--", linewidth=0.5, zorder=2
156
  ) # Add dotted lines
157
 
158
+ # Create bars: all from 0 → value (left-to-right only)
159
  for i, row in enumerate(results_df.itertuples(index=False)):
160
  color = color_map[row.Predictor]
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
  ax.barh(
163
  row.Predictor,
164
+ row.Importance_percent,
165
+ left=0,
166
  color=color,
167
  edgecolor="white",
168
  height=0.6,
169
+ zorder=3,
170
  )
171
+
172
  ax.text(
173
+ row.Importance_percent + 0.5,
174
  i,
175
  f"{row.Importance_percent:.1f}%",
176
  va="center",
177
+ ha="left",
178
  color="#8c8b8c",
179
  )
180
 
 
202
  plt.close(fig)
203
 
204
  return img
205
+
206
  except Exception as e:
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 = [
 
366
 
367
 
368
 
369
+
370
+
371
+
372
+
373
+ def plot_trust_driver_bubbles(trust_df, title, bubble_positions=None, gap=-0.2):
374
  """
375
+ Creates a bubble plot for Trust Drivers ensuring that all bubbles are proportionate in size (e.g., 20% is twice the size of 10%)
376
+ and slightly touch the Trust Core without overlapping.
377
  Args:
378
  trust_df (DataFrame): DataFrame containing Trust driver data with an "Importance_percent" column.
379
  title (str): Title of the plot.
380
+ trust_core_image_path (str): Path to the image to be placed inside the Trust Core circle.
381
+ bubble_positions (dict, optional): Dictionary specifying manual positions for each trust driver.
382
+ gap (float): Small gap adjustment to fine-tune bubble placement.
383
  Returns:
384
  Image: PIL Image of the bubble plot.
385
  """
386
+ # Load Trust Core image
387
  image_path = "./images/image.png"
388
 
389
+
390
  try:
391
+ trust_core_img = Image.open(image_path)
392
  except FileNotFoundError:
393
+ raise FileNotFoundError(f"❌ Error: Trust Core image '{trust_core_img}' not found!")
394
 
395
+ # Define the Trust Drivers
396
  bubble_order = ["Vision", "Development", "Benefit", "Competence", "Stability", "Relationship"]
397
 
398
  # Colors for each bubble (in the same order)
399
  colors = ["#DF8859", "#E3B05B", "#418387", "#6D93AB", "#375570", "#C63F48"]
400
 
401
+ # Extract importance percentages (default to 0 if missing)
 
 
 
 
 
 
 
 
 
 
 
402
  values_dict = trust_df.set_index("Predictor")["Importance_percent"].to_dict()
403
  percentages = [values_dict.get(pred, 0) for pred in bubble_order]
404
 
405
+ # Scale bubble sizes proportionally (e.g., 20% should be twice the size of 10%)
406
+ min_radius = 0.15 # Set minimum bubble size to 0.18
407
+ base_percentage = min(percentages) if min(percentages) > 0 else 1 # Prevent division by zero
408
+ #bubble_radii = [min_radius * (p / base_percentage) ** 0.5 for p in percentages] # Area-based scaling
409
+ import math
410
+
411
+ bubble_radii = [
412
+ min_radius * (p / base_percentage) ** 0.75 # 0.7–0.8 range is ideal
413
+ for p in percentages]
414
+
415
+ # Central circle radius (Trust Core)
416
+ central_radius = 0.8
417
+
418
+ #Default positions ensuring bubbles slightly touch the Trust Core
419
+ default_positions = {
420
+ "Vision": (0.6, 0.85),
421
+ "Development": (1.05, 0.0),
422
+ "Benefit": (0.6, -0.85),
423
+ "Competence": (-0.6, -0.85),
424
+ "Stability": (-1.05, 0.0),
425
+ "Relationship": (-0.6, 0.85)
426
+ }
427
+
428
+ # Use user-defined positions if provided, else default positions
429
+ bubble_positions = bubble_positions if bubble_positions else default_positions
430
+
431
+ # Adjust positions dynamically based on bubble sizes to ensure touching Trust Core
432
+ # for i, trust_driver in enumerate(bubble_order):
433
+ # x, y = bubble_positions[trust_driver]
434
+ # bubble_radius = bubble_radii[i]
435
+ # scale_factor = (central_radius + bubble_radius + gap) / np.sqrt(x**2 + y**2)
436
+ # bubble_positions[trust_driver] = (x * scale_factor, y * scale_factor)
437
+ for i, trust_driver in enumerate(bubble_order):
438
+ x, y = bubble_positions[trust_driver]
439
+ bubble_radius = bubble_radii[i]
440
+ distance_to_core = np.sqrt(x**2 + y**2)
441
+ scale_factor = (central_radius + bubble_radius + gap) / distance_to_core
442
+ bubble_positions[trust_driver] = (x * scale_factor, y * scale_factor)
443
+
444
 
445
  # Create the figure and axis
446
+ fig, ax = plt.subplots(figsize=(10, 10), dpi=300) # Increased resolution
447
  ax.set_xlim(-2, 2)
448
  ax.set_ylim(-2, 2)
449
+ ax.set_aspect('equal') # Lock aspect ratio
450
  ax.axis("off")
451
 
452
+ # Draw Trust Core image inside the central circle
453
+ extent = [-central_radius, central_radius, -central_radius, central_radius] # Trust Core image size
454
+ ax.imshow(trust_core_img, extent=extent, alpha=1.0)
455
 
456
+ # Draw bubbles ensuring they only touch but do not overlap
457
+ for i, trust_driver in enumerate(bubble_order):
458
+ x, y = bubble_positions[trust_driver]
459
+ radius = bubble_radii[i]
460
+ circle = patches.Circle((x, y), radius, facecolor=colors[i], alpha=1.0, lw=1.5)
461
  ax.add_patch(circle)
462
  ax.text(
463
+ x, y, f"{percentages[i]:.1f}%", fontsize=10, fontweight="bold",
464
  ha="center", va="center", color="white"
465
  )
466
 
467
+ # Add title
468
+ plt.title(title, fontsize=12)
469
 
470
  # Save the plot to a bytes buffer and return a PIL Image
471
  img_buffer = io.BytesIO()
472
  plt.savefig(img_buffer, format="png", bbox_inches="tight", facecolor=fig.get_facecolor())
473
  img_buffer.seek(0)
474
  plt.close(fig)
475
+
476
  return Image.open(img_buffer)
477
 
478