Skip to content

jatheepan86-ops/work-doccc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

import tkinter as tk from tkinter import ttk, messagebox import json import os import uuid import math

DB_FILE = "biology_db.json"

── DATABASE ──────────────────────────────────────────

def load_db(): if os.path.exists(DB_FILE): with open(DB_FILE, "r") as f: return json.load(f) return {"students": []}

def save_db(data): with open(DB_FILE, "w") as f: json.dump(data, f, indent=2) messagebox.showinfo("Saved", "Data saved successfully!")

db = load_db()

── CONSTANTS ─────────────────────────────────────────

SUBJECT = "Biology" SEMESTERS = ["Semester 1", "Semester 2", "Semester 3"] SEM_COLORS = ["#5B8CCC", "#CC7B5B", "#3DAA7A"] RANK_COLORS = ["#FFD700", "#B0B0B0", "#CD7F32", "#607080"]

── THEME ─────────────────────────────────────────────

BG_DARK = "#1E1E1E" # main ash-black background BG_PANEL = "#2A2A2A" # slightly lighter panel BG_CARD = "#333333" # card / treeview background FG_WHITE = "#F0F0F0" FG_MUTED = "#AAAAAA" ACCENT_BLUE = "#4C9BE8" ACCENT_GREEN = "#1D9E75" ACCENT_RED = "#E24B4A" ACCENT_PURP = "#9B59B6" BTN_RADIUS = 8 # used in rounded canvas buttons

── HELPERS ───────────────────────────────────────────

def get_suffix(n): if 11 <= n <= 13: return f"{n}th" return f"{n}{({1:'st',2:'nd',3:'rd'}).get(n % 10, 'th')}"

def generate_id(): return "STU-" + str(uuid.uuid4())[:8].upper()

── Z-SCORE CALCULATION ───────────────────────────────

A/L Z-score: how many standard deviations a student is

above or below the class average.

Formula: Z = (student_mark - mean) / std_dev

def compute_zscore(mark, all_marks): if len(all_marks) < 2: return 0.0 mean = sum(all_marks) / len(all_marks) variance = sum((x - mean) ** 2 for x in all_marks) / len(all_marks) std = math.sqrt(variance) if std == 0: return 0.0 return (mark - mean) / std

def get_all_sem3_marks(): return [s["semesters"][2] for s in db["students"]]

── ROUNDED BUTTON HELPER ─────────────────────────────

def rounded_button(parent, text, command, color=BG_CARD, fg=FG_WHITE, width=160, height=34, radius=BTN_RADIUS): """Draw a smooth-edge rounded button using Canvas.""" cvs = tk.Canvas(parent, width=width, height=height, bg=BG_PANEL, highlightthickness=0, cursor="hand2")

def draw(fill):
    cvs.delete("btn")
    r = radius
    x0, y0, x1, y1 = 2, 2, width - 2, height - 2
    cvs.create_arc(x0, y0, x0+2*r, y0+2*r, start=90, extent=90,
                   fill=fill, outline=fill, tags="btn")
    cvs.create_arc(x1-2*r, y0, x1, y0+2*r, start=0, extent=90,
                   fill=fill, outline=fill, tags="btn")
    cvs.create_arc(x0, y1-2*r, x0+2*r, y1, start=180, extent=90,
                   fill=fill, outline=fill, tags="btn")
    cvs.create_arc(x1-2*r, y1-2*r, x1, y1, start=270, extent=90,
                   fill=fill, outline=fill, tags="btn")
    cvs.create_rectangle(x0+r, y0, x1-r, y1, fill=fill, outline=fill, tags="btn")
    cvs.create_rectangle(x0, y0+r, x1, y1-r, fill=fill, outline=fill, tags="btn")
    cvs.create_text(width//2, height//2, text=text,
                    font=("Arial", 9, "bold"), fill=fg, tags="btn")

draw(color)

def on_enter(_):
    # lighten on hover
    draw("#4A4A4A" if color == BG_CARD else color)
def on_leave(_):
    draw(color)
def on_click(_):
    command()

cvs.bind("<Enter>", on_enter)
cvs.bind("<Leave>", on_leave)
cvs.bind("<Button-1>", on_click)
return cvs

