Social-Sphere / graphs.py
BlakeL's picture
Upload graphs.py
b5127dd verified
import matplotlib.pyplot as plt
import numpy as np
import io
import base64
# Pie chart for conflict prediction
def create_conflict_pie_chart(result):
fig, ax = plt.subplots(figsize=(3, 2))
# Handle missing confidence
if 'confidence' in result and result['confidence'] is not None:
confidence = result['confidence']
else:
confidence = 0.8 # Default confidence when not available
if result['conflict_level'] == 'High Risk':
colors = ['#ff6b6b', '#4ecdc4']
sizes = [confidence, 1 - confidence]
labels = ['High Risk', 'Low Risk']
else:
colors = ['#4ecdc4', '#ff6b6b']
sizes = [confidence, 1 - confidence]
labels = ['Low Risk', 'High Risk']
wedges, texts, autotexts = ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
startangle=90, explode=(0.1, 0))
# Update title to handle missing confidence
if 'confidence' in result and result['confidence'] is not None:
title = f'Conflict Risk Prediction\nConfidence: {confidence:.1%}'
else:
title = f'Conflict Risk Prediction\nConfidence: {confidence:.1%} (estimated)'
ax.set_title(title, fontsize=10, fontweight='bold', pad=10)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
ax.legend(wedges, labels, title="Risk Levels", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
plt.tight_layout()
img_buffer = io.BytesIO()
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
img_buffer.seek(0)
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
plt.close()
return f"data:image/png;base64,{img_base64}"
# Histogram for addiction score (not currently used, but included for completeness)
def create_addiction_score_chart(result, data=None):
fig, ax = plt.subplots(figsize=(3, 2))
if data is not None and 'Addicted_Score' in data.columns:
scores = data['Addicted_Score'].dropna()
else:
np.random.seed(42)
scores = np.random.normal(5.5, 1.5, 1000)
scores = np.clip(scores, 1, 10)
n, bins, patches = ax.hist(scores, bins=20, alpha=0.7, color='#4ecdc4',
edgecolor='black', linewidth=0.5)
predicted_score = result['predicted_score']
ax.axvline(x=predicted_score, color='#ff6b6b', linewidth=3,
label=f'Your Prediction: {predicted_score:.2f}')
if 'confidence' in result:
confidence = result['confidence']
ax.axvspan(predicted_score - 0.5, predicted_score + 0.5,
alpha=0.3, color='#ff6b6b',
label=f'Confidence: {confidence:.2f}')
ax.set_title('Addiction Score Distribution with Your Prediction',
fontsize=10, fontweight='bold', pad=10)
ax.set_xlabel('Addiction Score (1-10)', fontsize=8, fontweight='bold')
ax.set_ylabel('Frequency', fontsize=8, fontweight='bold')
ax.axvspan(1, 3, alpha=0.2, color='green', label='Low Addiction (1-3)')
ax.axvspan(3, 7, alpha=0.2, color='orange', label='Moderate Addiction (3-7)')
ax.axvspan(7, 10, alpha=0.2, color='red', label='High Addiction (7-10)')
ax.legend(loc='upper right', fontsize=7)
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 10)
plt.tight_layout()
img_buffer = io.BytesIO()
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
img_buffer.seek(0)
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
plt.close()
return f"data:image/png;base64,{img_base64}"
# Gauge chart for addiction score
def create_addiction_gauge_chart(result):
fig, ax = plt.subplots(figsize=(3, 2), subplot_kw={'projection': 'polar'})
predicted_score = result['predicted_score']
angle = (predicted_score - 1) * 20
theta = np.linspace(0, np.pi, 100)
# Reduce black line thickness by 30% (from 3 to 2.1)
ax.plot(theta, [1]*100, 'k-', linewidth=2.1)
# Flip colors over y-axis - now high scores are on the left (0) and low scores on the right (pi)
high_angle = np.linspace(0, 2*20*np.pi/180, 50)
ax.fill_between(high_angle, 0, 1, alpha=0.3, color='red', label='High (7-10)')
mod_angle = np.linspace(2*20*np.pi/180, 6*20*np.pi/180, 50)
ax.fill_between(mod_angle, 0, 1, alpha=0.3, color='orange', label='Moderate (3-7)')
low_angle = np.linspace(6*20*np.pi/180, np.pi, 50)
ax.fill_between(low_angle, 0, 1, alpha=0.3, color='green', label='Low (1-3)')
needle_angle = angle * np.pi / 180
# Reduce needle line thickness by 30% (from 4 to 2.8)
ax.plot([needle_angle, needle_angle], [0, 1.2], 'k-', linewidth=2.8, label=f'Your Score: {predicted_score:.1f}')
# Reduce round dot size by 50% (from 10 to 5)
ax.plot(needle_angle, 1.2, 'ko', markersize=5, markeredgecolor='white', markeredgewidth=2)
ax.set_title(f'Addiction Score Gauge\nPredicted: {predicted_score:.1f}/10',
fontsize=8, fontweight='bold', pad=10)
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylim(0, 1.3)
# Flip the gauge by adjusting text positions and angles
ax.text(np.pi, 1.4, 'Low\n(1-3)', ha='center', va='center', fontsize=3, fontweight='bold')
ax.text(np.pi/2, 1.4, 'Moderate\n(3-7)', ha='center', va='center', fontsize=3, fontweight='bold')
ax.text(0, 1.4, 'High\n(7-10)', ha='center', va='center', fontsize=3, fontweight='bold')
if 'confidence' in result:
confidence = result['confidence']
ax.text(0, -0.3, f'Confidence: {confidence:.2f}', ha='center', va='center',
fontsize=6, fontweight='bold', bbox=dict(boxstyle="round,pad=0.3", facecolor="lightblue"))
plt.tight_layout()
img_buffer = io.BytesIO()
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
img_buffer.seek(0)
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
plt.close()
return f"data:image/png;base64,{img_base64}"
# Clustering: Elbow and Sleep vs Age scatter plot
def create_clustering_charts(result, cluster_df=None, user_sleep=None, user_age=None, user_cluster=None, cluster_labels_map=None):
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
optimal_k = 3
k_values = range(1, 11)
inertias = [150, 120, 85, 65, 55, 50, 47, 45, 43, 42]
ax1.plot(k_values, inertias, 'bo-', linewidth=2, markersize=8)
ax1.set_xlabel('Number of Clusters (k)', fontweight='bold')
ax1.set_ylabel('Inertia', fontweight='bold')
ax1.set_title('Elbow Method: Optimal K Selection', fontsize=12, fontweight='bold')
ax1.grid(True, alpha=0.3)
ax1.axvline(x=optimal_k, color='red', linestyle='--', alpha=0.7, label=f'Optimal k = {optimal_k}')
ax1.legend()
# Scatter plot: Sleep vs Age colored by cluster (always 3 clusters/colors)
if cluster_df is not None and cluster_labels_map is not None:
colors = ['#4ecdc4', '#ffd93d', '#ff6b6b']
for cluster in range(optimal_k):
sub = cluster_df[cluster_df['cluster'] == cluster]
color = colors[cluster % len(colors)]
label = cluster_labels_map.get(cluster, f'Cluster {cluster}')
ax2.scatter(sub['Sleep_Hours_Per_Night'], sub['Age'], c=color, alpha=0.7, s=50, label=label)
# Highlight the user's point
if user_sleep is not None and user_age is not None and user_cluster is not None:
color = colors[user_cluster % len(colors)]
ax2.scatter([user_sleep], [user_age], c='red', marker='*', s=250, edgecolors='black', linewidths=2, label='You')
ax2.set_xlabel('Sleep Hours per Night', fontweight='bold')
ax2.set_ylabel('Age', fontweight='bold')
ax2.set_title(f'Cluster Analysis: Sleep vs Age (k={optimal_k})', fontsize=12, fontweight='bold')
handles, labels = ax2.get_legend_handles_labels()
# Remove duplicate 'You' label if present
seen = set()
new_handles, new_labels = [], []
for h, l in zip(handles, labels):
if l not in seen:
new_handles.append(h)
new_labels.append(l)
seen.add(l)
ax2.legend(new_handles, new_labels)
ax2.grid(True, alpha=0.3)
plt.tight_layout()
img_buffer = io.BytesIO()
plt.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight')
img_buffer.seek(0)
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
plt.close()
return f"data:image/png;base64,{img_base64}"