はじめに
gnuplot 5.0 からplotting styleにcircles が追加されて円グラフ(pie chart)を描けるようになりました。
円グラフは描けるは描けますが、ノウハウというかトリックが結構必要です。
目次
基本
サンプルの入力データ
使うデータはこのブログをアクセスしたユーザー環境のOS内訳です:
Windows 59.21 Linux 11.84 MacOS 11.84 iOS 9.87 Android 7.24
一番簡単な例は次のような例です:
set terminal pdfcairo color enhanced font "Helvetica,18" set output "pie-chart-simple.pdf" unset xlabel unset ylabel unset tics unset border unset key set size ratio -1 set xrange [-1.5:1.5] set yrange [-1.5:1.5] set style fill transparent solid 0.9 noborder plot '-' using 1:2:3:4:5:6 with circles lc var 0 0 1 0 213.156 1 0 0 1 213.2 255.8 2 0 0 1 255.8 298.4 3 0 0 1 298.4 334.0 4 0 0 1 334.0 360.0 5 e unset output
using の書式は 円弧の中心x座標 円弧の中心y座標 円弧の半径 円弧の開始角度 円弧の終了角度 色 です。角度は度(degree)です。
安直にやるには、データの換算が必要
上の例では(インラインデータです)、usingで使う値を直接データにしています。 元のOS内訳から換算しています。 これが一番安直ですが、生データを直接使えないのでちょっと面倒です。
見慣れた円グラフとは始点、回転方向が違う
円弧の開始角度0度は3時になり、回転方向が反時計回りになってしまいます。 よく見慣れた円グラフの始点は12時で、回転方向は時計回りです。
円グラフのテンプレート
上記をいじって改善したのが次の例です:
set terminal pngcairo color enhanced font "Helvetica,18" set output "pie-chart-label-inside.png" set size ratio -1 unset key data = "os.dat" stats data using 2 noout print STATS_sum ang(x) = x * 360.0 / STATS_sum perc(x)= x * 100.0 / STATS_sum set xrange [-1.5:1.5] set yrange [-1.5:1.5] unset tics unset border set angles degrees set style fill transparent solid 0.65 noborder Ai = 0.0 # init angle for pie-chart Bi = 0.0 # init angle for labels mid = 0.0 # mid angle for labels a(x) = x - floor(x) print a(0.9) plot data using (0):(0):(1):(A0 = Ai, Ai = Ai + ang($2), 90 - Ai ):(90 - A0):\ (hsv2rgb((a($0 / 9 + 0.7)), 0.95, 0.9)) with circles lc rgb var,\ data using (mid = Bi + ang($2) / 2, Bi = 2.0 * mid - Bi, 1.4 * cos(90 - mid)):\ (1.4 * sin(90 - mid)):(stringcolumn(1) . sprintf('\n%.1f\%', perc($2))) with labels # data using (mid = Bi + ang($2) / 2, Bi = 2.0 * mid - Bi, 0.7 * cos(90 - mid)):\ # (0.7 * sin(90 - mid)):($1) with labels unset output
改善点
見慣れた円グラフにするために改善した点について述べます。
始点・回転を修正
安直に円グラフを描くと円弧の開始角度0度は3時になり、回転方向が反時計回りになってしまいます。 これを12時(0時)から時計回りにするにはusingの円弧の角度を指定する部分で次のように工夫します:
using (円弧の中心x座標):(円弧の中心y座標):(円弧の半径):(90 - 円弧の終了角度):(90 - 円弧の開始角度):(色)
始点が90度オフセットして、回転方向が逆なので、90度から引き算しています。また始点・終点の角度を入れ替えます。
生データを扱えるように
元データをいちいち手動で換算するのは面倒で、ネットを調べるとみなさん似たようなことをやっています。
基本的には
- statsコマンドでデータの総和を出しておく
- 各円弧を描く度にデータを足して、開始角度と終了角度を計算する
上記の例では角度を計算する関数ang(x)を定義してあります。
あと、円グラフではパーセンテージを使うことが多いですからパーセントを計算する関数perc(x)も定義しています。
色の指定
色の指定は linecolor variable を使うか rgbcolor variable を使うのが良さそうです。
linecolor rgbcolor variableを使う
データファイルのデータを使って色を指定します。gnuplotのマニュアルの例では
rgb(r,g,b) = 65536 * int(r) + 256 * int(g) + int(b) splot "data" using 1:2:3:(rgb($1,$2,$3)) with points lc rgb variable
のように指定しています。円グラフでは上は使いにくいので、hsv2rgbを使って
plot data using (0):(0):(1):(A0 = Ai, Ai = Ai + ang($2), 90 - Ai ): (90 - A0):(hsv2rgb($0, 0.95, 0.9)) with circles lc rgb var
のようにしてみました。hsv2rgbの1番目の引数の$0はデータの番号(何番目のデータか)を表していいます。
$0はデータ番号なので、そのままでは上手く色指定が出来ない場合がありますし、好みの色にならないこともあります。 そこで最終的にはa(x) = x – floor(x)という出力が1以下になる周期関数を定義して、
hsv2rgb((a($0 / 9 + 0.7)), 0.95, 0.9)
としてみました。a(x)の引数はデータ番号を使って適当に書いています。0.7は開始の色を変えるために入れています。
linecolor variableを使う
line color variable を指定すると color indexを入力データファイルから読み取るようになります。 color index はstyle で指定したindexに対応します。
set style lines 1 lc rgb "orange"
しかしぼくの環境ではstyleを指定しても、plotでは反映されませんでした。デフォルトの色が使われてしまいます。何が違うのかな。
label 表示
label表示もトリッキーです。
data using (mid = Bi + ang($2) / 2, Bi = 2.0 * mid - Bi, 1.4 * cos(90 - mid)):\ (1.4 * sin(90 - mid)):(stringcolumn(1) . sprintf('\n%.1f\%', perc($2))) with labels
の部分です。
まずラベルの位置を計算しています。開始角度と終了角度の半分の角度を計算します。 それをcos, sinに入れて x,y座標を計算し、plotting style を label にして表示させています。
stringcolumn(x)はx番目のカラムにある文字列を返す関数です。ピリオド”.”はPerlと同様に文字列を連結する演算子です。
参考にしたページ
- gnuplotで円グラフを書く (米澤進吾さんのページ)
- Generation of pie chart using gnuplot (stackoverflow)
- パイチャート (Gnuplot Tips集)