── BAR CHART ─────────────────────────────────────────

def draw_bar_chart(canvas, data_sets, labels, colors, title, width=680, height=300, show_rank=False): canvas.delete("all") pad_left, pad_right, pad_top, pad_bottom = 60, 20, 50, 60

chart_w = width - pad_left - pad_right
chart_h = height - pad_top - pad_bottom

all_vals = [v for ds in data_sets for v in ds["values"]]
max_val = max(all_vals + [100]) + 15

canvas.create_text(width // 2, 22, text=title,
                   font=("Arial", 11, "bold"), fill=FG_WHITE)

for i in range(6):
    y_val = int(i * max_val / 5)
    y_px = pad_top + chart_h - int((y_val / max_val) * chart_h)
    canvas.create_line(pad_left, y_px, pad_left + chart_w, y_px,
                       fill="#3A3A3A", dash=(4, 3))
    canvas.create_text(pad_left - 6, y_px, text=str(y_val),
                       anchor="e", font=("Arial", 8), fill=FG_MUTED)

canvas.create_line(pad_left, pad_top, pad_left, pad_top + chart_h, fill="#555")
canvas.create_line(pad_left, pad_top + chart_h,
                   pad_left + chart_w, pad_top + chart_h, fill="#555")

num_groups = len(labels)
num_sets = len(data_sets)
group_w = chart_w / max(num_groups, 1)
bar_w = (group_w * 0.7) / max(num_sets, 1)
gap = group_w * 0.15

for g, label in enumerate(labels):
    group_x = pad_left + g * group_w + gap
    for s, ds in enumerate(data_sets):
        val = ds["values"][g]
        color = colors[g] if show_rank else colors[s % len(colors)]
        bar_x = group_x + s * bar_w
        bar_h = int((val / max_val) * chart_h)
        bar_y = pad_top + chart_h - bar_h

        canvas.create_rectangle(bar_x, bar_y, bar_x + bar_w - 2,
                                 pad_top + chart_h,
                                 fill=color, outline=BG_DARK, width=1)
        canvas.create_text(bar_x + (bar_w - 2) / 2, bar_y - 7,
                            text=str(int(val)),
                            font=("Arial", 8, "bold"), fill=FG_WHITE)

        if show_rank:
            bx = bar_x + (bar_w - 2) / 2
            by = bar_y - 22
            canvas.create_rectangle(bx-14, by-8, bx+14, by+8,
                                     fill=color, outline=BG_DARK)
            canvas.create_text(bx, by, text=get_suffix(g + 1),
                               font=("Arial", 8, "bold"), fill="white")

    lx = pad_left + g * group_w + group_w / 2
    canvas.create_text(lx, pad_top + chart_h + 14, text=label,
                       font=("Arial", 9), fill=FG_MUTED,
                       width=int(group_w - 4))

for s, ds in enumerate(data_sets):
    lx = pad_left + s * 130
    color = colors[s % len(colors)]
    canvas.create_rectangle(lx, height - 16, lx + 11, height - 5,
                             fill=color, outline="")
    canvas.create_text(lx + 15, height - 11, text=ds["label"],
                       anchor="w", font=("Arial", 9), fill=FG_MUTED)

══════════════════════════════════════════════════════

WINDOWS

══════════════════════════════════════════════════════

── ADD / EDIT STUDENT ────────────────────────────────

def open_add_student(root, refresh_cb, edit_index=None): win = tk.Toplevel(root) win.title("Edit Student" if edit_index is not None else "Add Student") win.configure(bg=BG_DARK) win.resizable(False, False)

editing = edit_index is not None
student = db["students"][edit_index] if editing else None

tk.Label(win,
         text="Edit Student" if editing else "Add Student",
         font=("Arial", 13, "bold"),
         bg=BG_DARK, fg=FG_WHITE).pack(pady=12)

# Student ID (read-only display when editing)
id_frame = tk.Frame(win, bg=BG_DARK)
id_frame.pack(pady=2)
tk.Label(id_frame, text="Student ID:", width=13,
         bg=BG_DARK, fg=FG_MUTED, anchor="w").pack(side="left")
id_val = student["student_id"] if editing else "(auto-generated)"
tk.Label(id_frame, text=id_val,
         font=("Arial", 9, "bold"), bg=BG_DARK, fg=ACCENT_BLUE).pack(side="left")

