最近自分の中で出番が多い本ライブラリ(まあプロット機能だけでなくADAPTのデータ分析全般は日ごろから使い倒しているが)。特にヒストグラム関係はしょっちゅう使うので、色々と機能が足されている。何を更新したのか忘れてしまいそうなので、このあたりでまとめておこうと思う。
プロット機能の詳細はこちらへ。
GitHubリポジトリはこちらへ。
デフォルトの解像度の拡大
私がGnuplotに抱えていた大きな不満点の一つは、デフォルトの解像度が低く文字が荒いこと、単純に解像度を引き上げたとしても文字や線の太さが変わらないので全く奇麗にならないことだ。今までは解像度を800x600などに制限することでやりくりしていたが、あまりの文字の汚さに嫌気がさし、見た目を整えることにした。
今、出力ファイル形式をpngにした場合のデフォルトの解像度は1200x900になっている。線の太さ、点の大きさ、タイトルやラベルのフォントの大きさなども整えたし、解像度設定に合わせて自動調整するようにしたので、幾分奇麗になっているとは思う。ただGnuplotはこのあたりターミナルごとに挙動がころころ変わり非常に調整が大変で、正常に動かない部分もあると思うので、こんなライブラリにユーザーがいるかどうかは不明だが、もし問題があったら報告してほしい。
デフォルトのフォントは互換性などいろいろと悩んだ末にArialに戻してあるが、私は近年普及しつつあるNoto Serifを使用している。過度に格式高いこともなく美しさと視認性が両立しているバランスの良いフォントに感じられて、色々試した中で最も気に入っている。ADAPT_PLOT_FONTという環境変数の値を任意のフォントに変更するか、adapt::SetPlotFontName("...")とすることでデフォルトのフォントが切り替わるので、好みのものがあれば設定しても良い。
なお実行時、Gnuplotがproblem determining pango font metricsのような警告を発し、文字が適切に描画されないことがあるかもしれない。これは本ライブラリではなくGnuplot側(もしくはその文字描画バックエンドであるCairoかPango)の不具合で、フォントの大きさを一定以上に設定すると発生する。ライブラリの側で解決する術はないが、対症療法は存在し、環境変数PANGOCAIRO_BACKENDの値をfcに設定することで解消される。
累積相対度数分布
PlotHistogram関数にplot::cumulまたはplot::inv_cumulというオプションを与えることで、プロットが累積相対度数分布に切り替わる。相対ではない累積度数にもできるようにするかちょっと悩むところだったが、私が現時点で必要としていないので未実装だ。
コード例はこちらを参照。

積み上げヒストグラム
PlotHistogram関数に対してplot::stackオプションを与えることで、plot::stackオプションが与えられたすべてのデータを対象にヒストグラムを積み上げ表示する。
なおx軸の最小、最大、ビン数は最初のPlotHistogram関数で指定すれば2度目以降は省略可能である。というか、ここで整合しない値を与えると結果がおかしなことになるので省略することを推奨する。
コード例はこちらを参照。
なおplot::stackを有効にした場合はヒストグラムの塗りつぶしが勝手に行われるのだが、このとき後述するPlotFilledCurvesを呼び出している関係で、各プロットの色を明示することが望ましい。

重み付けされたヒストグラム
PlotHistogram関数に対してplot::weightオプションによりデータごとの重みを与えられるようにした。
重みを考慮した統計誤差のエラーバー描画も可能ではあるが、重み付きとなると正規分布で近似して計算せざるを得ない。そのためplot::he_normalは使用可能だがplot::he_poissonには非対応である。コード例はこちらを参照。

