diff --git a/backend/main.py b/backend/main.py index 2d8450c..0b4f783 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,19 +1,16 @@ from fastapi import FastAPI, Query, HTTPException from fastapi.middleware.cors import CORSMiddleware from dotenv import load_dotenv -import plotly.graph_objects as go import pandas as pd import csv import os load_dotenv() -CORS_ORIGINS = [ - origin for origin in os.getenv("CORS_ORIGINS", "").split(",") if origin -] +CORS_ORIGINS = [origin for origin in os.getenv("CORS_ORIGINS", "").split(",") if origin] csvFiles = ["best_case.csv", "most_likely_case.csv", "worst_case.csv"] -campusDict = {"Pilani":0, "Goa":1, "Hyderabad":2 } +campusDict = {"Pilani": 0, "Goa": 1, "Hyderabad": 2} campusArr = ["Pilani", "Goa", "Hyderabad"] dfs = [] tableData = [[] for _ in range(9)] @@ -35,12 +32,12 @@ df["marks"] = df["marks"].astype(int) for case_idx in range(3): path = "predictions/" + csvFiles[case_idx] try: - with open(path, newline='', encoding='utf-8') as csv_file: - csv_reader = csv.reader(csv_file, delimiter=',') + with open(path, newline="", encoding="utf-8") as csv_file: + csv_reader = csv.reader(csv_file, delimiter=",") for row in csv_reader: if row[0] in campusDict: campus_idx = campusDict[row[0]] - tableData[campus_idx*3+case_idx].append(row) + tableData[campus_idx * 3 + case_idx].append(row) except FileNotFoundError: print(f"Prediction file {path} not found, skipping.") @@ -53,66 +50,42 @@ app.add_middleware( allow_origins=origins, allow_credentials=False, allow_methods=["*"], - allow_headers=["*"] + allow_headers=["*"], ) -def get_df_by_campus(campus: int = Query(0, ge=0, le=2)): + +def get_df_by_campus(campus: int = 0): try: campus_name = campusArr[campus] except IndexError: raise HTTPException(status_code=400, detail="Invalid Campus Index") - - ndf = df[df["campus"]==campus_name].iloc[:, -3:] + + ndf = df[df["campus"] == campus_name][["year", "branch", "marks"]] return ndf + @app.get("/graph") def get_graph(campus: int = Query(0, ge=0, le=2)): - campus_data = get_df_by_campus(campus) - fig = go.Figure() - + branches = [] for branch, values in campus_data.groupby("branch"): - fig.add_trace(go.Scatter( - x=values["year"], - y=values["marks"], - mode="lines+markers", - name=branch + branches.append( + { + "name": branch, + "years": values["year"].tolist(), + "marks": values["marks"].tolist(), + } ) - ) - fig.update_layout( - template="plotly_dark", - legend_title="Branches", - hovermode="x", - xaxis=dict( - showspikes=True, - spikemode="across", - spikesnap="cursor", - spikethickness=1, - spikecolor="rgba(255,255,255,0.6)" - ), - margin=dict(l=20, r=20, t=30, b=30) - ) - - fig.update_xaxes( - tickmode="linear", - dtick=1, - title="Year" - ) - - fig.update_yaxes( - title="Marks" - ) - - return fig.to_dict() + return {"branches": branches} @app.get("/table") def get_table(campus: int = Query(0, ge=0, le=2), scenario: int = Query(0, ge=0, le=2)): try: - tableRows = tableData[campus*3+scenario] + tableRows = tableData[campus * 3 + scenario] except IndexError: raise HTTPException(400, "Invalid Scenario or Campus index") - + return tableRows diff --git a/frontend/src/components/ui/GraphPlot.tsx b/frontend/src/components/ui/GraphPlot.tsx index 1ff7e67..0b475e7 100644 --- a/frontend/src/components/ui/GraphPlot.tsx +++ b/frontend/src/components/ui/GraphPlot.tsx @@ -4,8 +4,28 @@ import Plotly from "plotly.js-basic-dist"; import createPlotlyComponent from "react-plotly.js/factory"; import { useTheme } from "@/lib/themeContext"; +interface BranchData { + name: string; + years: number[]; + marks: number[]; +} + +interface GraphResponse { + branches: BranchData[]; +} + +interface Trace { + x: number[]; + y: number[]; + name: string; + type: 'scatter'; + mode: 'lines+markers'; + line?: { color?: string; width?: number }; + marker?: { size?: number; line?: { width?: number; color?: string } }; +} + interface PlotParams { - data?: any[]; + data?: Trace[]; layout?: any; } @@ -27,6 +47,29 @@ const formConfig = [ }, ] as const; +const PHOENIX_PATTERNS = [ + /computer science/i, + /electrical/i, + /electronics/i, + /mathematics.{0,3}(computing|and)/i, +]; + +const MSC_PATTERNS = [ + /M\.?Sc\.?/i, +]; + +function isBE(branchName: string): boolean { + return !MSC_PATTERNS.some((pattern) => pattern.test(branchName)); +} + +function isMSc(branchName: string): boolean { + return MSC_PATTERNS.some((pattern) => pattern.test(branchName)); +} + +function isPhoenix(branchName: string): boolean { + return PHOENIX_PATTERNS.some((pattern) => pattern.test(branchName)); +} + function GraphPlot() { const { theme } = useTheme(); const [graph, setGraph] = useState({}); @@ -54,8 +97,28 @@ function GraphPlot() { try { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); - const data = await res.json(); - setGraph(data); + const response: GraphResponse = await res.json(); + + const traces: Trace[] = response.branches.map((branch) => ({ + x: branch.years, + y: branch.marks, + name: branch.name, + type: 'scatter', + mode: 'lines+markers', + })); + + setGraph({ + data: traces, + layout: { + title: { + text: 'Cutoff Trends', + font: { + family: '"JetBrains Mono", monospace', + size: isMobile ? 14 : 18, + }, + }, + }, + }); setIsLoaded(true); } catch (err) { console.error("Failed to load Plot. Error: ", err); diff --git a/frontend/tsconfig.app.tsbuildinfo b/frontend/tsconfig.app.tsbuildinfo index a4657d1..ab8bef4 100644 --- a/frontend/tsconfig.app.tsbuildinfo +++ b/frontend/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/about.tsx","./src/app.tsx","./src/footer.tsx","./src/header.tsx","./src/home.tsx","./src/working.tsx","./src/main.tsx","./src/react-plotly.d.ts","./src/vite-env.d.ts","./src/components/ui/dropdown.tsx","./src/components/ui/graphplot.tsx","./src/components/ui/predicttable.tsx","./src/components/ui/profilecard.tsx","./src/lib/themecontext.tsx","./src/lib/utils.tsx","./src/lib/hooks/useappseo.ts"],"version":"5.8.3"} \ No newline at end of file +{"root":["./src/about.tsx","./src/app.tsx","./src/footer.tsx","./src/header.tsx","./src/home.tsx","./src/working.tsx","./src/main.tsx","./src/react-plotly.d.ts","./src/vite-env.d.ts","./src/components/ui/dropdown.tsx","./src/components/ui/graphplot.tsx","./src/components/ui/predicttable.tsx","./src/components/ui/profilecard.tsx","./src/lib/themecontext.tsx","./src/lib/utils.tsx","./src/lib/hooks/useappseo.ts"],"errors":true,"version":"5.8.3"} \ No newline at end of file