Skip to content
This repository was archived by the owner on Apr 20, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added analytics/__init__.py
Empty file.
97 changes: 97 additions & 0 deletions analytics/bargraph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# import requests
# import plotly.graph_objects as go
# import pandas as pd

# # Base URL for your API endpoints (adjust if needed)
# API_BASE_URL = "http://127.0.0.1:8000/courses"

# def fetch_requirement_coverage(major: str, semester: str):
# """
# Calls the API endpoint to get analytics data instead of reading Excel files directly.
# Expected endpoint: GET /courses/analytics?major=<major>&semester=<semester>
# """
# url = f"{API_BASE_URL}/analytics"
# params = {"major": major, "semester": semester}
# response = requests.get(url, params=params)
# response.raise_for_status() # raises an HTTPError for bad responses
# return response.json()

# def create_bargraph(data, selected_major: str):
# """
# Given analytics data (list of dicts with keys: major, short_requirement, NumCourses),
# create and display a horizontal bar graph using Plotly.
# """
# if not data:
# print("No data available to plot.")
# return

# # Convert the JSON data into a DataFrame for easier plotting
# df_grouped = pd.DataFrame(data)
# # Get all majors in the data
# majors = sorted(df_grouped["major"].dropna().unique())

# def get_trace(major: str):
# subset = df_grouped[df_grouped["major"] == major].copy()
# subset = subset.sort_values(by="NumCourses", ascending=True)
# return go.Bar(
# x=subset["NumCourses"],
# y=subset["short_requirement"],
# orientation="h",
# name=major,
# )

# init_trace = get_trace(selected_major)
# fig = go.Figure(data=[init_trace])

# # Create a dropdown for selecting different majors
# buttons = []
# for m in majors:
# buttons.append({
# "label": m,
# "method": "update",
# "args": [
# {"data": [get_trace(m)]},
# {"title": f"Course Count per Requirement for {m}"}
# ]
# })

# fig.update_layout(
# updatemenus=[{
# "buttons": buttons,
# "direction": "down",
# "x": 0.0,
# "xanchor": "left",
# "y": 1.15,
# "yanchor": "top",
# "showactive": True,
# "pad": {"r": 10, "t": 10}
# }],
# title=f"Course Count per Requirement for {selected_major}",
# xaxis_title="Number of Courses",
# yaxis_title="Requirement",
# margin={"l": 100, "r": 100, "t": 150, "b": 50}
# )
# fig.add_annotation(
# x=0.0,
# y=1.22,
# xanchor="left",
# yanchor="top",
# text="Select Major:",
# showarrow=False,
# font={"size": 12},
# )
# fig.show()

# def main():
# """
# Client entry point for the bar graph.
# Instead of reading from Excel, it fetches data from the API endpoint.
# """
# major = input("Enter major (e.g., IS): ").strip().upper()
# semester = input("Enter semester (e.g., F21): ").strip().upper()
# try:
# data = fetch_requirement_coverage(major, semester)
# create_bargraph(data, major)
# except Exception as e:
# print("Error fetching or plotting data:", e)

116 changes: 115 additions & 1 deletion analytics/predict_next_sem.py
Original file line number Diff line number Diff line change
@@ -1 +1,115 @@
# this is a placeholder for the code that will predict whether a course will be offered in the next semester
# import os
# import pandas as pd
# import numpy as np


# def semester_sort_key(sem):
# """
# Sort a semester code based on an academic cycle:
# - For Fall (F): effective_year = int(year), order = 0.
# - For Spring (S) and Summer (M): effective_year = int(year) - 1,
# order = 1 for Spring, 2 for Summer.
# For example:
# F20 -> (20, 0)
# S21 -> (20, 1)
# M21 -> (20, 2)
# F21 -> (21, 0)
# """
# letter = sem[0].upper()
# try:
# year = int(sem[1:])
# except Exception:
# year = 0

# if letter == "F":
# effective_year = year
# order = 0
# elif letter == "S":
# effective_year = year - 1
# order = 1
# elif letter == "M":
# effective_year = year - 1
# order = 2
# else:
# effective_year = year
# order = 3

# return effective_year, order