PlotFilledCurvesの拡張と整理
今までwith filledcurvesはPlotFilledCurves、with boxesとwith fillstepsによる塗りつぶしはPlotPointsで呼び出すというように機能が十分に分離できていなかったが、これらをPlotFilledCurvesに統合した。plot::s_lines、plot::s_boxes、plot::s_stepsいずれかをオプションとして与えるとそれに応じた形式でプロットされる。
また比較的新しいGnuplotではfilledcurvesやfillstepsにおいてボーダーが描画されないという腹立たしい仕様変更があったのだが、これをライブラリ側で吸収し描画するようにした。ボーダー不要の場合はオプションにplot::noborderを与えれば良い。
なお、ボーダーを描画するときは明示的にplot::c_redなどのように色を指定することを推奨する。現時点では色を明示しないと塗りつぶしの色とボーダーの色とがちぐはぐになってしまうためだ。ただこれを修正するにはGnuplotの仕様に抗って色々と設計修正する必要が生じて大変なので、今回は見送った。
色の追加
今までred/magenta/blue/cyan/green/yellowの6系統にdark/lightを加えた18色、さらに黒白灰色合わせて5色の名前を設けていたが、もっと中間色を使いたくなったので大量に用意した。現在は上記23色に加え、色相を15度ずつずらして生成した24色をベースにそれぞれlight/dark/mutedを加えた計96色が新たに使用可能になった。各色と名前の対応は以下の図のとおりである。
こういう色について、美的感覚の強い人は美しい色を選定して名前を与えたりするのかもしれないが、私はOklch色空間でLightness、Chroma、Hueを少しずつ変化させながら機械的に生成した。というより、そのような規則的に並ぶ色の一覧が欲しかったため用意したというほうが正しい。最初HSVで試したものの、あれは人間の色覚とはだいぶかけ離れた定式化であることを知った。実際にHSVで規則的に生成した色を使ってみると明るさにかなりの違いがあり、視認性に難が生じたのだ。とはいえOklchでも容易にsRGBの色域外に飛び出してしまうので調整が難しく、特にChromaがHueによっては全く表現できない問題はもっと調整を加えるかかなり悩んだ(上記画像でも青~緑のあたりは潰れてしまっている)。現在のカラーパレットもベストではないと思う。将来的にさらに調整するかもしれない。
ちなみにOklch色空間の計算にはsoreja様1開発のColorMというC++ライブラリを利用させてもらった。シングルヘッダで使いやすく、良いライブラリだった。将来的に3D可視化ツールを作成するときは色空間ごとの計算に導入させてもらうとRGBやHSV以外にも指定できるようになって面白いかもしれない。高度な色空間ほど直感性がなくなるので実用に値するかは何とも言えないが。
ちょっと愚痴
Gnuplotライブラリとしてはかつてないほど苦労した更新だった気がする。任意の配列に対応させるために動的ジェネリクスのギミックを盛り込んだ時も大変だったが、あれはC++との格闘だった。こちらはGnuplotの仕様(もしかするとバグ)との戦いだった。
例えば解像度の引き上げに関しては、ターミナルがpngcairoの場合とpdfcairoの場合とでは同じ指定をしても見た目が合致しなかったりして、暗中模索をひたすら続けるしかなかった。線の太さ、点の大きさが不自然になったり、破線の間隔が異常なことになったり、ドキュメントにあるオプションを指定しても効果を得られなかったりと、挙動が意味不明なのである。今の調整も正直本当に正しく設定できているのか理解しきれていない部分が多く、不安が尽きない。
PlotFilledCurvesについても非常に悩む更新だった。元々はPlotFilledCurvesという関数そのものを捨てて、PlotPointsに統合する方向で検討していたのだが、やめた。原因は、Gnuplot5.1か5.2の頃に行われたと思われる仕様変更だ。現在のwith filledcurves、with fillstepsは、closedモードでない限りボーダーを描画しないのである。塗りつぶしの部分だけが描画され、境界部分の線はどう設定しても一切現れない。5.0の頃はちゃんと描画されていたのでてっきりバグだと思っていたが、ドキュメントをしっかり読んでみると書かれていた。私にとっては激怒するレベルの悪質な仕様変更であった。
今回、上記の積み上げヒストグラムで塗りつぶしを行うことを考えた際、ボーダーがないせいで見た目が非常に陳腐になってしまい、どうしようかと悩んだ。そうこうするうちに上記のclosedモード以外での仕様変更に気づき、ならばいっそこちらで吸収してしまえと思い、PlotFilledCurves内で明確にボーダーを描画する機能を組み込むことにした。PlotFilledCurvesは内部でwith filledcurvesなどによる塗りつぶしとwith linesなどによるボーダー描画の両方を実行しているのである。この点でPlotFilledCurvesには存在意義が生まれ、消滅を免れた。
歴史あるツールは往々にして解決されないバグめいた挙動を抱え込む。長年開発された巨大なツールはかゆいところに手が届く(が、そのためには莫大な学習コストが必要)。
新しいツールが登場するときは、たいていそれまでのデファクトスタンダードが高機能、複雑化、雑多化しすぎて意味不明になり、シンプルなものを求めた人たちが最新のツールに引っ越していく、という現象が共通して起きているように思う。私はC++というどう考えてもデータ分析に不向きな言語で奮闘している都合上Gnuplotに頼る他ないのだが、本音を言えばもっと便利なツールが出てきてほしいとずっと願っている2。
まあC++でデータ分析、可視化を仕様などという奇天烈な人間が滅多に存在せず、いたとしてもROOTやApache Arrowなどを選択するであろう現在、私のライブラリが果たして世間にとって有益なのかは不明であるが、世間がなんと言おうと少なくとも私個人にとっては有益なので、まだしばらく開発を継続するつもりだ。