Spaces:
Runtime error
Runtime error
Upload 2 files
Browse files
graphs.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import matplotlib.pyplot as plt
|
| 2 |
+
import numpy as np
|
| 3 |
+
import io
|
| 4 |
+
import base64
|
| 5 |
+
|
| 6 |
+
# Pie chart for conflict prediction
|
| 7 |
+
|
| 8 |
+
def create_conflict_pie_chart(result):
|
| 9 |
+
fig, ax = plt.subplots(figsize=(3, 2))
|
| 10 |
+
if result['conflict_level'] == 'High Risk':
|
| 11 |
+
colors = ['#ff6b6b', '#4ecdc4']
|
| 12 |
+
sizes = [result['confidence'], 1 - result['confidence']]
|
| 13 |
+
labels = ['High Risk', 'Low Risk']
|
| 14 |
+
else:
|
| 15 |
+
colors = ['#4ecdc4', '#ff6b6b']
|
| 16 |
+
sizes = [result['confidence'], 1 - result['confidence']]
|
| 17 |
+
labels = ['Low Risk', 'High Risk']
|
| 18 |
+
wedges, texts, autotexts = ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
|
| 19 |
+
startangle=90, explode=(0.1, 0))
|
| 20 |
+
ax.set_title(f'Conflict Risk Prediction\nConfidence: {result["confidence"]:.1%}',
|
| 21 |
+
fontsize=10, fontweight='bold', pad=10)
|
| 22 |
+
for autotext in autotexts:
|
| 23 |
+
autotext.set_color('white')
|
| 24 |
+
autotext.set_fontweight('bold')
|
| 25 |
+
ax.legend(wedges, labels, title="Risk Levels", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
|
| 26 |
+
plt.tight_layout()
|
| 27 |
+
img_buffer = io.BytesIO()
|
| 28 |
+
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
|
| 29 |
+
img_buffer.seek(0)
|
| 30 |
+
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
|
| 31 |
+
plt.close()
|
| 32 |
+
return f"data:image/png;base64,{img_base64}"
|
| 33 |
+
|
| 34 |
+
# Histogram for addiction score (not currently used, but included for completeness)
|
| 35 |
+
def create_addiction_score_chart(result, data=None):
|
| 36 |
+
fig, ax = plt.subplots(figsize=(3, 2))
|
| 37 |
+
if data is not None and 'Addicted_Score' in data.columns:
|
| 38 |
+
scores = data['Addicted_Score'].dropna()
|
| 39 |
+
else:
|
| 40 |
+
np.random.seed(42)
|
| 41 |
+
scores = np.random.normal(5.5, 1.5, 1000)
|
| 42 |
+
scores = np.clip(scores, 1, 10)
|
| 43 |
+
n, bins, patches = ax.hist(scores, bins=20, alpha=0.7, color='#4ecdc4',
|
| 44 |
+
edgecolor='black', linewidth=0.5)
|
| 45 |
+
predicted_score = result['predicted_score']
|
| 46 |
+
ax.axvline(x=predicted_score, color='#ff6b6b', linewidth=3,
|
| 47 |
+
label=f'Your Prediction: {predicted_score:.2f}')
|
| 48 |
+
if 'confidence' in result:
|
| 49 |
+
confidence = result['confidence']
|
| 50 |
+
ax.axvspan(predicted_score - 0.5, predicted_score + 0.5,
|
| 51 |
+
alpha=0.3, color='#ff6b6b',
|
| 52 |
+
label=f'Confidence: {confidence:.2f}')
|
| 53 |
+
ax.set_title('Addiction Score Distribution with Your Prediction',
|
| 54 |
+
fontsize=10, fontweight='bold', pad=10)
|
| 55 |
+
ax.set_xlabel('Addiction Score (1-10)', fontsize=8, fontweight='bold')
|
| 56 |
+
ax.set_ylabel('Frequency', fontsize=8, fontweight='bold')
|
| 57 |
+
ax.axvspan(1, 3, alpha=0.2, color='green', label='Low Addiction (1-3)')
|
| 58 |
+
ax.axvspan(3, 7, alpha=0.2, color='orange', label='Moderate Addiction (3-7)')
|
| 59 |
+
ax.axvspan(7, 10, alpha=0.2, color='red', label='High Addiction (7-10)')
|
| 60 |
+
ax.legend(loc='upper right', fontsize=7)
|
| 61 |
+
ax.grid(True, alpha=0.3)
|
| 62 |
+
ax.set_xlim(0, 10)
|
| 63 |
+
plt.tight_layout()
|
| 64 |
+
img_buffer = io.BytesIO()
|
| 65 |
+
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
|
| 66 |
+
img_buffer.seek(0)
|
| 67 |
+
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
|
| 68 |
+
plt.close()
|
| 69 |
+
return f"data:image/png;base64,{img_base64}"
|
| 70 |
+
|
| 71 |
+
# Gauge chart for addiction score
|
| 72 |
+
def create_addiction_gauge_chart(result):
|
| 73 |
+
fig, ax = plt.subplots(figsize=(3, 2), subplot_kw={'projection': 'polar'})
|
| 74 |
+
predicted_score = result['predicted_score']
|
| 75 |
+
angle = (predicted_score - 1) * 20
|
| 76 |
+
theta = np.linspace(0, np.pi, 100)
|
| 77 |
+
ax.plot(theta, [1]*100, 'k-', linewidth=3)
|
| 78 |
+
low_angle = np.linspace(0, 2*20*np.pi/180, 50)
|
| 79 |
+
ax.fill_between(low_angle, 0, 1, alpha=0.3, color='green', label='Low (1-3)')
|
| 80 |
+
mod_angle = np.linspace(2*20*np.pi/180, 6*20*np.pi/180, 50)
|
| 81 |
+
ax.fill_between(mod_angle, 0, 1, alpha=0.3, color='orange', label='Moderate (3-7)')
|
| 82 |
+
high_angle = np.linspace(6*20*np.pi/180, np.pi, 50)
|
| 83 |
+
ax.fill_between(high_angle, 0, 1, alpha=0.3, color='red', label='High (7-10)')
|
| 84 |
+
needle_angle = angle * np.pi / 180
|
| 85 |
+
ax.plot([needle_angle, needle_angle], [0, 1.2], 'k-', linewidth=4, label=f'Your Score: {predicted_score:.1f}')
|
| 86 |
+
ax.plot(needle_angle, 1.2, 'ko', markersize=10, markeredgecolor='white', markeredgewidth=2)
|
| 87 |
+
ax.set_title(f'Addiction Score Gauge\nPredicted: {predicted_score:.1f}/10',
|
| 88 |
+
fontsize=10, fontweight='bold', pad=10)
|
| 89 |
+
ax.set_xticks([])
|
| 90 |
+
ax.set_yticks([])
|
| 91 |
+
ax.set_ylim(0, 1.3)
|
| 92 |
+
ax.text(0, 1.4, 'Low\n(1-3)', ha='center', va='center', fontsize=8, fontweight='bold')
|
| 93 |
+
ax.text(np.pi/2, 1.4, 'Moderate\n(3-7)', ha='center', va='center', fontsize=8, fontweight='bold')
|
| 94 |
+
ax.text(np.pi, 1.4, 'High\n(7-10)', ha='center', va='center', fontsize=8, fontweight='bold')
|
| 95 |
+
if 'confidence' in result:
|
| 96 |
+
confidence = result['confidence']
|
| 97 |
+
ax.text(0, -0.3, f'Confidence: {confidence:.2f}', ha='center', va='center',
|
| 98 |
+
fontsize=8, fontweight='bold', bbox=dict(boxstyle="round,pad=0.3", facecolor="lightblue"))
|
| 99 |
+
plt.tight_layout()
|
| 100 |
+
img_buffer = io.BytesIO()
|
| 101 |
+
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
|
| 102 |
+
img_buffer.seek(0)
|
| 103 |
+
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
|
| 104 |
+
plt.close()
|
| 105 |
+
return f"data:image/png;base64,{img_base64}"
|
| 106 |
+
|
| 107 |
+
# Clustering: Elbow and Sleep vs Age scatter plot
|
| 108 |
+
def create_clustering_charts(result, cluster_df=None, user_sleep=None, user_age=None, user_cluster=None, cluster_labels_map=None):
|
| 109 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
|
| 110 |
+
optimal_k = 3
|
| 111 |
+
k_values = range(1, 11)
|
| 112 |
+
inertias = [150, 120, 85, 65, 55, 50, 47, 45, 43, 42]
|
| 113 |
+
ax1.plot(k_values, inertias, 'bo-', linewidth=2, markersize=8)
|
| 114 |
+
ax1.set_xlabel('Number of Clusters (k)', fontweight='bold')
|
| 115 |
+
ax1.set_ylabel('Inertia', fontweight='bold')
|
| 116 |
+
ax1.set_title('Elbow Method: Optimal K Selection', fontsize=12, fontweight='bold')
|
| 117 |
+
ax1.grid(True, alpha=0.3)
|
| 118 |
+
ax1.axvline(x=optimal_k, color='red', linestyle='--', alpha=0.7, label=f'Optimal k = {optimal_k}')
|
| 119 |
+
ax1.legend()
|
| 120 |
+
# Scatter plot: Sleep vs Age colored by cluster (always 3 clusters/colors)
|
| 121 |
+
if cluster_df is not None and cluster_labels_map is not None:
|
| 122 |
+
colors = ['#4ecdc4', '#ffd93d', '#ff6b6b']
|
| 123 |
+
for cluster in range(optimal_k):
|
| 124 |
+
sub = cluster_df[cluster_df['cluster'] == cluster]
|
| 125 |
+
color = colors[cluster % len(colors)]
|
| 126 |
+
label = cluster_labels_map.get(cluster, f'Cluster {cluster}')
|
| 127 |
+
ax2.scatter(sub['Sleep_Hours_Per_Night'], sub['Age'], c=color, alpha=0.7, s=50, label=label)
|
| 128 |
+
# Highlight the user's point
|
| 129 |
+
if user_sleep is not None and user_age is not None and user_cluster is not None:
|
| 130 |
+
color = colors[user_cluster % len(colors)]
|
| 131 |
+
ax2.scatter([user_sleep], [user_age], c='red', marker='*', s=250, edgecolors='black', linewidths=2, label='You')
|
| 132 |
+
ax2.set_xlabel('Sleep Hours per Night', fontweight='bold')
|
| 133 |
+
ax2.set_ylabel('Age', fontweight='bold')
|
| 134 |
+
ax2.set_title(f'Cluster Analysis: Sleep vs Age (k={optimal_k})', fontsize=12, fontweight='bold')
|
| 135 |
+
handles, labels = ax2.get_legend_handles_labels()
|
| 136 |
+
# Remove duplicate 'You' label if present
|
| 137 |
+
seen = set()
|
| 138 |
+
new_handles, new_labels = [], []
|
| 139 |
+
for h, l in zip(handles, labels):
|
| 140 |
+
if l not in seen:
|
| 141 |
+
new_handles.append(h)
|
| 142 |
+
new_labels.append(l)
|
| 143 |
+
seen.add(l)
|
| 144 |
+
ax2.legend(new_handles, new_labels)
|
| 145 |
+
ax2.grid(True, alpha=0.3)
|
| 146 |
+
plt.tight_layout()
|
| 147 |
+
img_buffer = io.BytesIO()
|
| 148 |
+
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
|
| 149 |
+
img_buffer.seek(0)
|
| 150 |
+
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
|
| 151 |
+
plt.close()
|
| 152 |
+
return f"data:image/png;base64,{img_base64}"
|