# def predict_offering(course_code, target_semester):
# """
# Reads Offering.xlsx and applies rule-based logic to determine
# if `course_code` is likely to be offered in `target_semester`.
# """
# current_dir = os.path.dirname(os.path.abspath(__file__))
# data_dir = os.path.join(current_dir, "..", "data", "course")
# offering_file = os.path.join(data_dir, "Offering.xlsx")

# df = pd.read_excel(offering_file, engine="openpyxl")
# df.columns = df.columns.str.strip()
# df["Offered"] = 1

# grouped = df.groupby(["course_code", "semester"])["Offered"].max().reset_index()
# unique_semesters = grouped["semester"].unique()
# sorted_semesters = sorted(unique_semesters, key=semester_sort_key)

# wide_data = grouped.pivot(index="course_code", columns="semester", values="Offered")
# wide_data = wide_data.reindex(columns=sorted_semesters, fill_value=0).reset_index()
# wide_data.columns.name = None
# wide_data = wide_data.fillna(0)

# # Locate row for that course
# course_row = wide_data[wide_data["course_code"] == course_code]
# if course_row.empty:
# return {
# "course_code": course_code,
# "target_semester": target_semester,
# "prediction": "NO_DATA",
# "reason": f"Course {course_code} not found in data."
# }

# # Filter out columns that start with the target season AND have year > 20
# target_season = target_semester[0].upper() # "S", "F", or "M"
# season_cols = [
# col for col in sorted_semesters
# if col.startswith(target_season) and int(col[1:]) > 20
# ]

# offered_values = []
# for col in season_cols:
# if col in course_row.columns:
# offered_values.append(int(course_row[col].iloc[0]))
# else:
# offered_values.append(0)

# fraction_offered = (
# sum(offered_values) / len(offered_values) if offered_values else 0
# )

# threshold = 0.5
# prediction = "YES" if fraction_offered >= threshold else "NO"

# return {
# "course_code": course_code,
# "target_semester": target_semester,
# "prediction": prediction,
# "fraction_offered": fraction_offered
# }


# def main():
# """
# Interactive mode for `predict_next_sem.py`.
# Asks the user for target_semester and course_code,
# then prints the prediction result.
# """
# target_semester = input(
# "Enter the target future semester (e.g. S26): "
# ).strip().upper()
# course_input = input("Enter the Course Code to query: ").strip().upper()

# result = predict_offering(course_input, target_semester)
# print(result)


3 changes: 2 additions & 1 deletion backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from backend.app.routers import courses, requirements
from backend.app.routers import courses, requirements, analytics

app = FastAPI(
title="GenEd API",
Expand All @@ -24,3 +24,4 @@

app.include_router(courses.router)
app.include_router(requirements.router)
#app.include_router(analytics.router)
42 changes: 42 additions & 0 deletions backend/app/routers/analytics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# from fastapi import APIRouter, Depends, HTTPException
# from sqlalchemy.orm import Session

# # If you’re reading from Excel files, you won't necessarily need SQLAlchemy,
# # but if you're using a DB, you'll import get_db and possibly a repository.
# from backend.database.db import get_db
# from backend.app.schemas import CoverageOut, PredictOut
# from backend.services import analytics as analytics_service

# router = APIRouter()


# @router.get("/analytics/requirement-coverage", response_model=list[CoverageOut])
# def get_requirement_coverage(db: Session = Depends(get_db)):
# """
# Returns data for the bar graph (based on Countsfor.xlsx & Requirement.xlsx)
# OR from your DB tables if you migrated data there.
# """
# try:
# coverage_data = analytics_service.get_requirement_coverage(db)
# return coverage_data
# except Exception as exc:
# raise HTTPException(status_code=500, detail=str(exc))


# @router.get("/analytics/predict", response_model=PredictOut)
# def predict_course_offering(
# course_code: str,
# target_semester: str,
# db: Session = Depends(get_db)
# ):
# """
# Predicts if a course is offered in a given semester (based on Offering.xlsx)
# OR from your DB tables if that data is in the 'offering' table.
# Example usage: /analytics/predict?course_code=CS101&target_semester=S26
# """
# try:
# return analytics_service.predict_course_offering(db, course_code, target_semester)
# except ValueError as val_err:
# raise HTTPException(status_code=400, detail=str(val_err))
# except Exception as exc:
# raise HTTPException(status_code=500, detail=str(exc))
Loading