# Name
nf = tk.Frame(win, bg=BG_DARK)
nf.pack(pady=4)
tk.Label(nf, text="Name:", width=13, bg=BG_DARK,
         fg=FG_MUTED, anchor="w").pack(side="left")
name_entry = tk.Entry(nf, width=22, font=("Arial", 10),
                      bg=BG_CARD, fg=FG_WHITE,
                      insertbackground=FG_WHITE, relief="flat")
name_entry.pack(side="left", ipady=4)
if editing:
    name_entry.insert(0, student["name"])

# Marks for each semester
entries = {}
for sem_i, sem in enumerate(SEMESTERS):
    tk.Label(win, text=sem, font=("Arial", 10, "bold"),
             bg=BG_DARK, fg=SEM_COLORS[sem_i]).pack(pady=(10, 2))
    row = tk.Frame(win, bg=BG_DARK)
    row.pack(pady=2)
    tk.Label(row, text=f" {SUBJECT}:", width=14,
             bg=BG_DARK, fg=FG_MUTED, anchor="w").pack(side="left")
    e = tk.Entry(row, width=8, font=("Arial", 10),
                 bg=BG_CARD, fg=FG_WHITE,
                 insertbackground=FG_WHITE, relief="flat")
    e.pack(side="left", ipady=4)
    if editing and sem_i < len(student["semesters"]):
        val = student["semesters"][sem_i]
        if val != "":
            e.insert(0, str(int(val)))
    entries[sem_i] = e

def save_student():
    name = name_entry.get().strip()
    if not name:
        messagebox.showwarning("Warning", "Enter student name.")
        return

    semester_marks = []
    for sem_i in range(3):
        val = entries[sem_i].get().strip()
        if not val:
            messagebox.showwarning("Warning",
                f"Enter Biology mark for Semester {sem_i+1}.")
            return
        try:
            m = float(val)
            if not 0 <= m <= 100:
                raise ValueError
            semester_marks.append(m)
        except ValueError:
            messagebox.showerror("Error",
                f"Invalid mark for Semester {sem_i+1}. Enter 0–100.")
            return

    if editing:
        db["students"][edit_index]["name"] = name
        db["students"][edit_index]["semesters"] = semester_marks
    else:
        db["students"].append({
            "student_id": generate_id(),
            "name": name,
            "semesters": semester_marks
        })

    save_db(db)
    refresh_cb()
    win.destroy()

btn = rounded_button(win, "Save Student", save_student,
                     color=ACCENT_GREEN, width=170, height=36)
btn.pack(pady=16)

── PROGRESS WINDOW ───────────────────────────────────

def open_progress(student): all_marks = get_all_sem3_marks() z = compute_zscore(student["semesters"][2], all_marks)

win = tk.Toplevel()
win.title(f"Progress — {student['name']}")
win.configure(bg=BG_DARK)

tk.Label(win,
         text=f"Progress: {student['name']} | ID: {student['student_id']}",
         font=("Arial", 12, "bold"), bg=BG_DARK, fg=FG_WHITE).pack(pady=8)

# Z-score banner
z_color = ACCENT_GREEN if z >= 0 else ACCENT_RED
z_text = f"A/L Z-Score (Sem 3): {z:+.3f} — "
z_text += "Above average" if z > 0 else ("Below average" if z < 0 else "At average")
tk.Label(win, text=z_text, font=("Arial", 10, "bold"),
         bg=BG_DARK, fg=z_color).pack(pady=2)
tk.Label(win,
         text="Z-score = (your mark − class mean) ÷ std deviation",
         font=("Arial", 8), bg=BG_DARK, fg=FG_MUTED).pack()

canvas = tk.Canvas(win, width=680, height=300,
                   bg=BG_PANEL, highlightthickness=0)
canvas.pack(padx=10, pady=10)

draw_bar_chart(canvas,
               [{"label": SUBJECT, "values": student["semesters"]}],
               SEMESTERS,
               [SEM_COLORS[0], SEM_COLORS[1], SEM_COLORS[2]],
               f"{SUBJECT} — Semester Progress")

── RANKING WINDOW ────────────────────────────────────

