ludocomito's picture
init
d328b13
"use client"
import { useMemo } from "react"
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell, Legend } from "recharts"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
interface Dataset {
Name: string
Category: string
Description: string
Task: string
Data_Type: string
Source: string
"Paper link": string
Availability: string
Contact: string
}
interface DatasetStatisticsProps {
datasets: Dataset[]
selectedCategory: string | null
selectedDataType: string | null
selectedAvailability: string | null
onCategoryClick: (category: string) => void
onDataTypeClick: (dataType: string) => void
onAvailabilityClick: (availability: string) => void
}
const CATEGORY_COLORS = [
"#6366f1", // indigo
"#10b981", // emerald
"#f59e0b", // amber
"#3b82f6", // blue
"#8b5cf6", // violet
"#06b6d4", // cyan
]
const DATA_TYPE_COLORS = [
"#3b82f6", // blue
"#10b981", // emerald
"#6366f1", // indigo
"#f59e0b", // amber
"#8b5cf6", // violet
"#06b6d4", // cyan
]
const AVAILABILITY_COLORS = {
"Open source": "#3b82f6", // blue
"Gated": "#10b981", // emerald
"Unknown": "#6b7280", // gray
}
export function DatasetStatistics({
datasets,
selectedCategory,
selectedDataType,
selectedAvailability,
onCategoryClick,
onDataTypeClick,
onAvailabilityClick
}: DatasetStatisticsProps) {
const categoryData = useMemo(() => {
const counts: Record<string, number> = {}
datasets.forEach((dataset) => {
if (dataset.Category) {
counts[dataset.Category] = (counts[dataset.Category] || 0) + 1
}
})
return Object.entries(counts)
.map(([name, value]) => ({ name, value }))
.sort((a, b) => b.value - a.value)
}, [datasets])
const dataTypeData = useMemo(() => {
const counts: Record<string, number> = {}
datasets.forEach((dataset) => {
if (dataset.Data_Type) {
counts[dataset.Data_Type] = (counts[dataset.Data_Type] || 0) + 1
}
})
return Object.entries(counts)
.map(([name, value]) => ({ name, value }))
.sort((a, b) => b.value - a.value)
}, [datasets])
const availabilityData = useMemo(() => {
const counts: Record<string, number> = {}
datasets.forEach((dataset) => {
if (dataset.Availability) {
counts[dataset.Availability] = (counts[dataset.Availability] || 0) + 1
}
})
return Object.entries(counts).map(([name, value]) => ({ name, value }))
}, [datasets])
const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
return (
<div className="bg-popover border border-border rounded-lg shadow-lg p-3">
<p className="font-medium text-sm">{payload[0].payload.name}</p>
<p className="text-sm text-muted-foreground">Count: {payload[0].value}</p>
</div>
)
}
return null
}
const renderCustomBarLabel = (props: any) => {
const { x, y, width, height, value } = props
return (
<text
x={x + width + 5}
y={y + height / 2}
fill="currentColor"
className="text-sm font-medium fill-foreground"
textAnchor="start"
dominantBaseline="middle"
>
{value}
</text>
)
}
return (
<div className="space-y-6 mb-8">
{/* Top Row: By Data Type and Availability */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* By Data Type */}
<Card>
<CardHeader>
<CardTitle className="text-lg font-semibold">
By Data Type
{selectedDataType && (
<span className="text-sm font-normal text-muted-foreground ml-2">
(Click to clear filter)
</span>
)}
</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<BarChart
data={dataTypeData}
layout="vertical"
margin={{ top: 5, right: 40, left: 5, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" className="stroke-border" />
<XAxis type="number" className="text-xs" tick={{ fill: "currentColor" }} />
<YAxis
type="category"
dataKey="name"
width={100}
className="text-xs"
tick={{ fill: "currentColor" }}
/>
<Tooltip content={<CustomTooltip />} />
<Bar
dataKey="value"
radius={[0, 4, 4, 0]}
label={renderCustomBarLabel}
onClick={(data) => onDataTypeClick(data.name)}
cursor="pointer"
>
{dataTypeData.map((entry, index) => {
const isSelected = selectedDataType === entry.name
const shouldGreyscale = selectedDataType && !isSelected
const color = shouldGreyscale
? "#94a3b8"
: DATA_TYPE_COLORS[index % DATA_TYPE_COLORS.length]
return (
<Cell
key={`cell-${index}`}
fill={color}
opacity={shouldGreyscale ? 0.4 : 1}
/>
)
})}
</Bar>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
{/* Availability */}
<Card>
<CardHeader>
<CardTitle className="text-lg font-semibold">
Availability
{selectedAvailability && (
<span className="text-sm font-normal text-muted-foreground ml-2">
(Click to clear filter)
</span>
)}
</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={availabilityData}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, value, percent }) => `${name}: ${value}`}
outerRadius={80}
fill="#8884d8"
dataKey="value"
onClick={(data) => onAvailabilityClick(data.name)}
cursor="pointer"
>
{availabilityData.map((entry, index) => {
const isSelected = selectedAvailability === entry.name
const shouldGreyscale = selectedAvailability && !isSelected
const originalColor = AVAILABILITY_COLORS[entry.name as keyof typeof AVAILABILITY_COLORS] || "#6b7280"
const color = shouldGreyscale ? "#94a3b8" : originalColor
return (
<Cell
key={`cell-${index}`}
fill={color}
opacity={shouldGreyscale ? 0.4 : 1}
/>
)
})}
</Pie>
<Tooltip content={<CustomTooltip />} />
<Legend
verticalAlign="bottom"
height={36}
iconType="circle"
formatter={(value) => <span className="text-sm">{value}</span>}
/>
</PieChart>
</ResponsiveContainer>
</CardContent>
</Card>
</div>
{/* Bottom Row: By Category */}
<div className="grid grid-cols-1 gap-6">
<Card>
<CardHeader>
<CardTitle className="text-lg font-semibold">
By Category
{selectedCategory && (
<span className="text-sm font-normal text-muted-foreground ml-2">
(Click to clear filter)
</span>
)}
</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<BarChart
data={categoryData}
layout="vertical"
margin={{ top: 5, right: 40, left: 5, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" className="stroke-border" />
<XAxis type="number" className="text-xs" tick={{ fill: "currentColor" }} />
<YAxis
type="category"
dataKey="name"
width={180}
className="text-xs"
tick={{ fill: "currentColor" }}
/>
<Tooltip content={<CustomTooltip />} />
<Bar
dataKey="value"
radius={[0, 4, 4, 0]}
label={renderCustomBarLabel}
onClick={(data) => onCategoryClick(data.name)}
cursor="pointer"
>
{categoryData.map((entry, index) => {
const isSelected = selectedCategory === entry.name
const shouldGreyscale = selectedCategory && !isSelected
const color = shouldGreyscale
? "#94a3b8"
: CATEGORY_COLORS[index % CATEGORY_COLORS.length]
return (
<Cell
key={`cell-${index}`}
fill={color}
opacity={shouldGreyscale ? 0.4 : 1}
/>
)
})}
</Bar>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
</div>
</div>
)
}