vorniity-rescraper-api / result_analyzer.py
KindAlien's picture
Upload 32 files
3301039 verified
Raw
History Blame Contribute Delete
5.18 kB
import pandas as pd
import matplotlib.pyplot as plt
from io import BytesIO
def analyze_results(input_file):
"""
Analyzes a VTU result Excel file with multi-level headers.
Args:
input_file: A file path or a file-like object (e.g., from a file uploader).
Returns:
BytesIO: An in-memory Excel file containing the analysis report.
"""
try:
# Step 1: Read the Excel file, telling pandas the first two rows are the header.
# This creates a MultiIndex for the columns.
df = pd.read_excel(input_file, header=[0, 1])
# Step 2: Clean and flatten the multi-level column headers.
# e.g., ('BCS401', 'IA') becomes 'BCS401_IA'
# e.g., ('Class', 'Unnamed: ...') becomes 'Class'
new_cols = []
for col in df.columns:
if 'Unnamed' in str(col[1]):
# This handles single-level headers like 'USN', 'Name', 'Class'
new_cols.append(col[0])
else:
# This joins multi-level headers like ('BCS401', 'Pass/Fail')
new_cols.append(f"{col[0]}_{col[1]}")
df.columns = new_cols
except Exception as e:
raise ValueError(f"Could not read the Excel file. Please ensure it has the correct two-level header format. Error: {e}")
# --- 1. Analyze Pass Percentage for Each Subject ---
analysis_data = []
total_students = len(df)
# Find all columns that represent a subject's pass/fail status
pass_fail_columns = [col for col in df.columns if col.endswith('_Pass/Fail')]
if not pass_fail_columns:
raise ValueError("Could not find any 'Pass/Fail' columns. Please check the Excel file headers.")
for pf_col in pass_fail_columns:
# Extract subject code from the column name (e.g., 'BCS401_Pass/Fail' -> 'BCS401')
subject_code = pf_col.split('_')[0]
pass_count = (df[pf_col] == 'P').sum()
pass_percentage = (pass_count / total_students) * 100 if total_students > 0 else 0
analysis_data.append({
"Subject": subject_code,
"Total Students": total_students,
"Pass Count": pass_count,
"Pass Percentage": f"{pass_percentage:.2f}%"
})
pass_percentage_df = pd.DataFrame(analysis_data)
pass_percentage_df['Pass Percentage (Numeric)'] = pass_percentage_df['Pass Percentage'].str.replace('%', '').astype(float)
# --- 2. Analyze Class Distribution ---
# This part will now work because the 'Class' column is correctly identified.
class_distribution = df['Class'].value_counts().reset_index()
class_distribution.columns = ['Class', 'Number of Students']
# --- 3. Create Charts in Memory (No changes needed here) ---
# Bar Chart for Pass Percentage
plt.figure(figsize=(10, 6))
bars = plt.bar(pass_percentage_df['Subject'], pass_percentage_df['Pass Percentage (Numeric)'], color='skyblue')
plt.title('Pass Percentage per Subject', fontsize=16)
plt.ylabel('Pass Percentage (%)', fontsize=12)
plt.xlabel('Subject', fontsize=12)
plt.xticks(rotation=45, ha='right')
plt.ylim(0, 105)
plt.grid(axis='y', linestyle='--', alpha=0.7)
for bar in bars:
yval = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2.0, yval + 1, f'{yval:.1f}%', ha='center', va='bottom')
plt.tight_layout()
bar_chart_buffer = BytesIO()
plt.savefig(bar_chart_buffer, format='png')
plt.close()
# Pie Chart for Class Distribution
plt.figure(figsize=(8, 8))
plt.pie(
class_distribution['Number of Students'],
labels=class_distribution['Class'],
autopct='%1.1f%%',
startangle=140,
colors=['#66b3ff','#ff9999','#99ff99','#ffcc99']
)
plt.title('Overall Class Distribution', fontsize=16)
plt.axis('equal')
pie_chart_buffer = BytesIO()
plt.savefig(pie_chart_buffer, format='png')
plt.close()
# --- 4. Write Everything to an In-Memory Excel File (No changes needed here) ---
output_buffer = BytesIO()
with pd.ExcelWriter(output_buffer, engine='openpyxl') as writer:
pass_percentage_df[['Subject', 'Total Students', 'Pass Count', 'Pass Percentage']].to_excel(
writer, sheet_name='Dashboard', startrow=1, index=False
)
class_distribution.to_excel(
writer, sheet_name='Dashboard', startrow=1, startcol=6, index=False
)
workbook = writer.book
worksheet = writer.sheets['Dashboard']
worksheet['A1'] = "Subject Pass/Fail Analysis"
worksheet['G1'] = "Class Distribution"
from openpyxl.drawing.image import Image
bar_chart_img = Image(bar_chart_buffer)
worksheet.add_image(bar_chart_img, 'A10')
pie_chart_img = Image(pie_chart_buffer)
worksheet.add_image(pie_chart_img, 'J10')
# We will write the cleaned data back to the report
df.to_excel(writer, sheet_name='Raw Data', index=False)
output_buffer.seek(0)
return output_buffer