def open_rankings(): students = db["students"] if not students: messagebox.showinfo("No Data", "No students found.") return

win = tk.Toplevel()
win.title("Semester 3 Rankings")
win.configure(bg=BG_DARK)

tk.Label(win, text="Biology — Semester 3 Rankings",
         font=("Arial", 13, "bold"), bg=BG_DARK, fg=FG_WHITE).pack(pady=8)

# Rankings table with Z-scores
cols_frame = tk.Frame(win, bg=BG_DARK)
cols_frame.pack(fill="x", padx=10)

style = ttk.Style()
style.theme_use("default")
style.configure("Rank.Treeview",
                background=BG_CARD, foreground=FG_WHITE,
                fieldbackground=BG_CARD, rowheight=28,
                font=("Arial", 9))
style.configure("Rank.Treeview.Heading",
                background=BG_PANEL, foreground=FG_MUTED,
                font=("Arial", 9, "bold"), relief="flat")
style.map("Rank.Treeview", background=[("selected", "#3A5A7A")])

cols = ("rank", "id", "name", "mark", "zscore")
tree = ttk.Treeview(win, columns=cols, show="headings",
                    height=min(len(students), 12),
                    style="Rank.Treeview")
tree.heading("rank", text="Rank")
tree.heading("id", text="Student ID")
tree.heading("name", text="Name")
tree.heading("mark", text="Sem 3 Mark")
tree.heading("zscore", text="A/L Z-Score")
tree.column("rank", width=60, anchor="center")
tree.column("id", width=120, anchor="center")
tree.column("name", width=160)
tree.column("mark", width=110, anchor="center")
tree.column("zscore", width=120, anchor="center")
tree.pack(padx=10, pady=6, fill="x")

all_marks = [s["semesters"][2] for s in students]
ranked = sorted(students, key=lambda x: x["semesters"][2], reverse=True)
for rank, s in enumerate(ranked, 1):
    mark = s["semesters"][2]
    z = compute_zscore(mark, all_marks)
    tree.insert("", "end", values=(
        get_suffix(rank),
        s["student_id"],
        s["name"],
        f"{mark:.0f}",
        f"{z:+.3f}"
    ))

# Bar chart
canvas = tk.Canvas(win, width=680, height=300,
                   bg=BG_PANEL, highlightthickness=0)
canvas.pack(padx=10, pady=6)

names = [s["name"] for s in ranked]
marks = [s["semesters"][2] for s in ranked]
colors = [RANK_COLORS[i] if i < 3 else RANK_COLORS[3]
          for i in range(len(ranked))]
draw_bar_chart(canvas,
               [{"label": SUBJECT, "values": marks}],
               names, colors,
               "Biology — Semester 3 Rankings",
               show_rank=True)

── ALL STUDENTS COMPARISON ───────────────────────────

def open_comparison(): students = db["students"] if not students: messagebox.showinfo("No Data", "No students found.") return

win = tk.Toplevel()
win.title("All Students Comparison")
win.configure(bg=BG_DARK)

tk.Label(win, text="Biology — All Students Comparison",
         font=("Arial", 13, "bold"), bg=BG_DARK, fg=FG_WHITE).pack(pady=8)

canvas = tk.Canvas(win, width=680, height=300,
                   bg=BG_PANEL, highlightthickness=0)
canvas.pack(padx=10, pady=8)

datasets = []
for sem_i, sem in enumerate(SEMESTERS):
    vals = [s["semesters"][sem_i] for s in students]
    datasets.append({"label": sem, "values": vals})

names = [s["name"] for s in students]
draw_bar_chart(canvas, datasets, names, SEM_COLORS,
               "Biology — All Semesters Comparison")

── Z-SCORE OVERVIEW WINDOW ───────────────────────────

def open_zscore_overview(): students = db["students"] if not students: messagebox.showinfo("No Data", "No students found.") return

win = tk.Toplevel()
win.title("A/L Z-Score Overview")
win.configure(bg=BG_DARK)

tk.Label(win, text="A/L Z-Score Overview — Semester 3",
         font=("Arial", 13, "bold"), bg=BG_DARK, fg=FG_WHITE).pack(pady=8)
