ようへいの日々精進XP

よかろうもん

シュッとグラフ画像が欲しい時に image-charts.com を使ったら助かったのでメモ

tl;dr

ある数値を集計して円グラフを描いてその画像を Slack に貼り付けたいなあと調べていたら image-charts.com なるサービスが提供されていたので利用してみました.

www.image-charts.com

Google Chart API も選択肢として検討しましたが, 画像を S3 バケットに保存したかったり, Node.js から利用したかったりという要件に合わなかった (探せていないだけかもしれませんが) 為, 今回は image-charts.com を利用することにしました.

developers.google.com

image-charts.com

API でグラフを生成することが出来る

image-charts.com のトップページに以下のように記載されています.

No need to spend hours to setup and develop a complex server-side solution. We spent months tuning our chart API generation infrastructure so you don't have to. One API call url = one chart.

スーパーざっくりと申し上げると, 簡単に REST API を利用してグラフイメージを生成することが出来るサービスです.

例えば, 以下のように curl を利用してリクエストを送信することで...

$ curl -s 'https://image-charts.com/chart?cht=p3&chs=700x100&chd=t:60,40&chl=Hello|World&chf=ps0-0,lg,45,ffeb3b,0.2,f44336,1|ps0-1,lg,45,8bc34a,0.2,009688,1' -o helloworld.png

helloworld.png を開くと以下のような円グラフ画像が生成されます.

f:id:inokara:20200503154036p:plain

また, パラメータに &chan を付与してリクエストを送信すると...

$ curl -s 'https://image-charts.com/chart?cht=p3&chs=700x100&chd=t:60,40&chl=Hello|World&chf=ps0-0,lg,45,ffeb3b,0.2,f44336,1|ps0-1,lg,45,8bc34a,0.2,009688,1&chan' -o helloworld.gif

以下のように GIF アニメーションの円グラフ画像が生成されます.

f:id:inokara:20200503154249g:plain

パラメータ

描画するグラフのタイプやサイズ, 出力のフォーマット (デフォルトは PNG) 等設定可能なパラメータが非常に多いです.

documentation.image-charts.com

詳細はドキュメントをご確認いただければと思いますが, 先述の円グラフリクエストに付与しているパラメータについて書きます.

パラメータ 用途 サンプル値
cht グラフのタイプ指定 (bvs = バー, p = 円, ls = 折れ線) p3
chs 出力する画像サイズ指定 700x100
chd データフォーマット指定 t:60,40
chl グラフラベル指定 Hello|World
chf グラフの塗りつぶし指定 ps0-0,lg,45,ffeb3b,0.2,f44336,1|ps0-1,lg,45,8bc34a,0.2,009688,1
chn GIF アニメーションで出力する

以下のように image-charts.com のサイト上で, 実際にパラメータを調整しながらグラフ画像を確認することが可能です.

f:id:inokara:20200503160659p:plain

Node.js から利用する

Image Charts Node.js Library

以下のように npm で提供されているので, yarn add image-charts 等で自身のプロジェクトに追加しましょう.

www.npmjs.com

雑なサンプルコード

Node.js (JavaScript) も Hello World な身分で恐縮ですが, 以下のような円グラフを描画するサンプルスクリプトを書きました.

const imageCharts = require('image-charts')({});
const fs = require("fs");

const buildGraphArgs = (graphData) => {
    let imageArgs = {};
    let datas = [];
    let labels = [];
    let legendLabels = [];
    const total = graphData.total
    let counts = 0;
    for (let i in graphData.values) {
        counts += graphData.values[i].count;
        percent = Math.round(graphData.values[i].count / total * 100);
        datas.push(percent);
        labels.push(percent + '%');
        legendLabels.push(graphData.values[i].name);
    }
    const others = Math.round((total - counts) / total * 100);
    datas.push(others);
    labels.push(others + '%');
    legendLabels.push('others');

    return {
      title: 'Percentage of Total', 
      size: [ 500, 300 ], 
      data: datas,
      labels: labels,
      legendLables: legendLabels
    };
};

// ここはサンプルを拝借
const buildImage = async (imageArgs) => {
    const pieChart = imageCharts.pie(imageArgs);
 
    try {
        const b = await pieChart.buffer();
        return b;
    } catch (err) {
        return Promise.reject(err);
    }
};

const main = async () => {
    graphData = {
      total: 100,
      values: [
        { name: 'aa', count: 30 },
        { name: 'bb', count: 18 },
        { name: 'cc', count: 12 },
      ]
    };

    imageArgs = buildGraphArgs(graphData);
    imageData = await buildImage(imageArgs);
    fs.writeFile('sample.png', imageData, (err) => {
      if (err) throw err;
      console.log('Image written successfully.');
    });
}

main();

実行すると, 以下のように出力されるだけですが...

$ node sample.js
Image written successfully.

同じディレクトリに sample.png というファイルが生成されるので開いてみます.

$ open sample.png

以下のような円グラフ画像が生成されています.

f:id:inokara:20200503170105p:plain

良い感じです.

円グラフ以外にも...

棒グラフの場合には, 以下のように書きます.

const buildGraphArgs = (graphData) => {
... 略...
    legendLabels.unshift('0:');

    return {
      title: 'Percentage of Total', 
      size: [ 500, 300 ], 
      data: datas,
      labels: labels,
      axis: [ 'x', 'y' ],
      axisLabels: [ legendLabels ]
    };
};

const buildImage = async (imageArgs) => {
    const barChart = imageCharts.bar(imageArgs);
 
    try {
        const b = await barChart.buffer();
        return b;
    } catch (err) {
        return Promise.reject(err);
    }
};

X 軸, Y 軸にラベルを付与するパラメータを付与して imageCharts.bar() を呼び出します.

以下のような棒グラブの画像が生成されました.

f:id:inokara:20200503173852p:plain

ついでに GIF アニメーションも生成してみました.

f:id:inokara:20200503174956g:plain

GIF アニメーションを生成する場合, パラメータは以下のようなパラメータを付与します.

... 略 ...
    return {
      title: 'Percentage of Total', 
      size: [ 500, 300 ], 
      data: datas,
      labels: labels,
      axis: [ 'x', 'y' ],
      axisLabels: [ legendLabels ],
      animation: ['1200','easeOutBack'],
      format: '.gif'
    };

以上

シュッと

image-charts.com を Node.js から使ってみたメモでした. ライブラリ自体は初心者の自分でも何となく雰囲気を掴むことが出来, コードやテストコードを読みながら試行錯誤することが出来ました.

他にも似たようなサービスがあるのかもしれませんが, シュッとグラフ画像を作成して Slack に張りたい場合等に利用を検討したいなあと思います.

ちなみに, おいくら万円?

www.image-charts.com

image-charts.com では, 以下のように, Developer プラン, Enterprise プラン, Enterprise+ プランが提供されています.

f:id:inokara:20200503223416p:plain

Docker イメージによるオンプレミス環境での利用も可能 (Enterprise プラン以上) です.