BeatSense / frontend /src /components /charts /eda-charts.tsx
devrup404's picture
BeatSense: unified FastAPI + Next.js deployment
f4102c2
Raw
History Blame Contribute Delete
4.45 kB
"use client";
import { useQuery } from "@tanstack/react-query";
import {
BarChart,
Bar,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
CartesianGrid,
ScatterChart,
Scatter,
Legend,
Cell,
PieChart,
Pie,
} from "recharts";
import { api } from "@/lib/api";
import { useT } from "@/i18n/context";
import { Card, CardContent } from "@/components/ui/card";
const TOOLTIP = {
contentStyle: {
background: "var(--popover)",
border: "1px solid var(--border)",
borderRadius: 8,
fontSize: 12,
color: "var(--popover-foreground)",
},
cursor: { fill: "var(--muted)", opacity: 0.3 },
};
export function EdaCharts() {
const { dict } = useT();
const { data, isLoading } = useQuery({ queryKey: ["eda"], queryFn: api.eda });
if (isLoading || !data) {
return (
<Card>
<CardContent className="p-10 text-center text-sm text-muted-foreground">
{dict.common.loading}
</CardContent>
</Card>
);
}
return (
<div className="grid gap-6 lg:grid-cols-2">
<ChartCard title={dict.eda.ageDist}>
<ResponsiveContainer width="100%" height={280}>
<BarChart data={data.age_dist}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
<XAxis dataKey="bin" tick={{ fontSize: 10 }} stroke="var(--muted-foreground)" />
<YAxis tick={{ fontSize: 10 }} stroke="var(--muted-foreground)" />
<Tooltip {...TOOLTIP} />
<Bar dataKey="count" fill="var(--primary)" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</ChartCard>
<ChartCard title={dict.eda.sexDist}>
<ResponsiveContainer width="100%" height={280}>
<PieChart>
<Pie
data={data.sex_dist}
dataKey="count"
nameKey="sex"
innerRadius={50}
outerRadius={90}
label
>
{data.sex_dist.map((_, i) => (
<Cell key={i} fill={i === 0 ? "var(--primary)" : "var(--accent)"} />
))}
</Pie>
<Tooltip {...TOOLTIP} />
<Legend wrapperStyle={{ fontSize: 12 }} />
</PieChart>
</ResponsiveContainer>
</ChartCard>
<ChartCard title={dict.eda.chestPainDist}>
<ResponsiveContainer width="100%" height={280}>
<BarChart data={data.chest_pain_dist}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
<XAxis dataKey="type" tick={{ fontSize: 11 }} stroke="var(--muted-foreground)" />
<YAxis tick={{ fontSize: 11 }} stroke="var(--muted-foreground)" />
<Tooltip {...TOOLTIP} />
<Bar dataKey="count" fill="var(--primary)" radius={[4, 4, 0, 0]} />
<Bar dataKey="risk_rate" fill="var(--destructive)" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</ChartCard>
<ChartCard title={dict.eda.maxHrVsAge}>
<ResponsiveContainer width="100%" height={280}>
<ScatterChart>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
<XAxis
dataKey="Age"
type="number"
tick={{ fontSize: 11 }}
stroke="var(--muted-foreground)"
name="Age"
/>
<YAxis
dataKey="MaxHR"
type="number"
tick={{ fontSize: 11 }}
stroke="var(--muted-foreground)"
name="MaxHR"
/>
<Tooltip {...TOOLTIP} />
<Scatter
data={data.scatter.filter((d) => d.HeartDisease === 0)}
fill="var(--success)"
name={dict.common.low}
/>
<Scatter
data={data.scatter.filter((d) => d.HeartDisease === 1)}
fill="var(--destructive)"
name={dict.common.high}
/>
<Legend wrapperStyle={{ fontSize: 12 }} />
</ScatterChart>
</ResponsiveContainer>
</ChartCard>
</div>
);
}
function ChartCard({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) {
return (
<Card>
<CardContent className="p-6">
<h2 className="mb-4 text-sm font-semibold uppercase tracking-wide text-muted-foreground">
{title}
</h2>
{children}
</CardContent>
</Card>
);
}