import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.styles.differential import DifferentialStyle
from openpyxl.formatting.rule import Rule, FormulaRule
from openpyxl.chart import BarChart, PieChart, Reference
from openpyxl.chart.label import DataLabelList
from openpyxl.chart.series import DataPoint
from openpyxl.worksheet.datavalidation import DataValidation
from openpyxl.utils import get_column_letter
from openpyxl.drawing.image import Image
import datetime
import os
def create_class_assessment_tool(output_file="Class_Assessment_Tool.xlsx"):
"""Create an Excel class assessment tool with three sheets for data entry,
analysis, and dashboard."""
# Create a new workbook
wb = openpyxl.Workbook()
# Create sheets
mark_sheet = wb.active
mark_sheet.title = "Mark Schedule"
summary_sheet = wb.create_sheet("Summary Analysis")
dashboard_sheet = wb.create_sheet("Dashboard")
# Set up Mark Schedule sheet
setup_mark_schedule(mark_sheet)
# Set up Summary Analysis sheet
setup_summary_analysis(summary_sheet, mark_sheet)
# Set up Dashboard sheet
setup_dashboard(dashboard_sheet, mark_sheet, summary_sheet)
# Apply general workbook formatting and settings
for sheet in wb.sheetnames:
wb[sheet].sheet_properties.tabColor = "1072BA"
# Add documentation sheet
instruction_sheet = wb.create_sheet("Instructions", 0)
setup_instructions(instruction_sheet)
# Save the workbook
wb.save(output_file)
print(f"Excel assessment tool created successfully: {output_file}")
return output_file
def setup_mark_schedule(ws):
"""Set up the Mark Schedule sheet with headers, formulas, and formatting."""
# Set column widths
ws.column_dimensions['A'].width = 5 # SN
ws.column_dimensions['B'].width = 30 # Name
ws.column_dimensions['C'].width = 8 # Sex
ws.column_dimensions['D'].width = 15 # Assessment 1
ws.column_dimensions['E'].width = 15 # Assessment 2
ws.column_dimensions['F'].width = 15 # Assessment 3
ws.column_dimensions['G'].width = 15 # Average
ws.column_dimensions['H'].width = 12 # Grade
ws.column_dimensions['I'].width = 18 # Remark
# Add title
ws.merge_cells('A1:I1')
ws['A1'] = "CLASS ASSESSMENT RECORD"
ws['A1'].font = Font(size=16, bold=True)
ws['A1'].alignment = Alignment(horizontal='center', vertical='center')
ws.row_dimensions[1].height = 30
# Add subtitle with date
ws.merge_cells('A2:I2')
ws['A2'] = f"Generated on: {datetime.datetime.now().strftime('%Y-%m-%d')}"
ws['A2'].font = Font(size=10, italic=True)
ws['A2'].alignment = Alignment(horizontal='center')
# Set up headers
headers = ["SN", "Name", "Sex", "Assessment 1", "Assessment 2", "Assessment 3",
"Average", "Grade", "Remark"]
for col, header in enumerate(headers, 1):
cell = ws.cell(row=4, column=col)
cell.value = header
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3",
fill_type="solid")
# Add thin borders to header
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'),
top=Side(style='thin'), bottom=Side(style='thin'))
for row in ws.iter_rows(min_row=4, max_row=4, min_col=1, max_col=9):
for cell in row:
cell.border = thin_border
# Add data validation for gender (Sex) column
gender_validation = DataValidation(type="list", formula1='"M,F"',
allow_blank=True)
gender_validation.add('C5:C104') # Apply to rows 5-104
ws.add_data_validation(gender_validation)
# Add data validation for assessment scores (0-100)
score_validation = DataValidation(type="decimal", formula1='0', formula2='100',
operator='between', allow_blank=True)
score_validation.add('D5:F104') # Apply to all three assessment columns
ws.add_data_validation(score_validation)
# Auto-generate SN and add formulas for 100 students
for row in range(5, 105): # Rows 5-104 (100 students)
# SN
ws.cell(row=row, column=1).value = row - 4
ws.cell(row=row, column=1).alignment = Alignment(horizontal='center')
# Add formulas
# Average formula
avg_cell = ws.cell(row=row, column=7)
avg_cell.value = f'=IF(COUNTA(D{row}:F{row})=0,"",AVERAGE(D{row}:F{row}))'
avg_cell.number_format = '0.00'
# Grade formula
grade_cell = ws.cell(row=row, column=8)
grade_cell.value =
(f'=IF(G{row}="","",IF(G{row}>=75,"ONE",IF(G{row}>=70,"TWO",'
f'IF(G{row}>=65,"THREE",IF(G{row}>=60,"FOUR",IF(G{row}>=55,"FIVE",'
f'IF(G{row}>=50,"SIX",IF(G{row}>=45,"SEVEN",IF(G{row}>=40,"EIGHT",'
f'IF(G{row}>=0,"NINE","X"))))))))))')
# Remark formula
remark_cell = ws.cell(row=row, column=9)
remark_cell.value =
(f'=IF(H{row}="","",IF(H{row}="X","ABSENT",IF(H{row}="NINE","UNSATISFACTORY",'
f'IF(OR(H{row}="SEVEN",H{row}="EIGHT"),"SATISFACTORY",'
f'IF(OR(H{row}="FIVE",H{row}="SIX"),"CREDIT",'
f'IF(OR(H{row}="THREE",H{row}="FOUR"),"MERIT","DISTINCTION"))))))')
# Add borders to all cells in the row
for col in range(1, 10):
ws.cell(row=row, column=col).border = thin_border
# Add conditional formatting for grades
# Define colors for different grades
colors = {
'DISTINCTION': 'A7C942', # Green for ONE-TWO (DISTINCTION)
'MERIT': 'FFEB9C', # Yellow for THREE-FOUR (MERIT)
'CREDIT': 'ADD8E6', # Light Blue for FIVE-SIX (CREDIT)
'SATISFACTORY': 'D8D8D8', # Light Gray for SEVEN-EIGHT (SATISFACTORY)
'UNSATISFACTORY': 'FF9999', # Light Red for NINE (UNSATISFACTORY)
'ABSENT': 'C0C0C0' # Gray for X (ABSENT)
}
# Apply conditional formatting to grade column
ws.conditional_formatting.add(f'H5:H104',
FormulaRule(formula=['OR(H5="ONE",H5="TWO")'],
fill=PatternFill(start_color=colors['DISTINCTION'],
end_color=colors['DISTINCTION'],
fill_type='solid')))
ws.conditional_formatting.add(f'H5:H104',
FormulaRule(formula=['OR(H5="THREE",H5="FOUR")'],
fill=PatternFill(start_color=colors['MERIT'],
end_color=colors['MERIT'],
fill_type='solid')))
ws.conditional_formatting.add(f'H5:H104',
FormulaRule(formula=['OR(H5="FIVE",H5="SIX")'],
fill=PatternFill(start_color=colors['CREDIT'],
end_color=colors['CREDIT'],
fill_type='solid')))
ws.conditional_formatting.add(f'H5:H104',
FormulaRule(formula=['OR(H5="SEVEN",H5="EIGHT")'],
fill=PatternFill(start_color=colors['SATISFACTORY'],
end_color=colors['SATISFACTORY'],
fill_type='solid')))
ws.conditional_formatting.add(f'H5:H104',
FormulaRule(formula=['H5="NINE"'],
fill=PatternFill(start_color=colors['UNSATISFACTORY'],
end_color=colors['UNSATISFACTORY'],
fill_type='solid')))
ws.conditional_formatting.add(f'H5:H104',
FormulaRule(formula=['H5="X"'],
fill=PatternFill(start_color=colors['ABSENT'],
end_color=colors['ABSENT'],
fill_type='solid')))
# Also apply same conditional formatting to remark column
ws.conditional_formatting.add(f'I5:I104',
FormulaRule(formula=['I5="DISTINCTION"'],
fill=PatternFill(start_color=colors['DISTINCTION'],
end_color=colors['DISTINCTION'],
fill_type='solid')))
ws.conditional_formatting.add(f'I5:I104',
FormulaRule(formula=['I5="MERIT"'],
fill=PatternFill(start_color=colors['MERIT'],
end_color=colors['MERIT'],
fill_type='solid')))
ws.conditional_formatting.add(f'I5:I104',
FormulaRule(formula=['I5="CREDIT"'],
fill=PatternFill(start_color=colors['CREDIT'],
end_color=colors['CREDIT'],
fill_type='solid')))
ws.conditional_formatting.add(f'I5:I104',
FormulaRule(formula=['I5="SATISFACTORY"'],
fill=PatternFill(start_color=colors['SATISFACTORY'],
end_color=colors['SATISFACTORY'],
fill_type='solid')))
ws.conditional_formatting.add(f'I5:I104',
FormulaRule(formula=['I5="UNSATISFACTORY"'],
fill=PatternFill(start_color=colors['UNSATISFACTORY'],
end_color=colors['UNSATISFACTORY'],
fill_type='solid')))
ws.conditional_formatting.add(f'I5:I104',
FormulaRule(formula=['I5="ABSENT"'],
fill=PatternFill(start_color=colors['ABSENT'],
end_color=colors['ABSENT'],
fill_type='solid')))
# Add a note about data entry
ws.merge_cells('A3:I3')
ws['A3'] = "Enter student information and assessment scores below (scores must
be between 0-100)"
ws['A3'].font = Font(italic=True)
ws['A3'].alignment = Alignment(horizontal='center')
def setup_summary_analysis(ws, mark_sheet):
"""Set up the Summary Analysis sheet with summary tables and statistics."""
# Set column widths
for col in range(1, 10):
ws.column_dimensions[get_column_letter(col)].width = 15
# Add title
ws.merge_cells('A1:G1')
ws['A1'] = "SUMMARY ANALYSIS"
ws['A1'].font = Font(size=16, bold=True)
ws['A1'].alignment = Alignment(horizontal='center', vertical='center')
ws.row_dimensions[1].height = 30
# Add subtitle with date
ws.merge_cells('A2:G2')
ws['A2'] = f"Generated on: {datetime.datetime.now().strftime('%Y-%m-%d')}"
ws['A2'].font = Font(size=10, italic=True)
ws['A2'].alignment = Alignment(horizontal='center')
# Table 1: Grade Distribution by Gender
ws['A4'] = "Table 1: Grade Distribution by Gender"
ws['A4'].font = Font(bold=True)
# Headers for Table 1
headers = ["Grade", "Male Count", "Male %", "Female Count", "Female %", "Total
Count", "Total %"]
for col, header in enumerate(headers, 1):
cell = ws.cell(row=5, column=col)
cell.value = header
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3",
fill_type="solid")
# Add thin borders to header
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'),
top=Side(style='thin'), bottom=Side(style='thin'))
for row in ws.iter_rows(min_row=5, max_row=5, min_col=1, max_col=7):
for cell in row:
cell.border = thin_border
# Grade rows for Table 1
grades = ["ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT",
"NINE", "X", "TOTAL"]
for idx, grade in enumerate(grades):
row_num = 6 + idx
ws.cell(row=row_num, column=1).value = grade
ws.cell(row=row_num, column=1).alignment = Alignment(horizontal='center')
if grade != "TOTAL":
# Male Count
ws.cell(row=row_num, column=2).value = f'=COUNTIFS(\'Mark Schedule\'!
$C$5:$C$104,"M",\'Mark Schedule\'!$H$5:$H$104,"{grade}")'
# Male Percentage
ws.cell(row=row_num, column=3).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"M")=0,0,B{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M"))'
ws.cell(row=row_num, column=3).number_format = '0.00%'
# Female Count
ws.cell(row=row_num, column=4).value = f'=COUNTIFS(\'Mark Schedule\'!
$C$5:$C$104,"F",\'Mark Schedule\'!$H$5:$H$104,"{grade}")'
# Female Percentage
ws.cell(row=row_num, column=5).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"F")=0,0,D{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F"))'
ws.cell(row=row_num, column=5).number_format = '0.00%'
# Total Count
ws.cell(row=row_num, column=6).value = f'=B{row_num}+D{row_num}'
# Total Percentage
ws.cell(row=row_num, column=7).value = f'=IF(COUNT(\'Mark Schedule\'!
$C$5:$C$104)=0,0,F{row_num}/COUNT(\'Mark Schedule\'!$C$5:$C$104))'
ws.cell(row=row_num, column=7).number_format = '0.00%'
else:
# Total row calculations
ws.cell(row=row_num, column=2).value = f'=SUM(B6:B15)'
ws.cell(row=row_num, column=3).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"M")=0,0,B{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M"))'
ws.cell(row=row_num, column=3).number_format = '0.00%'
ws.cell(row=row_num, column=4).value = f'=SUM(D6:D15)'
ws.cell(row=row_num, column=5).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"F")=0,0,D{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F"))'
ws.cell(row=row_num, column=5).number_format = '0.00%'
ws.cell(row=row_num, column=6).value = f'=SUM(F6:F15)'
ws.cell(row=row_num, column=7).value = f'=IF(COUNT(\'Mark Schedule\'!
$C$5:$C$104)=0,0,F{row_num}/COUNT(\'Mark Schedule\'!$C$5:$C$104))'
ws.cell(row=row_num, column=7).number_format = '0.00%'
# Add borders to all cells in the row
for col in range(1, 8):
ws.cell(row=row_num, column=col).border = thin_border
# Table 2: Performance Categories Summary
ws['A18'] = "Table 2: Performance Categories Summary"
ws['A18'].font = Font(bold=True)
# Headers for Table 2
headers = ["Performance", "Male Count", "Male %", "Female Count", "Female %",
"Total Count", "Total %"]
for col, header in enumerate(headers, 1):
cell = ws.cell(row=19, column=col)
cell.value = header
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3",
fill_type="solid")
# Add thin borders to header
for row in ws.iter_rows(min_row=19, max_row=19, min_col=1, max_col=7):
for cell in row:
cell.border = thin_border
# Performance categories for Table 2
performance_categories = ["DISTINCTION", "MERIT", "CREDIT", "SATISFACTORY",
"UNSATISFACTORY", "ABSENT", "TOTAL"]
for idx, category in enumerate(performance_categories):
row_num = 20 + idx
ws.cell(row=row_num, column=1).value = category
ws.cell(row=row_num, column=1).alignment = Alignment(horizontal='center')
if category != "TOTAL":
# Male Count
ws.cell(row=row_num, column=2).value = f'=COUNTIFS(\'Mark Schedule\'!
$C$5:$C$104,"M",\'Mark Schedule\'!$I$5:$I$104,"{category}")'
# Male Percentage
ws.cell(row=row_num, column=3).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"M")=0,0,B{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M"))'
ws.cell(row=row_num, column=3).number_format = '0.00%'
# Female Count
ws.cell(row=row_num, column=4).value = f'=COUNTIFS(\'Mark Schedule\'!
$C$5:$C$104,"F",\'Mark Schedule\'!$I$5:$I$104,"{category}")'
# Female Percentage
ws.cell(row=row_num, column=5).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"F")=0,0,D{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F"))'
ws.cell(row=row_num, column=5).number_format = '0.00%'
# Total Count
ws.cell(row=row_num, column=6).value = f'=B{row_num}+D{row_num}'
# Total Percentage
ws.cell(row=row_num, column=7).value = f'=IF(COUNT(\'Mark Schedule\'!
$C$5:$C$104)=0,0,F{row_num}/COUNT(\'Mark Schedule\'!$C$5:$C$104))'
ws.cell(row=row_num, column=7).number_format = '0.00%'
else:
# Total row calculations
ws.cell(row=row_num, column=2).value = f'=SUM(B20:B25)'
ws.cell(row=row_num, column=3).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"M")=0,0,B{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M"))'
ws.cell(row=row_num, column=3).number_format = '0.00%'
ws.cell(row=row_num, column=4).value = f'=SUM(D20:D25)'
ws.cell(row=row_num, column=5).value = f'=IF(COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"F")=0,0,D{row_num}/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F"))'
ws.cell(row=row_num, column=5).number_format = '0.00%'
ws.cell(row=row_num, column=6).value = f'=SUM(F20:F25)'
ws.cell(row=row_num, column=7).value = f'=IF(COUNT(\'Mark Schedule\'!
$C$5:$C$104)=0,0,F{row_num}/COUNT(\'Mark Schedule\'!$C$5:$C$104))'
ws.cell(row=row_num, column=7).number_format = '0.00%'
# Add borders to all cells in the row
for col in range(1, 8):
ws.cell(row=row_num, column=col).border = thin_border
# Table 3: Key Performance Indicators
ws['A28'] = "Table 3: Key Performance Indicators"
ws['A28'].font = Font(bold=True)
# Headers for Table 3
headers = ["KPI", "Male", "Female", "Overall"]
for col, header in enumerate(headers, 1):
cell = ws.cell(row=29, column=col)
cell.value = header
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3",
fill_type="solid")
# Add thin borders to header
for row in ws.iter_rows(min_row=29, max_row=29, min_col=1, max_col=4):
for cell in row:
cell.border = thin_border
# KPI rows for Table 3
kpis = [
("Percentage of students who achieved grades ONE to SIX",
f'=SUM(B6:B11)/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M")',
f'=SUM(D6:D11)/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F")',
f'=SUM(F6:F11)/COUNT(\'Mark Schedule\'!$C$5:$C$104)'),
("Percentage of students who achieved grades ONE to EIGHT",
f'=SUM(B6:B13)/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M")',
f'=SUM(D6:D13)/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F")',
f'=SUM(F6:F13)/COUNT(\'Mark Schedule\'!$C$5:$C$104)'),
("Percentage of students who failed (grade NINE)",
f'=B15/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M")',
f'=D15/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F")',
f'=F15/COUNT(\'Mark Schedule\'!$C$5:$C$104)'),
("Percentage of students who were absent (grade X)",
f'=B16/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M")',
f'=D16/COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F")',
f'=F16/COUNT(\'Mark Schedule\'!$C$5:$C$104)'),
("Male to female ratio in the class",
f'=COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M")/COUNTIF(\'Mark Schedule\'!
$C$5:$C$104,"F")',
"",
""),
("Overall class average score",
"",
"",
f'=AVERAGE(\'Mark Schedule\'!$G$5:$G$104)')
]
for idx, (kpi, male_formula, female_formula, overall_formula) in
enumerate(kpis):
row_num = 30 + idx
ws.cell(row=row_num, column=1).value = kpi
ws.cell(row=row_num, column=1).alignment = Alignment(horizontal='left')
ws.cell(row=row_num, column=2).value = male_formula
ws.cell(row=row_num, column=2).number_format = '0.00%'
ws.cell(row=row_num, column=3).value = female_formula
ws.cell(row=row_num, column=3).number_format = '0.00%'
ws.cell(row=row_num, column=4).value = overall_formula
ws.cell(row=row_num, column=4).number_format = '0.00%'
# Add borders to all cells in the row
for col in range(1, 5):
ws.cell(row=row_num, column=col).border = thin_border
# Add a note about the data
ws.merge_cells('A3:G3')
ws['A3'] = "All data is derived from the 'Mark Schedule' sheet."
ws['A3'].font = Font(italic=True)
ws['A3'].alignment = Alignment(horizontal='center')
def setup_dashboard(ws, mark_sheet, summary_sheet):
"""Set up the Dashboard sheet with visual representations of the analysis."""
# Set column widths
for col in range(1, 10):
ws.column_dimensions[get_column_letter(col)].width = 15
# Add title
ws.merge_cells('A1:G1')
ws['A1'] = "DASHBOARD"
ws['A1'].font = Font(size=16, bold=True)
ws['A1'].alignment = Alignment(horizontal='center', vertical='center')
ws.row_dimensions[1].height = 30
# Add subtitle with date
ws.merge_cells('A2:G2')
ws['A2'] = f"Generated on: {datetime.datetime.now().strftime('%Y-%m-%d')}"
ws['A2'].font = Font(size=10, italic=True)
ws['A2'].alignment = Alignment(horizontal='center')
# Scorecard/KPI Section
ws['A4'] = "Scorecard/KPI Section"
ws['A4'].font = Font(bold=True)
# Add KPI labels and values
kpis = [
("Class average score (overall)", '=Summary Analysis!G36'),
("Class average by gender (Male)", '=Summary Analysis!B36'),
("Class average by gender (Female)", '=Summary Analysis!C36'),
("Pass rate (grades ONE-EIGHT)", '=Summary Analysis!G31'),
("Distinction rate (grades ONE-TWO)", '=Summary Analysis!G30'),
("Failure rate (grade NINE)", '=Summary Analysis!G33'),
("Absence rate (grade X)", '=Summary Analysis!G34'),
("Total students count", '=COUNT(\'Mark Schedule\'!$C$5:$C$104)'),
("Male students count", '=COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"M")'),
("Female students count", '=COUNTIF(\'Mark Schedule\'!$C$5:$C$104,"F")')
]
for idx, (label, formula) in enumerate(kpis):
row_num = 5 + idx
ws.cell(row=row_num, column=1).value = label
ws.cell(row=row_num, column=1).alignment = Alignment(horizontal='left')
ws.cell(row=row_num, column=2).value = formula
ws.cell(row=row_num, column=2).number_format = '0.00%' if "%" in label else
'0.00'
# Grouped Bar Chart: Grade Distribution by Gender
chart1 = BarChart()
chart1.type = "col"
chart1.style = 10
chart1.title = "Grade Distribution by Gender"
chart1.y_axis.title = "Student Count"
chart1.x_axis.title = "Grade"
# Data for the chart
data = Reference(summary_sheet, min_col=2, min_row=5, max_col=6, max_row=15)
cats = Reference(summary_sheet, min_col=1, min_row=6, max_row=15)
chart1.add_data(data, titles_from_data=True)
chart1.set_categories(cats)
# Add the chart to the worksheet
ws.add_chart(chart1, "A18")
# Pie Charts: Performance Distribution
# Male Performance Distribution
chart2 = PieChart()
chart2.title = "Male Performance Distribution"
data = Reference(summary_sheet, min_col=2, min_row=20, max_row=25)
labels = Reference(summary_sheet, min_col=1, min_row=20, max_row=25)
chart2.add_data(data, titles_from_data=True)
chart2.set_categories(labels)
# Add the chart to the worksheet
ws.add_chart(chart2, "J5")
# Female Performance Distribution
chart3 = PieChart()
chart3.title = "Female Performance Distribution"
data = Reference(summary_sheet, min_col=4, min_row=20, max_row=25)
labels = Reference(summary_sheet, min_col=1, min_row=20, max_row=25)
chart3.add_data(data, titles_from_data=True)
chart3.set_categories(labels)
# Add the chart to the worksheet
ws.add_chart(chart3, "J20")
# Overall Performance Distribution
chart4 = PieChart()
chart4.title = "Overall Performance Distribution"
data = Reference(summary_sheet, min_col=6, min_row=20, max_row=25)
labels = Reference(summary_sheet, min_col=1, min_row=20, max_row=25)
chart4.add_data(data, titles_from_data=True)
chart4.set_categories(labels)
# Add the chart to the worksheet
ws.add_chart(chart4, "J35")
# Add a note about the data
ws.merge_cells('A3:G3')
ws['A3'] = "All data is derived from the 'Summary Analysis' sheet."
ws['A3'].font = Font(italic=True)
ws['A3'].alignment = Alignment(horizontal='center')
def setup_instructions(ws):
"""Set up the Instructions sheet with user guidance."""
# Set column widths
ws.column_dimensions['A'].width = 100
# Add title
ws.merge_cells('A1:A2')
ws['A1'] = "INSTRUCTIONS FOR USING THE CLASS ASSESSMENT TOOL"
ws['A1'].font = Font(size=16, bold=True)
ws['A1'].alignment = Alignment(horizontal='center', vertical='center')
ws.row_dimensions[1].height = 30
# Add instructions
instructions = [
"1. Enter student data in the 'Mark Schedule' sheet.",
"2. Ensure that the 'Sex' column contains only 'M' or 'F'.",
"3. Ensure that assessment scores are between 0 and 100.",
"4. The 'Average', 'Grade', and 'Remark' columns will be automatically
calculated.",
"5. View summary statistics and analysis in the 'Summary Analysis' sheet.",
"6. View visual representations of the data in the 'Dashboard' sheet.",
"7. Do not modify cells with formulas or conditional formatting.",
"8. Save the file after entering data to preserve changes."
]
for idx, instruction in enumerate(instructions, 3):
ws.cell(row=idx, column=1).value = instruction
ws.cell(row=idx, column=1).alignment = Alignment(horizontal='left')
# Add a note about the tool
ws.merge_cells('A12:A13')
ws['A12'] = "This tool is designed to simplify class assessment analysis and
reporting."
ws['A12'].font = Font(italic=True)
ws['A12'].alignment = Alignment(horizontal='center')
# Run the function to create the Excel tool
create_class_assessment_tool()