Skip to content

Instantly share code, notes, and snippets.

@reagle
Last active December 15, 2023 18:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reagle/9cc2f4e2f98446528128d1f6edfe3d73 to your computer and use it in GitHub Desktop.
Save reagle/9cc2f4e2f98446528128d1f6edfe3d73 to your computer and use it in GitHub Desktop.
Using dictionary of letter grades, calculate mean GPA from list of letter grades converted to points
#!/usr/bin/env python3
"""Using dictionary of letter grades, calculate mean GPA from list
of letter grades converted to points"""
# https://gist.github.com/reagle/9cc2f4e2f98446528128d1f6edfe3d73
# add results to e-statement-1b-teaching-trace-table.xlsx
__author__ = "Joseph Reagle"
__copyright__ = "Copyright (C) 2021-2024 Joseph Reagle"
__license__ = "GLPv3"
__version__ = "1.1"
import statistics
from collections import Counter
try:
import asciietch.graph as ag # type:ignore
asciietch_imported = True
except ImportError:
asciietch_imported = False
print("`pip install asciietch` if you want nice graphs ▁▅█▂▁▃▁▂▁▁▁▂▁")
print(" https://github.com/linkedin/asciietch\n")
# https://registrar.northeastern.edu/article/how-to-calculate-your-gpa/
POINTS = {
"A+": 4.0,
"A": 4.0,
"A-": 3.667,
"B+": 3.333,
"B": 3.0,
"B-": 2.667,
"C+": 2.333,
"C": 2.0,
"C-": 1.667,
"D+": 1.333,
"D": 1.0,
"D-": 0.667,
"F": 0,
}
def calc_gpa(grades: list[str]) -> float:
"""Calculate mean GPA from list of letter grades converted to points."""
return statistics.mean([POINTS[grade] for grade in grades])
def print_header():
"""Print a header for the output."""
print(f"{'COURSE':<15} {'N':<5} {'MEAN':<10}", end="")
print(" ".join(f"{letter:<2}" for letter in POINTS.keys()))
def print_course(title: str, grades: list[str]) -> None:
"""Print single-line information for a course."""
print(f"{title:<15} N={len(grades):02d} μ={calc_gpa(grades):.2f}", end=" ")
distribution = [grades.count(letter) for letter in POINTS]
counter = Counter(grades)
for letter in POINTS.keys():
if letter in counter:
print(f"{counter[letter]:<3}", end="")
else:
print(" ", end="")
if asciietch_imported:
grapher = ag.Grapher()
print(grapher.asciihist(distribution), end="")
print()
COURSES = { # Target: B+ / 3.33 average
################### 2023 Fall
# 3.35 unprecedented drops at start, leaving mostly strong students
"2023_CDA_2FA": "A- A A- B- A- A- A- C A A A- A A- D- A B- A- A- B- B+",
# 3.33 first time teaching public speaking (includes F no show; 3.52 without him)
"2023_PS_2_FA": "B+ A- B A- A A- B- A B A- B+ A- A- A F B+ A A- B",
################### 2023 Spring
# 3.31
"2023_CDA_1_SP": (
"B B A A- A A- A- A- B+ A- A- A- A- A- A- F A B B+ A F A C+ A- A A A- B+ A- C+"
),
# 3.60, excellent students
"2023_OC_1_SP": "B+ A A B- B+ A- A- A A A- B A A B",
################### 2022 Fall
# 3.44
"2022_CDA_2FA": (
"D+ A A B+ A- A- A- A B+ B+ A- A- A A- A- B+ A A B+ B B B+ A- B B B+ A C+"
),
# 3.48
"2022_OC_2FA": "A- A B+ A C B+ B+ A- A",
################### 2022 Spring
# 3.42
"2022_CDA_1_SP": (
"C- A- A A- C- B A- A- A- B+ A B+ B+ A B+ B A- A- A A B+ A A- B A- B+ B"
),
# 3.61, excellent students
"2022_PC_1_SP": "B+ B+ A A- B+ B+ A B A- A A- A A A- A- A- B",
# "TEST": "A B B C C C D D D D F F F F F",
}
print_header()
for title, grades in COURSES.items():
print_course(title, grades.split(" "))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment