- Codex CLIはD3.js・Chart.js・Rechartsなど主要チャートライブラリのコードを自然言語から高精度に生成できる
- CSVやJSON形式のデータを渡すだけで、データに最適なグラフ種類を自動選択・生成してくれる
- リアルタイムダッシュボードの構築では、WebSocket連携やAPI統合のコードも一括で生成可能
「売上データのグラフを作りたいけど、D3.jsのAPI複雑すぎて毎回ドキュメント見直してる…」 「ダッシュボードのチャートコンポーネント、1つ作るのに半日かかる…」
データ可視化は多くのWebアプリに必須の機能ですが、チャートライブラリのAPI習得と細かなカスタマイズに時間を取られがちです。OpenAI Codex CLIを活用すれば、自然言語でグラフの要件を伝えるだけで、高品質なチャートコードを瞬時に生成できます。
この記事では、Codex CLIを使ったデータ可視化・ダッシュボード開発の実践テクニックを、主要ライブラリごとに詳しく解説します。
- Codex CLIでD3.js・Chart.js・Rechartsのチャートを効率的に生成する方法
- データ形式に応じた最適なグラフ種類の選択指針
- リアルタイムダッシュボードの構築手順
- SES現場でのデータ可視化案件に活かせるテクニック
データ可視化ライブラリの選択指針
主要ライブラリの比較
データ可視化に使えるJavaScriptライブラリは多数ありますが、SES現場で特によく使われるのは以下の4つです。
| ライブラリ | 特徴 | 学習コスト | カスタマイズ性 | React対応 |
|---|---|---|---|---|
| D3.js | 最も柔軟、SVG直接操作 | 高い | ◎ 無限 | △ ラッパー必要 |
| Chart.js | 簡単・軽量・Canvas描画 | 低い | ○ 十分 | ○ react-chartjs-2 |
| Recharts | React特化・宣言的API | 低い | ○ 十分 | ◎ ネイティブ |
| Apache ECharts | 大規模データ対応 | 中程度 | ◎ 豊富 | ○ echarts-for-react |
Codex CLIはこれらすべてのライブラリに対応しており、プロンプトでライブラリを指定するだけで適切なコードを生成します。
Codex CLIでライブラリ選択を相談する
codex "以下のデータ可視化要件に最適なライブラリを選んで理由も教えて:
- 月別売上の棒グラフ(5系列)
- リアルタイム更新(5秒間隔)
- React + TypeScript環境
- ツールチップとドリルダウン機能
- データポイント数: 最大1000"
Codex CLIの回答例:
推奨: Recharts
理由:
1. React環境でのネイティブサポート - JSXで宣言的にチャートを定義可能
2. TypeScriptの型定義が充実
3. 1000データポイントはSVGベースで十分なパフォーマンス
4. ツールチップはビルトイン、ドリルダウンはonClickハンドラで実装可能
5. リアルタイム更新はReactの状態管理で自然に対応
D3.jsほどの自由度は不要な要件。Chart.jsはCanvas描画のため
ツールチップのカスタマイズがやや制限される。
Chart.jsでグラフを生成する
基本的な棒グラフの生成
まず、最も利用頻度の高いChart.jsでの棒グラフ生成から見ていきましょう。
codex "Chart.jsとreact-chartjs-2で月別売上棒グラフコンポーネントを作って。
TypeScriptで、以下の要件:
- 月別の売上データ(金額と件数の2軸)
- レスポンシブ対応
- ツールチップに通貨フォーマット(¥)
- 棒グラフの色はブランドカラー(#4285f4, #34a853)
- 件数は折れ線グラフで重ねる(複合チャート)"
Codex CLIが生成するコード:
// components/charts/MonthlySalesChart.tsx
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
LineElement,
PointElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
import { Chart } from 'react-chartjs-2';
import type { ChartData, ChartOptions } from 'chart.js';
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
LineElement,
PointElement,
Title,
Tooltip,
Legend
);
interface SalesData {
month: string;
revenue: number;
count: number;
}
interface Props {
data: SalesData[];
title?: string;
}
export function MonthlySalesChart({ data, title = '月別売上推移' }: Props) {
const chartData: ChartData<'bar' | 'line'> = {
labels: data.map(d => d.month),
datasets: [
{
type: 'bar' as const,
label: '売上金額',
data: data.map(d => d.revenue),
backgroundColor: 'rgba(66, 133, 244, 0.8)',
borderColor: '#4285f4',
borderWidth: 1,
yAxisID: 'y',
order: 2,
},
{
type: 'line' as const,
label: '受注件数',
data: data.map(d => d.count),
borderColor: '#34a853',
backgroundColor: 'rgba(52, 168, 83, 0.1)',
borderWidth: 2,
pointRadius: 4,
pointHoverRadius: 6,
fill: true,
yAxisID: 'y1',
order: 1,
},
],
};
const options: ChartOptions<'bar'> = {
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: title,
font: { size: 16, weight: 'bold' },
},
tooltip: {
callbacks: {
label: (context) => {
const label = context.dataset.label ?? '';
const value = context.parsed.y;
if (label === '売上金額') {
return `${label}: ¥${value.toLocaleString()}`;
}
return `${label}: ${value}件`;
},
},
},
legend: {
position: 'top',
},
},
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
title: { display: true, text: '売上金額 (¥)' },
ticks: {
callback: (value) => `¥${Number(value).toLocaleString()}`,
},
},
y1: {
type: 'linear',
display: true,
position: 'right',
title: { display: true, text: '受注件数' },
grid: { drawOnChartArea: false },
ticks: {
callback: (value) => `${value}件`,
},
},
},
};
return (
<div style={{ height: '400px', width: '100%' }}>
<Chart type="bar" data={chartData} options={options} />
</div>
);
}
円グラフ・ドーナツグラフ
codex "Chart.jsでSES案件のスキル別割合をドーナツグラフで表示するコンポーネントを作って。
中央にパーセンテージ表示、クリックでドリルダウン対応"
// components/charts/SkillDistributionChart.tsx
import { Doughnut } from 'react-chartjs-2';
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';
import { useState } from 'react';
ChartJS.register(ArcElement, Tooltip, Legend);
interface SkillData {
skill: string;
count: number;
subSkills?: { name: string; count: number }[];
}
interface Props {
data: SkillData[];
onDrillDown?: (skill: string) => void;
}
export function SkillDistributionChart({ data, onDrillDown }: Props) {
const [selectedSkill, setSelectedSkill] = useState<string | null>(null);
const total = data.reduce((sum, d) => sum + d.count, 0);
const colors = [
'#4285f4', '#ea4335', '#fbbc04', '#34a853',
'#ff6d01', '#46bdc6', '#7baaf7', '#f07b72',
];
const chartData = {
labels: data.map(d => d.skill),
datasets: [{
data: data.map(d => d.count),
backgroundColor: colors.slice(0, data.length),
borderWidth: 2,
borderColor: '#ffffff',
}],
};
const centerTextPlugin = {
id: 'centerText',
afterDraw(chart: ChartJS) {
const { ctx, width, height } = chart;
ctx.save();
ctx.font = 'bold 24px sans-serif';
ctx.fillStyle = '#333';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(`${total}件`, width / 2, height / 2 - 10);
ctx.font = '14px sans-serif';
ctx.fillStyle = '#666';
ctx.fillText('総案件数', width / 2, height / 2 + 15);
ctx.restore();
},
};
const options = {
responsive: true,
cutout: '65%',
plugins: {
legend: { position: 'right' as const },
tooltip: {
callbacks: {
label: (context: { label: string; parsed: number }) => {
const pct = ((context.parsed / total) * 100).toFixed(1);
return `${context.label}: ${context.parsed}件 (${pct}%)`;
},
},
},
},
onClick: (_: unknown, elements: { index: number }[]) => {
if (elements.length > 0) {
const skill = data[elements[0].index].skill;
setSelectedSkill(skill);
onDrillDown?.(skill);
}
},
};
return (
<div style={{ maxWidth: '500px', margin: '0 auto' }}>
<Doughnut data={chartData} options={options} plugins={[centerTextPlugin]} />
{selectedSkill && (
<p className="text-center mt-2 text-blue-600">
{selectedSkill}の詳細を表示中
</p>
)}
</div>
);
}
D3.jsで高度なチャートを作成
ヒートマップの生成
D3.jsは複雑なカスタムチャートを作る際に必要になります。Codex CLIにD3.jsのコードを生成させましょう。
codex "D3.jsでGitHubの草(contribution graph)のようなヒートマップコンポーネントをReact + TypeScriptで作って。
- 過去1年分のデータを週×日で表示
- 色の濃さで件数を表現(緑グラデーション)
- ツールチップで日付と件数を表示
- セルサイズは12px、gap 2px"
// components/charts/ContributionHeatmap.tsx
'use client';
import { useEffect, useRef } from 'react';
import * as d3 from 'd3';
interface DayData {
date: string; // YYYY-MM-DD
count: number;
}
interface Props {
data: DayData[];
colorScheme?: string[];
}
export function ContributionHeatmap({
data,
colorScheme = ['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39'],
}: Props) {
const svgRef = useRef<SVGSVGElement>(null);
const tooltipRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!svgRef.current || !data.length) return;
const cellSize = 12;
const gap = 2;
const margin = { top: 20, right: 10, bottom: 20, left: 30 };
const svg = d3.select(svgRef.current);
svg.selectAll('*').remove();
const maxCount = d3.max(data, d => d.count) ?? 0;
const colorScale = d3.scaleQuantize<string>()
.domain([0, maxCount])
.range(colorScheme);
const dataMap = new Map(data.map(d => [d.date, d.count]));
// Generate all days in the past year
const today = new Date();
const oneYearAgo = new Date(today);
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
const days: { date: Date; count: number }[] = [];
const current = new Date(oneYearAgo);
while (current <= today) {
const key = current.toISOString().slice(0, 10);
days.push({ date: new Date(current), count: dataMap.get(key) ?? 0 });
current.setDate(current.getDate() + 1);
}
const weeks = d3.group(days, d => d3.timeWeek.count(oneYearAgo, d.date));
const weekLabels = ['', '月', '', '水', '', '金', ''];
// Day labels
svg.selectAll('.day-label')
.data(weekLabels)
.join('text')
.attr('class', 'day-label')
.attr('x', margin.left - 5)
.attr('y', (_, i) => margin.top + i * (cellSize + gap) + cellSize)
.attr('text-anchor', 'end')
.attr('font-size', '10px')
.attr('fill', '#666')
.text(d => d);
const tooltip = d3.select(tooltipRef.current);
// Cells
weeks.forEach((weekDays, weekIndex) => {
svg.selectAll(`.cell-${weekIndex}`)
.data(weekDays)
.join('rect')
.attr('x', margin.left + weekIndex * (cellSize + gap))
.attr('y', d => margin.top + d.date.getDay() * (cellSize + gap))
.attr('width', cellSize)
.attr('height', cellSize)
.attr('rx', 2)
.attr('fill', d => d.count === 0 ? colorScheme[0] : colorScale(d.count))
.on('mouseover', (event, d) => {
tooltip
.style('display', 'block')
.style('left', `${event.pageX + 10}px`)
.style('top', `${event.pageY - 30}px`)
.html(`<strong>${d.date.toLocaleDateString('ja-JP')}</strong><br/>${d.count}件`);
})
.on('mouseout', () => {
tooltip.style('display', 'none');
});
});
const totalWeeks = weeks.size;
svg.attr('width', margin.left + totalWeeks * (cellSize + gap) + margin.right)
.attr('height', margin.top + 7 * (cellSize + gap) + margin.bottom);
}, [data, colorScheme]);
return (
<div style={{ position: 'relative', overflowX: 'auto' }}>
<svg ref={svgRef} />
<div
ref={tooltipRef}
style={{
display: 'none',
position: 'absolute',
background: 'rgba(0,0,0,0.8)',
color: 'white',
padding: '6px 10px',
borderRadius: '4px',
fontSize: '12px',
pointerEvents: 'none',
zIndex: 10,
}}
/>
</div>
);
}

