はじめに
センサーデータやサーバーメトリクスのダッシュボードを作っていて、「データ点数が増えたらチャートがカクカクになった」という経験はありませんか?Chart.jsやEChartsは高機能で使いやすい反面、数万〜数十万点の時系列データを流し込むと、描画の遅延やメモリ消費が一気に目立ってきます。
そんな悩みを解決してくれるのが、今回紹介するuPlotです。ミニファイ後わずか約50KBという小ささながら、16万点を超えるデータポイントを約25msで描画してしまう、驚異的なパフォーマンスを持つチャートライブラリです。
uPlotとは
uPlotは、時系列データの可視化に特化したCanvas 2Dベースの超軽量チャートライブラリです。作者はJavaScriptフレームワークのベンチマークでも知られるLeon Sorokin氏で、「小さく・速く」という設計思想が徹底されています。折れ線・エリア・バー・OHLC(ローソク足)といったチャートを描画できます。
公式ベンチマークでは、166,650点のデータを含むインタラクティブなチャートを約25msで生成し、60fpsのライブストリーミング表示でもCPU使用率は約10%、メモリ消費は12MB程度に収まります。同条件でChart.jsはCPU 40%・77MB、EChartsはCPU 70%・85MBという結果が公表されており、その差は歴然です。
主な特徴
- 圧倒的な軽さと速さ - 約50KB(min)のバンドルサイズで、初期描画後は1msあたり約10万点というスループットを実現します
- 時系列に強い - 時間軸・数値軸の切り替え、IANAタイムゾーンとサマータイム(DST)のサポート、データストリーミングに対応しています
- 必要十分な機能 - 複数系列の表示切り替え、複数のY軸・スケール・グリッド、対数スケール、ズームと自動スケーリングを備えています
- あえて持たない機能 - アニメーションやデータ集計・スタック処理は意図的に非搭載です。描画に専念することで、この速度を実現しています
インストール
npmでインストールする場合は以下のコマンドを実行します。
# npm
npm install uplot
# yarn
yarn add uplot
# pnpm
pnpm add uplot
CDN経由でscriptタグから読み込むこともできます。CSSの読み込みを忘れやすいので注意してください(カーソルや凡例のスタイルに必要です)。
<link rel="stylesheet" href="https://unpkg.com/uplot/dist/uPlot.min.css">
<script src="https://unpkg.com/uplot/dist/uPlot.iife.min.js"></script>
ESModulesで使う場合は次のようにインポートします。
import uPlot from "uplot";
import "uplot/dist/uPlot.min.css";
基本的な使い方
uPlotの最大の特徴は、データを**列指向(columnar)**の配列で渡す点です。「1点ごとのオブジェクトの配列」ではなく、「X値の配列」と「系列ごとのY値の配列」を並べた二次元配列を使います。これがパフォーマンスの秘密のひとつです。
import uPlot from "uplot";
import "uplot/dist/uPlot.min.css";
// [x値の配列, 系列1のy値, 系列2のy値, ...]
const data = [
[1546300800, 1546387200, 1546473600], // Unixタイムスタンプ(秒)
[35, 71, 90], // CPU使用率
[90, 15, 64], // メモリ使用率
];
const opts = {
title: "サーバーメトリクス",
width: 800,
height: 400,
series: [
{}, // 先頭はX軸用(必須)
{
label: "CPU",
stroke: "red",
width: 1,
fill: "rgba(255, 0, 0, 0.1)",
},
{
label: "RAM",
stroke: "blue",
width: 1,
},
],
};
const chart = new uPlot(opts, data, document.getElementById("chart"));
いくつか押さえておきたいルールがあります。
- X値は昇順にソートされた一意な数値である必要があります(時系列なら秒単位のUnixタイムスタンプ)
- 欠損値は
nullで表現します - データに系列を入れるだけでは描画されず、
opts.seriesにも必ず定義が必要です
たったこれだけで、ズームやカーソル追従、凡例クリックによる系列の表示切り替えまで動くチャートが手に入ります。
実践的なユースケース
リアルタイムモニタリングダッシュボード
uPlotが最も輝くのは、データが刻々と追加されるライブモニタリングです。setData() を呼ぶだけで再描画され、60fpsでもCPU負荷はごくわずかです。
const maxPoints = 600; // 直近10分(1秒間隔)を保持
const data = [[], []];
const opts = {
title: "リアルタイムCPU使用率",
width: 800,
height: 300,
series: [
{},
{ label: "CPU %", stroke: "#0ea5e9", width: 2 },
],
scales: {
y: { range: [0, 100] }, // 0〜100%に固定
},
};
const chart = new uPlot(opts, data, document.getElementById("live"));
setInterval(() => {
const now = Math.floor(Date.now() / 1000);
const value = getCpuUsage(); // 計測値を返す自前の関数
data[0].push(now);
data[1].push(value);
// 古いデータを捨ててウィンドウをスライド
if (data[0].length > maxPoints) {
data[0].shift();
data[1].shift();
}
chart.setData(data);
}, 1000);
配列を差し替えて setData() するだけというシンプルさで、ストリーミンググラフが完成します。
Reactコンポーネントとして使う
Reactプロジェクトでは、useEffect でライフサイクルを管理するだけで組み込めます。公式の uplot-react パッケージもありますが、素のuPlotでも十分シンプルです。
import { useEffect, useRef } from "react";
import uPlot from "uplot";
import "uplot/dist/uPlot.min.css";
type Props = {
data: uPlot.AlignedData;
};
export function MetricsChart({ data }: Props) {
const containerRef = useRef<HTMLDivElement>(null);
const chartRef = useRef<uPlot | null>(null);
useEffect(() => {
if (!containerRef.current) return;
chartRef.current = new uPlot(
{
width: 800,
height: 300,
series: [{}, { label: "値", stroke: "#22c55e" }],
},
data,
containerRef.current
);
return () => chartRef.current?.destroy();
}, []);
// データ更新時はインスタンスを作り直さずsetDataで反映
useEffect(() => {
chartRef.current?.setData(data);
}, [data]);
return <div ref={containerRef} />;
}
TypeScriptの型定義(uPlot.d.ts)が同梱されているため、オプションの補完も効いて快適に開発できます。
数十万点のログデータを俯瞰する
APMツールやIoTの分析画面のように「まず全期間を俯瞰し、気になる箇所をズームで深掘りする」という使い方でも、uPlotはデータの間引きなしで応えてくれます。ドラッグによる範囲ズームは標準機能なので、特別な設定は不要です。対数スケールが必要な場合も、scales の設定を1行加えるだけです。
scales: {
y: {
distr: 3, // 対数スケール
},
},
まとめ
uPlotの魅力を振り返ってみましょう。
- 約50KBの超軽量ライブラリでありながら、16万点超のデータを約25msで描画する圧倒的なパフォーマンス
- 列指向のデータ形式とCanvas 2Dによる、時系列データに最適化された設計
- ズーム・複数軸・タイムゾーン対応・ストリーミングなど、モニタリング用途に必要な機能はひととおり搭載
一方で、アニメーションや円グラフのような装飾的なチャートは守備範囲外です。「見栄えのするプレゼン用グラフ」ならChart.jsやEChartsが、「大量の時系列データを高速に描画するダッシュボード」ならuPlotが適任、という住み分けで考えると選びやすいでしょう。
GitHubリポジトリの /demos ディレクトリには実行可能なサンプルが豊富に揃っています。まずは手元のメトリクスデータを流し込んで、その速さを体感してみてください。
