memory-distribution-chart.jsx•9.42 kB
import React from 'react';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
/**
* Memory Distribution Chart Component
*
* A comprehensive visualization component for displaying monthly memory storage
* distribution with insights, statistics, and interactive features.
*
* Features:
* - Responsive bar chart with monthly distribution
* - Custom tooltips with percentages
* - Statistics cards for key metrics
* - Automatic insights generation
* - Professional styling and layout
*
* Usage:
* 1. Install dependencies: npm install recharts
* 2. Import and use: <MemoryDistributionChart data={yourData} />
* 3. Or use with sample data as shown below
*/
const MemoryDistributionChart = ({ data = null, title = "Memory Storage Distribution by Month" }) => {
// Sample data based on real MCP Memory Service analysis
// Replace with actual data from your analytics pipeline
const defaultData = [
{ month: "Jan 2025", count: 50, monthKey: "2025-01" },
{ month: "Feb 2025", count: 15, monthKey: "2025-02" },
{ month: "Mar 2025", count: 8, monthKey: "2025-03" },
{ month: "Apr 2025", count: 12, monthKey: "2025-04" },
{ month: "May 2025", count: 4, monthKey: "2025-05" },
{ month: "Jun 2025", count: 45, monthKey: "2025-06" }
];
const monthlyData = data || defaultData;
const totalMemories = monthlyData.reduce((sum, item) => sum + item.count, 0);
// Calculate statistics
const peakMonth = monthlyData.reduce((max, item) =>
item.count > max.count ? item : max, monthlyData[0]);
const averagePerMonth = (totalMemories / monthlyData.length).toFixed(1);
// Find most recent month with data
const recentMonth = monthlyData[monthlyData.length - 1];
// Custom tooltip component
const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
const data = payload[0].payload;
const percentage = ((data.count / totalMemories) * 100).toFixed(1);
return (
<div className="bg-white p-3 border border-gray-300 rounded-lg shadow-lg">
<p className="font-semibold text-gray-800">{label}</p>
<p className="text-blue-600">
<span className="font-medium">Memories: </span>
{data.count}
</p>
<p className="text-gray-600">
<span className="font-medium">Percentage: </span>
{percentage}%
</p>
</div>
);
}
return null;
};
// Custom label function for bars
const renderCustomLabel = (entry) => {
if (entry.count > 5) { // Only show labels for bars with more than 5 memories
return entry.count;
}
return null;
};
// Generate insights based on data patterns
const generateInsights = () => {
const insights = [];
// Peak activity insight
const peakPercentage = ((peakMonth.count / totalMemories) * 100).toFixed(1);
insights.push(`Peak activity in ${peakMonth.month} (${peakPercentage}% of total memories)`);
// Recent activity insight
const recentPercentage = ((recentMonth.count / totalMemories) * 100).toFixed(1);
if (recentMonth.count > averagePerMonth) {
insights.push(`High recent activity: ${recentMonth.month} above average`);
}
// Growth pattern insight
const firstMonth = monthlyData[0];
const lastMonth = monthlyData[monthlyData.length - 1];
if (lastMonth.count > firstMonth.count * 0.8) {
insights.push(`Sustained activity: Recent months maintain high productivity`);
}
return insights;
};
const insights = generateInsights();
return (
<div className="w-full max-w-6xl mx-auto p-6 bg-gray-50 rounded-lg">
{/* Header Section */}
<div className="mb-6">
<h2 className="text-2xl font-bold text-gray-800 mb-2">
{title}
</h2>
<p className="text-gray-600">
Total memories analyzed: <span className="font-semibold text-blue-600">{totalMemories}</span> memories
</p>
</div>
{/* Main Chart */}
<div className="bg-white p-4 rounded-lg shadow-sm mb-6">
<ResponsiveContainer width="100%" height={400}>
<BarChart
data={monthlyData}
margin={{
top: 20,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis
dataKey="month"
tick={{ fontSize: 12 }}
tickLine={{ stroke: '#d1d5db' }}
axisLine={{ stroke: '#d1d5db' }}
/>
<YAxis
tick={{ fontSize: 12 }}
tickLine={{ stroke: '#d1d5db' }}
axisLine={{ stroke: '#d1d5db' }}
label={{
value: 'Number of Memories',
angle: -90,
position: 'insideLeft',
style: { textAnchor: 'middle', fontSize: '12px', fill: '#6b7280' }
}}
/>
<Tooltip content={<CustomTooltip />} />
<Legend />
<Bar
dataKey="count"
name="Memories Stored"
fill="#3b82f6"
radius={[4, 4, 0, 0]}
label={renderCustomLabel}
/>
</BarChart>
</ResponsiveContainer>
</div>
{/* Statistics Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div className="bg-blue-50 p-4 rounded-lg">
<h3 className="font-semibold text-blue-800 mb-2">Peak Month</h3>
<p className="text-lg font-bold text-blue-600">{peakMonth.month}</p>
<p className="text-sm text-blue-600">
{peakMonth.count} memories ({((peakMonth.count / totalMemories) * 100).toFixed(1)}%)
</p>
</div>
<div className="bg-green-50 p-4 rounded-lg">
<h3 className="font-semibold text-green-800 mb-2">Recent Activity</h3>
<p className="text-lg font-bold text-green-600">{recentMonth.month}</p>
<p className="text-sm text-green-600">
{recentMonth.count} memories ({((recentMonth.count / totalMemories) * 100).toFixed(1)}%)
</p>
</div>
<div className="bg-amber-50 p-4 rounded-lg">
<h3 className="font-semibold text-amber-800 mb-2">Average/Month</h3>
<p className="text-lg font-bold text-amber-600">{averagePerMonth}</p>
<p className="text-sm text-amber-600">memories per month</p>
</div>
</div>
{/* Insights Section */}
<div className="bg-white p-4 rounded-lg shadow-sm">
<h3 className="font-semibold text-gray-800 mb-3">📊 Data Insights</h3>
<div className="space-y-2">
{insights.map((insight, index) => (
<div key={index} className="flex items-start">
<span className="text-blue-500 mr-2">•</span>
<p className="text-sm text-gray-600">{insight}</p>
</div>
))}
</div>
<div className="mt-4 pt-4 border-t border-gray-200">
<p className="text-xs text-gray-500">
<strong>Analysis Pattern:</strong> This distribution shows typical software development
lifecycle phases - high initial activity (project setup), consolidation periods,
and renewed intensive development phases.
</p>
</div>
</div>
</div>
);
};
export default MemoryDistributionChart;
/**
* Usage Examples:
*
* 1. Basic Usage (with sample data):
* <MemoryDistributionChart />
*
* 2. With Custom Data:
* const myData = [
* { month: "Jan 2025", count: 25, monthKey: "2025-01" },
* { month: "Feb 2025", count: 30, monthKey: "2025-02" },
* // ... more data
* ];
* <MemoryDistributionChart data={myData} title="My Project Analysis" />
*
* 3. Integration with MCP Memory Service:
*
* async function loadMemoryData() {
* const memories = await recall_memory({
* "query": "memories from this year",
* "n_results": 500
* });
*
* // Process memories into chart format
* const processedData = processMemoriesForChart(memories);
* return processedData;
* }
*
* function processMemoriesForChart(memories) {
* const monthlyDistribution = {};
*
* memories.forEach(memory => {
* const date = new Date(memory.timestamp);
* const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
*
* if (!monthlyDistribution[monthKey]) {
* monthlyDistribution[monthKey] = 0;
* }
* monthlyDistribution[monthKey]++;
* });
*
* return Object.entries(monthlyDistribution)
* .sort(([a], [b]) => a.localeCompare(b))
* .map(([month, count]) => {
* const [year, monthNum] = month.split('-');
* const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
* 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
* const monthName = monthNames[parseInt(monthNum) - 1];
*
* return {
* month: `${monthName} ${year}`,
* count: count,
* monthKey: month
* };
* });
* }
*
* Dependencies:
* npm install recharts
*
* For Tailwind CSS styling, ensure you have Tailwind configured in your project.
*/