Rechartsでダッシュボードを構築
ダッシュボード全体の設計
Rechartsは宣言的なAPIでReactとの親和性が最も高く、ダッシュボード開発に最適です。
codex "Rechartsを使ったSES事業のダッシュボードを設計して。以下のチャートを含む:
1. 月別売上推移(棒グラフ + 目標ライン)
2. スキル別案件分布(円グラフ)
3. エンジニア稼働率推移(エリアチャート)
4. 地域別案件ヒートマップ
5. KPIカード(売上・利益率・稼働率・新規契約数)
全てTypeScript + レスポンシブ対応で"
KPIカードコンポーネント:
// components/dashboard/KpiCards.tsx
interface KpiData {
title: string;
value: string;
change: number;
changeLabel: string;
icon: string;
}
export function KpiCards({ data }: { data: KpiData[] }) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{data.map((kpi) => (
<div key={kpi.title} className="bg-white rounded-lg shadow p-6">
<div className="flex items-center justify-between">
<span className="text-2xl">{kpi.icon}</span>
<span className={`text-sm font-medium ${
kpi.change >= 0 ? 'text-green-600' : 'text-red-600'
}`}>
{kpi.change >= 0 ? '↑' : '↓'} {Math.abs(kpi.change)}%
</span>
</div>
<p className="mt-2 text-3xl font-bold text-gray-900">{kpi.value}</p>
<p className="mt-1 text-sm text-gray-500">{kpi.title}</p>
<p className="text-xs text-gray-400">{kpi.changeLabel}</p>
</div>
))}
</div>
);
}
売上推移チャート(目標ライン付き):
// components/dashboard/RevenueChart.tsx
import {
BarChart, Bar, XAxis, YAxis, CartesianGrid,
Tooltip, Legend, ReferenceLine, ResponsiveContainer,
} from 'recharts';
interface RevenueData {
month: string;
revenue: number;
target: number;
profit: number;
}
interface Props {
data: RevenueData[];
monthlyTarget: number;
}
export function RevenueChart({ data, monthlyTarget }: Props) {
const formatYen = (value: number) => `¥${(value / 10000).toFixed(0)}万`;
return (
<div className="bg-white rounded-lg shadow p-6">
<h3 className="text-lg font-semibold mb-4">📈 月別売上推移</h3>
<ResponsiveContainer width="100%" height={350}>
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis dataKey="month" tick={{ fontSize: 12 }} />
<YAxis tickFormatter={formatYen} tick={{ fontSize: 12 }} />
<Tooltip
formatter={(value: number, name: string) => [
formatYen(value),
name === 'revenue' ? '売上' : '利益',
]}
labelStyle={{ fontWeight: 'bold' }}
/>
<Legend formatter={(value) => (value === 'revenue' ? '売上' : '利益')} />
<ReferenceLine
y={monthlyTarget}
label={{ value: '目標', position: 'right' }}
stroke="#ea4335"
strokeDasharray="5 5"
strokeWidth={2}
/>
<Bar dataKey="revenue" fill="#4285f4" radius={[4, 4, 0, 0]} />
<Bar dataKey="profit" fill="#34a853" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</div>
);
}
エンジニア稼働率エリアチャート
// components/dashboard/UtilizationChart.tsx
import {
AreaChart, Area, XAxis, YAxis, CartesianGrid,
Tooltip, ResponsiveContainer, ReferenceLine,
} from 'recharts';
interface UtilizationData {
month: string;
utilization: number;
benchmark: number;
}
export function UtilizationChart({ data }: { data: UtilizationData[] }) {
return (
<div className="bg-white rounded-lg shadow p-6">
<h3 className="text-lg font-semibold mb-4">👥 エンジニア稼働率推移</h3>
<ResponsiveContainer width="100%" height={300}>
<AreaChart data={data}>
<defs>
<linearGradient id="utilizationGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#4285f4" stopOpacity={0.3} />
<stop offset="95%" stopColor="#4285f4" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis dataKey="month" tick={{ fontSize: 12 }} />
<YAxis
domain={[0, 100]}
tickFormatter={(v) => `${v}%`}
tick={{ fontSize: 12 }}
/>
<Tooltip formatter={(value: number) => [`${value}%`, '稼働率']} />
<ReferenceLine
y={80}
label="目標80%"
stroke="#ea4335"
strokeDasharray="3 3"
/>
<Area
type="monotone"
dataKey="utilization"
stroke="#4285f4"
strokeWidth={2}
fill="url(#utilizationGradient)"
/>
</AreaChart>
</ResponsiveContainer>
</div>
);
}
リアルタイムダッシュボードの構築
WebSocket連携パターン
リアルタイムデータの可視化は、SES管理ツールなどで需要の高い機能です。
codex "WebSocketでリアルタイム更新されるダッシュボードを作って。
- データソース: WebSocket (ws://localhost:8080)
- 受信メッセージ: {type: 'metric', name: string, value: number, timestamp: string}
- 直近60秒のデータをローリング表示
- 接続ステータス表示(接続中/切断/再接続中)
- 自動再接続(指数バックオフ)"
// hooks/useRealtimeMetrics.ts
import { useState, useEffect, useCallback, useRef } from 'react';
interface Metric {
name: string;
value: number;
timestamp: string;
}
type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
export function useRealtimeMetrics(url: string, windowSeconds = 60) {
const [metrics, setMetrics] = useState<Metric[]>([]);
const [status, setStatus] = useState<ConnectionStatus>('connecting');
const wsRef = useRef<WebSocket | null>(null);
const retryCountRef = useRef(0);
const connect = useCallback(() => {
const ws = new WebSocket(url);
wsRef.current = ws;
ws.onopen = () => {
setStatus('connected');
retryCountRef.current = 0;
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'metric') {
setMetrics(prev => {
const cutoff = Date.now() - windowSeconds * 1000;
const filtered = prev.filter(
m => new Date(m.timestamp).getTime() > cutoff
);
return [...filtered, {
name: data.name,
value: data.value,
timestamp: data.timestamp,
}];
});
}
};
ws.onclose = () => {
setStatus('reconnecting');
const delay = Math.min(1000 * Math.pow(2, retryCountRef.current), 30000);
retryCountRef.current += 1;
setTimeout(connect, delay);
};
ws.onerror = () => ws.close();
}, [url, windowSeconds]);
useEffect(() => {
connect();
return () => wsRef.current?.close();
}, [connect]);
return { metrics, status };
}
リアルタイムチャートコンポーネント
// components/dashboard/RealtimeChart.tsx
'use client';
import { useRealtimeMetrics } from '@/hooks/useRealtimeMetrics';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from 'recharts';
export function RealtimeChart() {
const { metrics, status } = useRealtimeMetrics('ws://localhost:8080');
const statusColor = {
connecting: 'text-yellow-500',
connected: 'text-green-500',
disconnected: 'text-red-500',
reconnecting: 'text-orange-500',
};
const chartData = metrics
.filter(m => m.name === 'cpu_usage')
.map(m => ({
time: new Date(m.timestamp).toLocaleTimeString('ja-JP'),
value: m.value,
}));
return (
<div className="bg-white rounded-lg shadow p-6">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold">⚡ リアルタイムメトリクス</h3>
<span className={`text-sm ${statusColor[status]}`}>
● {status}
</span>
</div>
<ResponsiveContainer width="100%" height={250}>
<LineChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="time" tick={{ fontSize: 10 }} />
<YAxis domain={[0, 100]} tickFormatter={(v) => `${v}%`} />
<Line
type="monotone"
dataKey="value"
stroke="#4285f4"
strokeWidth={2}
dot={false}
isAnimationActive={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
);
}
CSVデータからチャートを自動生成
Codex CLIのデータ分析能力
Codex CLIにCSVファイルを渡して、適切なチャートを自動生成させることができます。
codex "このCSVデータを分析して、最適なチャートを3つ生成して。Rechartsで。
月,売上,コスト,利益,案件数,エンジニア数,稼働率
2026-01,15200000,11400000,3800000,42,35,85
2026-02,16800000,12600000,4200000,45,37,88
2026-03,14500000,10875000,3625000,38,33,82
...
"
Codex CLIは以下の分析を行い、チャートを生成します。
- トレンド分析: 売上・利益の推移 → 折れ線グラフ
- 構成比分析: コスト構造 → 積み上げ棒グラフ
- 相関分析: 稼働率と利益率の関係 → 散布図
SES現場でのデータ可視化案件
よくある要件パターン
SES現場でデータ可視化が求められる典型的な案件を紹介します。
1. 経営ダッシュボード
- KPIの一覧表示(売上・利益・顧客数)
- 前月比・前年比の比較チャート
- 部門別のドリルダウン
2. BI(ビジネスインテリジェンス)ツール
- SQLクエリ結果の自動可視化
- フィルタ・ドリルダウン・エクスポート
- ユーザーがチャート種類を選択可能
3. IoT/監視ダッシュボード
- リアルタイムセンサーデータの可視化
- 閾値超過時のアラート表示
- 時系列データのズーム・パン操作
4. レポート自動生成
- 定期レポートのPDF出力
- チャートを含むメール配信
- Slack/Teams連携での定期配信
単価への影響
データ可視化スキルはSES市場で評価が高まっています。
| スキルセット | 月額単価相場(2026年) |
|---|---|
| フロントエンド(React基本) | 60〜75万円 |
| D3.js / Chart.js 実装経験 | 70〜90万円 |
| ダッシュボード設計・構築 | 75〜95万円 |
| リアルタイムデータ可視化 | 80〜100万円 |
| 上記 + AI活用(Codex CLI等) | 85〜105万円 |
パフォーマンス最適化テクニック
大量データの描画最適化
codex "10万データポイントのチャートパフォーマンスを最適化して。
現在Rechartsで描画に5秒かかっている。
ダウンサンプリング、仮想化、Canvas描画への切り替えを検討して"
Codex CLIの提案するアプローチ:
- ダウンサンプリング: LTTB(Largest-Triangle-Three-Buckets)アルゴリズムで視覚的に重要なポイントのみ残す
- Canvas描画: SVGからCanvas(EChartsまたはuPlot)に切り替え
- 仮想スクロール: テーブルデータはTanStack Virtual で仮想化
- メモ化:
useMemoでチャートデータの再計算を防止
// utils/downsample.ts — LTTBアルゴリズム
export function lttbDownsample<T extends { x: number; y: number }>(
data: T[],
threshold: number
): T[] {
if (data.length <= threshold) return data;
const sampled: T[] = [data[0]];
const bucketSize = (data.length - 2) / (threshold - 2);
let a = 0;
for (let i = 0; i < threshold - 2; i++) {
const rangeStart = Math.floor((i + 1) * bucketSize) + 1;
const rangeEnd = Math.min(
Math.floor((i + 2) * bucketSize) + 1,
data.length
);
// Average point of next bucket
let avgX = 0, avgY = 0;
for (let j = rangeStart; j < rangeEnd; j++) {
avgX += data[j].x;
avgY += data[j].y;
}
avgX /= (rangeEnd - rangeStart);
avgY /= (rangeEnd - rangeStart);
// Find point with largest triangle area
let maxArea = -1;
let maxIndex = rangeStart;
for (let j = rangeStart; j < rangeEnd; j++) {
const area = Math.abs(
(data[a].x - avgX) * (data[j].y - data[a].y) -
(data[a].x - data[j].x) * (avgY - data[a].y)
) * 0.5;
if (area > maxArea) {
maxArea = area;
maxIndex = j;
}
}
sampled.push(data[maxIndex]);
a = maxIndex;
}
sampled.push(data[data.length - 1]);
return sampled;
}
まとめ — データ可視化をAIで加速する
Codex CLIとデータ可視化ライブラリの組み合わせは、SES現場でのダッシュボード開発を大幅に加速します。
- Chart.js: 手軽に美しいグラフを生成したい場合に最適。Codex CLIなら設定の細かなカスタマイズも瞬時に対応
- D3.js: カスタムチャートが必要な場合。Codex CLIが複雑なSVG操作コードを自動生成
- Recharts: Reactダッシュボードの定番。宣言的APIとCodex CLIの相性が抜群
- リアルタイム対応: WebSocket連携・自動再接続も含めたコードを一括生成可能
Codex CLI入門ガイドでまず基本を押さえ、フロントエンド開発ガイドと合わせて学習を進めることで、データ可視化のスキルを効率的に高められます。TypeScript開発ガイドの型安全なパターンも参考にしてください。