tk.Label(win,
         text="Z-score shows how far each student is from the class average (in standard deviations).",
         font=("Arial", 9), bg=BG_DARK, fg=FG_MUTED).pack()

style = ttk.Style()
style.configure("Z.Treeview",
                background=BG_CARD, foreground=FG_WHITE,
                fieldbackground=BG_CARD, rowheight=26,
                font=("Arial", 9))
style.configure("Z.Treeview.Heading",
                background=BG_PANEL, foreground=FG_MUTED,
                font=("Arial", 9, "bold"), relief="flat")
style.map("Z.Treeview", background=[("selected", "#3A5A7A")])

cols = ("id", "name", "s1", "s2", "s3", "z1", "z2", "z3")
tree = ttk.Treeview(win, columns=cols, show="headings",
                    height=min(len(students), 14),
                    style="Z.Treeview")
for col, head, w in [
    ("id", "Student ID", 120),
    ("name", "Name", 150),
    ("s1", "Sem 1", 80),
    ("s2", "Sem 2", 80),
    ("s3", "Sem 3", 80),
    ("z1", "Z (Sem 1)", 100),
    ("z2", "Z (Sem 2)", 100),
    ("z3", "Z (Sem 3)", 100),
]:
    tree.heading(col, text=head)
    tree.column(col, width=w, anchor="center")
tree.pack(padx=10, pady=10, fill="x")

for sem_i in range(3):
    all_m = [s["semesters"][sem_i] for s in students]
    for s in students:
        s[f"_z{sem_i}"] = compute_zscore(s["semesters"][sem_i], all_m)

for s in students:
    tree.insert("", "end", values=(
        s["student_id"], s["name"],
        f"{s['semesters'][0]:.0f}",
        f"{s['semesters'][1]:.0f}",
        f"{s['semesters'][2]:.0f}",
        f"{s['_z0']:+.3f}",
        f"{s['_z1']:+.3f}",
        f"{s['_z2']:+.3f}",
    ))

══════════════════════════════════════════════════════

MAIN DASHBOARD

══════════════════════════════════════════════════════

def main(): root = tk.Tk() root.title("Biology Mark Ranking System") root.geometry("780x600") root.configure(bg=BG_DARK)

# Apply dark ttk theme
style = ttk.Style()
style.theme_use("default")
style.configure("Main.Treeview",
                background=BG_CARD, foreground=FG_WHITE,
                fieldbackground=BG_CARD, rowheight=26,
                font=("Arial", 9))
style.configure("Main.Treeview.Heading",
                background=BG_PANEL, foreground=FG_MUTED,
                font=("Arial", 9, "bold"), relief="flat")
style.map("Main.Treeview", background=[("selected", "#3A5A7A")])
style.configure("TScrollbar", background=BG_CARD, troughcolor=BG_PANEL)

tk.Label(root, text="🔬 Biology Mark Ranking System",
         font=("Arial", 15, "bold"), bg=BG_DARK, fg=FG_WHITE).pack(pady=12)

# ── top action buttons ────────────────────────────
top_frame = tk.Frame(root, bg=BG_DARK)
top_frame.pack(pady=6)

def refresh():
    render_student_list()

btn_defs = [
    ("Add Student", lambda: open_add_student(root, refresh), ACCENT_GREEN),
    ("View Rankings", open_rankings, ACCENT_BLUE),
    ("Compare All", open_comparison, "#E87B4C"),
    ("Z-Score Table", open_zscore_overview, ACCENT_PURP),
]
for col_i, (label, cmd, color) in enumerate(btn_defs):
    b = rounded_button(top_frame, label, cmd, color=color, width=155, height=34)
    b.grid(row=0, column=col_i, padx=5)

# ── student table ──────────────────────────────────
list_frame = tk.Frame(root, bg=BG_DARK)
list_frame.pack(fill="both", expand=True, padx=16, pady=6)

columns = ("id", "name", "sem1", "sem2", "sem3", "zscore", "trend")
tree = ttk.Treeview(list_frame, columns=columns, show="headings",
                    height=16, style="Main.Treeview")
tree.heading("id", text="Student ID")
tree.heading("name", text="Name")
tree.heading("sem1", text="Sem 1")
tree.heading("sem2", text="Sem 2")

work-doccc

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors