diff --git a/analysis.py b/analysis.py index a9e2264..2a95135 100644 --- a/analysis.py +++ b/analysis.py @@ -6,8 +6,9 @@ from fastapi.responses import JSONResponse from pydantic import BaseModel, Field from sqlmodel import Session, func, select from sqlmodel.sql.expression import SelectOfScalar -from db import Chemistry, Player, engine +from db import Chemistry, MVPRanking, Player, engine import networkx as nx +import numpy as np import matplotlib matplotlib.use("agg") @@ -18,6 +19,7 @@ analysis_router = APIRouter(prefix="/analysis") C = Chemistry +R = MVPRanking P = Player @@ -192,9 +194,31 @@ async def render_sociogram(params: Params): return {"image": encoded_image} +def mvp(): + ranks = dict() + with Session(engine) as session: + subquery = ( + select(R.user, func.max(R.time).label("latest")) + .where(R.time > datetime(2025, 2, 8)) + .group_by(R.user) + .subquery() + ) + statement2 = select(R).join( + subquery, (R.user == subquery.c.user) & (R.time == subquery.c.latest) + ) + for r in session.exec(statement2): + for i, p in enumerate(r.mvps): + ranks[p] = ranks.get(p, []) + [i + 1] + return [ + {"name": p, "rank": f"{np.mean(v):.02f}", "std": f"{np.std(v):.02f}"} + for p, v in ranks.items() + ] + + analysis_router.add_api_route("/json", endpoint=sociogram_json, methods=["GET"]) analysis_router.add_api_route("/graph_json", endpoint=graph_json, methods=["GET"]) analysis_router.add_api_route("/image", endpoint=render_sociogram, methods=["POST"]) +analysis_router.add_api_route("/mvp", endpoint=mvp, methods=["GET"]) if __name__ == "__main__": with Session(engine) as session: diff --git a/package.json b/package.json index abcf61f..7cc8275 100644 --- a/package.json +++ b/package.json @@ -10,16 +10,16 @@ "preview": "vite preview" }, "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "18.3.1", + "react-dom": "18.3.1", "react-sortablejs": "^6.1.4", "reagraph": "^4.21.2", "sortablejs": "^1.15.6" }, "devDependencies": { "@eslint/js": "^9.17.0", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", + "@types/react": "18.3.18", + "@types/react-dom": "18.3.5", "@types/sortablejs": "^1.15.8", "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.17.0", diff --git a/src/Analysis.tsx b/src/Analysis.tsx index e1b2b75..2d25cfb 100644 --- a/src/Analysis.tsx +++ b/src/Analysis.tsx @@ -42,7 +42,7 @@ interface DeferredProps { } -let timeoutID: number | null = null; +let timeoutID: NodeJS.Timeout | null = null; export default function Analysis() { const [image, setImage] = useState(""); const [params, setParams] = useState({ diff --git a/src/App.tsx b/src/App.tsx index e0b7073..eac95a6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import Rankings from "./Rankings"; import { BrowserRouter, Routes, Route } from "react-router"; import { SessionProvider } from "./Session"; import { GraphComponent } from "./Network"; +import MVPChart from "./MVPChart"; function App() { return ( @@ -13,16 +14,25 @@ function App() {
} /> + } /> + } /> + + + + + } /> +