ページが長いので「しおり」の仕組みを用意してみました。
「しおり用」と書かれた所をクリックしてからブックマークに入れると、
それはページの先頭ではなく、その箇所へのブックマークになります。
(03/03 2006)
今までちゃんと説明していませんでしたが、
ここには、日付ごとに記事 (記事 A とします) を書いていますが、
その最後に、(cf. 「情報やメモ (XX/XX 20XX)」)
のように別な日付の記事 (記事 B とします)
へのリンクがついているものがあります。
これは、「被参照リンク」で、
記事 B が記事 A を参照している (リンクを貼っている) ことを意味します。
つまり、記事 B の方が記事 A より後の記事であり、
記事 A の続きや追加情報、訂正などの内容であったり、
記事 A に関連する別な話題であったりしますので、
記事 A に被参照リンクがついている場合は、
是非そちら (記事 B) もご覧ください。
(01/29 2014)
最新の開発版 (git) の all.dem の出力を置いておきます。
「情報やメモ (09/29 2023)」 の時点でのデモ (782 ページ) に比べると、1 ページ分だけ増えていますが、 これは、polygon_border.dem の分の追加 (762 ページ) です。
この間の改変には以下のようなものがあります (以下以外にも色々あると思いますが最近は変更全体を把握していません)。
1. は、printerr 同様にメッセージを常に stderr に出力するコマンドですが、 指定メッセージの出力前に、現在のファイル名 (か関数ブロック名)、 および現在の行番号を追加して出力します。デバッグ用により便利です。
2. は、従来の multiplot では、replot がうまく効かずに、 multiplot 内の最後の plot のみ replot し、 それ以外のものは破壊していました。 今回の新しい機能では、最後の multiplot で実行したコマンドをすべて データブロック $GPVAL_LAST_MULTIPLOT に記録し、 それを remultiplot で実行できるようになりました。 replot でも、直前のコマンドが multiplot の一部であれば自動的に remultiplot を呼び出してくれますし、 mouse 操作による zoom/pan などの際の再描画でも remultiplot が呼び出されるようになります (set mouse multiplot 時には)。 ただし、完全というわけではないようですし、 マウス操作の対応も、例えば mouse による座標の取得は、 最後の plot に関する軸での計算になってしまうようです。
3. は、多分上に書いたデモの追加部分だと思います。
4. は、例えば linespoints に関する話で、 従来は linespoints は線 (lines) を書き、 点記号の下を消してから点記号 (points) を書いていた、 すなわち「不透明」な点記号を描画していました。 その「消す」部分のサイズの指定が set pointintervalbox だったわけですが、 今回「unset pointintervalbox」を使うことで、 点記号部分を消さずに点記号が書けるようになりました。 これにより「透明」な点記号を使えるようになったことになります。 なお、これは linespoints だけではなく、 xerrorbars, xyerrorbars などの誤差線にも適用されます。
5. は、plot コマンド上で指定する軸の範囲指定と、 サンプリング範囲指定の区別がやや曖昧だったために、 これまでは必要なら sample キーワードを追加する、 という仕様だったものを、サンプリング範囲指定には 3 番目のフィールドとしてサンプリング間隔を指定できるようにして、 そこを空欄にすれば、サンプリング範囲指定と軸の範囲指定の区別ができる、 という効果を狙ったもののようです。例えば、
set xrange [0:50]
plot [0:10] f(x), [10:20] g(x), [20:30] h(x)
だと、最初の [0:10] が大域的な x の範囲になってしまい、
set xrange も無視されてしまうので、従来は
set xrange [0:50]
plot sample [0:10] f(x), [10:20] g(x), [20:30] h(x)
と書くことが推奨されていたのですが、今回あらたに
set xrange [0:50]
plot [0:10:] f(x), [10:20] g(x), [20:30] h(x)
のように書けるようになった、ということです。
6. は、例えば「keyentry "文字列" left」などとすれば、 key の通常なら凡例を置く場所に左合わせで文字列が書かれる、 というもので、それにより key の幅全体に渡る文字列を置けるようになる、 というものです。
なお、4., 5., 6. などは、 今までもできていたのかどうかは確認していませんので、 もしかしたら新たな機能というわけではなく、 単に今回新たにドキュメント化したというだけなのかもしれません。
(cf. 「情報やメモ (08/23 2024)」)
今さら珍しくない話ですが、数列をグラフ化する方法について紹介します。 数列データがデータファイルとして存在する場合は、 単に with lp でグラフ化することができますが、 それを、一般項、あるいは漸化式から、ファイルを経由せずに gnuplot でグラフ化する、という方法について考えます。
それは現在の gnuplot では少しも難しくなく、以下により簡単にできます。
例として、
π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...のグラフを書いてみます。
f(n) = sum [j=1:n] (-1)**(j-1)/(2*j - 1.0)
N = 20
set xrange [0.5:N+0.5]
set yrange [0.6:1.1]
set grid
set sample N
plot sample [n=1:N] '+' using (n):(f(int(n))) with lp
title "部分和のグラフ", pi/4.0
最初の f(n) は、第 n 部分和の定義です。 f(1) から f(N) までを、(x,y)=(n,f(n)) の点を折れ線でつないだグラフにします。
疑似ファイル '+' は、xrange と set sample の数字によって x の標本点を作成します。しかし、グラフの枠線と重ならないように xrange を上のように少し広げる場合は、 plot の sample キーワードを使って実際にサンプルする範囲と 変数を指定すればできます。
なお、f(n) ではなく f(int(n)) としていますが、 サンプル値は一般には実数になるので、int(n) としないと sum でエラーがでます。
一般項ではなく漸化式の場合は、plot の行を例えば
yy = 0
plot sample [n=1:N] '+' using (n):(yy = yy+(-1)**(n-1)/(2*n-1)) with lp
title "部分和のグラフ", pi/4.0
のようにすればいいでしょう。
こちらは特に int を使わなくてもエラーはでませんでした。
最新の開発版 (git) の all.dem の出力を置いておきます。
「情報やメモ (08/29 2023)」 の時点でのデモ (776 ページ) に比べると、6 ページ分だけ増えていますが、 これは、新たに追加された hstep スタイル用のデモの追加分です。
この間の改変としては、 なんといっても上に書いた描画スタイル with hsteps の追加でしょう。 作成したのは、最近活発に開発チームで関わっている Hiroki Motoyoshi さんです。 以前の開発 with sectors と同様に、色々なサンプルが追加されています。
実は、以前 「情報やメモ (05/09 2023)」 などに書いたヒストグラムの「グループ毎の接続線」について、 描画スタイル histogram にそういうオプションを追加してもらえると、 という要望をだいぶ前に本家に出していたのですが、 つい最近、 histogram には実装していないけれど、 最近追加された hsteps を使うとそれができるようになったのでもういいよね、 という返事がきました。 今度試してみて、また報告したいと思います。
毎度おなじみ、レーダーチャートの件です。 「情報やメモ (04/06 2021)」, 「情報やメモ (09/23 2022)」 で、spiderplot によるレーダーチャートの作成例を紹介しました。
実は私のところでは、そこで紹介したような複数人 (3 人) のレーダーチャートを重ねて描く、 すなわち人数分のレーダーチャートの重ね描きからなるグラフ 1 つを 作成するのに利用しているのではなく、 むしろ主に各人毎のレーダーチャートを平均と重ねて描く、 すなわち 2 つのレーダーチャートのグラフを人数分作成する、 という形で利用しています。今回はその方法について紹介します。 またついでに、あらためて spiderplot で気がついたことについても紹介します。
データは今までと同じものを利用します。すなわち、data.dat が
生徒 国語 社会 理科 算数 英語であるとします。 そして、平均値と重ね描きするため、 あらかじめ平均値も別に計算しておき、そのファイルを mean.dat とします。
Aさん 70 80 60 50 90
Bさん 40 20 90 90 70
Cさん 90 90 90 90 90
平均 66.67 63.33 80.00 76.67 83.33
実は、spiderplot では、 この別々のファイルのデータを一つのグラフに重ね描きするために newspiderplot という命令があります。 それを利用して別々のファイルからデータを読んで重ね描きするか、 または 2 つのデータを連結して、
生徒 国語 社会 理科 算数 英語のようにしたデータ (comb.dat) からグラフを作成することも可能です。 表計算ソフトなどから出力したデータの場合は 後者の連結したデータを元にすることも多いと思います。 今回はその両者、すなわち
Aさん 70 80 60 50 90
Bさん 40 20 90 90 70
Cさん 90 90 90 90 90
平均 66.67 63.33 80.00 76.67 83.33
を紹介します。
また、データのヘッダにある科目名の情報は spiderplot の軸のラベルとして使いますが、 その取得の方法も複数のやり方が考えられます。ここでは、
を紹介します。[b-1] は前の例で紹介した方法ですが、 [b-2] は Unix なら head コマンドで可能で、 MS-Windows なら gawk で代用できます。
さらにデータ 1 列目の生徒の名前の情報は key のラベルとして使用しますが、 その取得は
があります。[c-1] は前に紹介した方法です。
まずは複数グラフの出力についてですが、 PNG や SVG のような単体画像ファイルを生成する場合は、 「set output [ファイル名]」として plot して「set output」とする、 という作業が必要になりますが、 複数ページをサポートしている PDF ファイルや PostScript ファイルの場合は、 plot コマンドを複数回実行すれば、 それに応じて複数ページの出力ファイルが生成され、 各 plot は各ページに出力されます。ファイル指定は 1 つで良くなります。 どうせ do for 文で実行するので手間の違いはたいしたことではありませんが、 例えば pdfcairo terminal を利用すると便利です。
次は [a-1],[a-2] について考えます。 M を人数、N を科目数として (これらは stats で取得可能)、 [a-1] の場合は、基本的な plot 部分については、 以下のように plot します (サンプルは こちら (spider-multi-1.pdf))。
set spiderplot
set for [i=1:N] paxis i range [0:100]
do for [k=1:M] {
plot for [j=1:N] "mean.dat" using j+1 lt 1 lw 1,\
newspiderplot,\
for [j=1:N] "data.dat" using j+1
every ::k::k lt 2 lw 5
}
newspiderplot を入れないと軸が 10 本の不正なグラフができてしまいます。
また、newspiderplot により lt や lw がリセットされるため、
lt, lw を改めて設定する必要があります。
data.dat の方は、「every ::k::k」を使って
(k+1) 行目のデータのみを描画しています (every では 1 行目は 0 と数える)。
[a-2] の場合は、every を使って、 k+1 行目と M+2 行目を描画させるようにします (サンプルは こちら (spider-multi-2.pdf))。
set spiderplot
set for [i=1:N] paxis i range [0:100]
do for [k=1:M] {
plot for [j=1:N] "comb.dat" using j+1
every M-k+1::k lw 4
}
ただ、この場合先に描画されるのが各人のデータ、
次に描画されるのが平均値になるので、
上の [a-1] の例とは線種が逆になります。
しかも、こちらの [a-2] の場合は、
グラフ毎に線種、線幅を指定することができないので、
グラフの色を変更したい場合は、
あらかじめ set linetype を使って、
使いたい色などを線種に設定しておく必要があります。
次は、[b-1],[b-2] について考えます。 spiderplot では plot の title は key に入るのではなく、 各軸のラベルになります。[b-1] はそれを columnheader で取得する方法で、 上の plot の例で言えば、data.dat か comb.dat の plot の最後に 「title columnhead」をつければいいです。 ただし、その場合 1 列目が通常のデータとは見なされなくなるので、 every 指定が 1 減ることになります。 例えば [a-1] で [b-1] を行う場合は以下の通りです (サンプルは こちら (spider-multi-3.pdf))。
set spiderplot
set for [i=1:N] paxis i range [0:100]
do for [k=1:M] {
plot for [j=1:N] "mean.dat" using j+1 lt 1 lw 1,\
newspiderplot,\
for [j=1:N] "data.dat" using j+1
every ::k-1::k-1 lt 2 lw 5 title columnheader
}
なお、git 版の gnuplot の場合、key に外枠をつけて
「set key box」とするとわかりますが、その「title columnhead」の分、
どうやら空のエントリが key に追加されてしまいます
(サンプルは こちら
(spider-multi-4.pdf))。
5.4.4 の gnuplot では起きませんが、
5.4.6 以降では起きるようになっています。
多分バグだと思いますので、報告しておきます。
[b-2] の場合は、unix ならバッククォートを用いて
chead = "`head -1 data.dat`"
Windows なら gawk を使って
chead = "`gawk \"NR==1\" data.dat`"
とすることで、直接 data.dat の 1 行目文字列を変数 chead に取得できます。
バッククォートの代わりに system() を使うこともできます。
それを paxis に割り当てるには、
word() を使ってそこから単語を拾えばいいです。
chead = "`head -1 data.dat`"
set for [j=1:N] paxis j label word(chead, j + 1)
なお、git 版の gnuplot なら split() 関数で配列に切り分ける、
という手もあります。
また、Windows の場合は、head の部分を gawk に変えてやってみてください。
最後は [c-1],[c-2] ですが、[c-1] は前に紹介した通り、 stats によるデータファイルの空読みを利用して、 1 列目を配列に保存する方法です。 その配列の値は、plot の際に keyentry を使って key に利用できます (サンプルは こちら (spider-multi-5.pdf))。
array name[M]
j = 0
stats "data.dat" every ::1
using 2:(j = j + 1, name[j] = strcol(1), 0) noout
set spiderplot
set for [i=1:N] paxis i range [0:100]
set key box
do for [k=1:M] {
plot\
keyentry with l lt 1 lw 1 title "平均",\
keyentry with l lt 2 lw 5 title name[k],\
for [j=1:N] "mean.dat"
using j+1 lt 1 lw 1,\
newspiderplot,\
for [j=1:N] "data.dat" using j+1
every ::k-1::k-1 lt 2 lw 5 title columnheader
}
それに対して [c-2] は、配列は必要なく、plot の際に
「using j+1:key(1)
」とする方法です。
これでもちゃんと 1 列目が key になります。
これだと、keyentry は不要になりますが、
key の凡例が with lines ではなく with box のようになります
(サンプルは こちら
(spider-multi-6.pdf))。
set spiderplot
set for [i=1:N] paxis i range [0:100]
set key box
do for [k=1:M] {
plot for [j=1:N] "mean.dat" using j+1:key(1)
lt 1 lw 1,\
newspiderplot,\
for [j=1:N] "data.dat" using j+1:key(1)
every ::k-1::k-1 lt 2 lw 5 title columnheader
}
あとは、 「情報やメモ (04/06 2021)」 のように paxis に tics を設定して、 set grid spider でその tics をつなぐ多角形を書いてやれば完成です。 [a-1],[b-1],[c-2] での例を以下に示します (サンプルは こちら (spider-multi-7.pdf))。
### M,N の取得
stats "data.dat" every ::1 using 2 noout
M = STATS_records
N = STATS_columns - 1
### teminal と出力ファイル
set term pdfcairo size 6,4
set output "spider-multi-7.pdf"
### グラフの設定
set spiderplot
set for [i=1:N] paxis i range [0:100]
set paxis 1 tics font ",9" # 刻みの数字は 1 番軸のみ
set grid spider lt 1 lc "gray" lw 0.5 back
set key box
### 描画
do for [k=1:M] {
plot for [j=1:N] "mean.dat" using j+1:key(1)
lt 1 lw 1,\
newspiderplot,\
for [j=1:N] "data.dat" using j+1:key(1)
every ::k-1::k-1 lt 2 lw 5
title columnheader
}
最新の開発版 (git) の all.dem の出力を置いておきます。
「情報やメモ (05/30 2023)」 の時点でのデモ (772 ページ) に比べると、4 ページ分だけ増えていますが、 これは前回報告した
です。
この間 (2023-05-26 以降) の git 版の改変としては、 以下のようなものがあるようです。 なお、主にドキュメントの差分で見ているので、 変更はほかにもあると思います。
(cf. 「情報やメモ (09/29 2023)」)
最近、LaTeX などのフォントの書体を変えて使ったりしているのですが、 フリーの TrueType フォントをたくさんダウンロードした際に、 どのような見た目のフォントか、太さはどうかなどを比較するために フォントの見本を作ろうと考えました。
古い freetype ライブラリにはそういった目的用の、 指定したフォントで文字列を書かせてみるツール (freetype 1 の頃の ftdump とか ftzoom とか) がついていましたが、 多くのフォントのものを見る場合はそれも手間です。
他に思いついたのは、freetype ライブラリを直接使うか libgd ライブラリを使って C でそういうプログラムを書くこと、 あるいは GD モジュールを使って perl でそういうプログラムを書くことでしたが、 よく考えたら、それは gnuplot でやらせるのと変わりませんし、 gnuplot でやるのが一番手軽だと気がつきました。 そこで、gnuplot でやってみました。
以下に示すのがその csh スクリプトで、gnuplot を呼び出して、 指定したディレクトリ内の TrueType フォント (*.ttf, *.ttc, *.otf, *.TTF, *.TTC) の見本を作成するものです。 ただし、gnuplot が libgd を使ってコンパイルされている必要がありますし、 fontconfig が有効な libgd の場合は、 フォントの絶対パスを指定しても 正しくそのフォントを使ってくれない可能性があります。 横がはみでたり、縦のサイズが適切でなかったりしたら、 pngH, yH, pngW などの数値を変えてみてください。
#! /bin/csh -f
set gnuplot = gnuplot
set png = outf.png
set fontd = /usr/local/share/fonts/aozoramincho
set fontlist = ( $fontd/*.{ttf,ttc,otf,TTF,TTC} )
set fnamelist = ( )
foreach i ( $fontlist )
set fnamelist = ( $fnamelist `basename $i` )
end
# 以下が gnuplot 実行部分
$gnuplot <<EOF
N = $#fnamelist # フォント数
pngH = 50 # 1 行分の png サイズでの高さ
pngW = 600 # png サイズでの出力ファイルの横幅
yH = 10 # グラフ座標での 1 行分の高さ
set term png size pngW,pngH*N
array Fname = split("$fnamelist")
set out "$png"
set xrange [0:100]
set yrange [0:yH*N]
str = "私のなまえは竹野茂治です。"
unset xtics
unset ytics
unset border
do for [j=1:N] {
set label j sprintf("%s%s", str, Fname[j])
at 0, yH*(N-j) \
font "${fontd}/".Fname[j].",20"
}
plot 1/0 not
set out
EOF
xli $png # xli は外部の画像ビューワプログラム
unset xtics, unset ytics, unset border で グラフの枠や軸の刻みなど不要な要素を消して、 set label で文字列 (str + フォント名) を指定したフォントで表示させています。 フォント名は、最近導入された配列と split() を組み合わせて配列化していますが、 他のやり方もあるかもしれません。
gnuplot の本来の使い方ではないですが、 最近の do for や配列などの機能の充実により、 gnuplot でもこういうことが楽にできるようになってきました。
最新の開発版 (git) の all.dem の出力を置いておきます。
「情報やメモ (04/07 2023)」 の時点でのデモ (771 ページ) に比べると、1 ページ分だけ増えていますが、
という形で、これは 「情報やメモ (05/24 2023)」 で紹介した 5.4.7 で行われた変更と同じものです。
この間 (2023-04-05 以降) の git 版の改変としては、 以下のようなものがあるようです。 なお、ドキュメントの差分で見ているので、 変更はほかにもあると思います。
1. は新しい描画スタイルで、 等高線の間を個別の色で塗り潰すことを可能にするもので、 demo に contourfill.dem が追加されています。 まだ本家の demo サイトには現れてはいないようです。
2. は kitty という端末エミュレータで実装されている kitty グラフィックプロトコルを使って、 それをサポートする端末エミュレータ上でグラフを表示するものです。 sixel グラフィックのようなものですが、 カラーがふんだんに使えるなど、sixel ドライバよりも優位性があるようです。 ただし、kitty プロトコルをサポートする端末エミュレータが どれくらいあるのかはよくは知りません。
3. も端末エミュレータ用の話で、それ用の出力形式で pause mouse 中に 矢印キーなどを使って視方向を変えたり (3 次元グラフ)、 視点移動や拡大 (2 次元グラフ) などが行えるようにするものです。
4. は、ドキュメントに追加されているのですが、 「これを使う以外には存在できないような状況でその実行を可能にする」 ためものだそうです。
例として、 2 つの CSV ファイルのグラフを同時に描画する際に、 一方はカンマ (,) 区切りの CSV ファイル、 もう一方はセミコロン (;) 区切りの CSV ファイルの場合の利用が紹介されています。 CSV ファイルの区切り文字は、 gnuplot では set datafile で指定できるのですが、 それはコマンドレベルでの実行なので、 一つの plot で同時にグラフを描画させるときに set datafile を割り込ませる仕組みがなく、 今までは事前にデータファイルの形式を変更するしかありませんでした。 それを関数ブロックで解決する例として、
function $set_csv(char) << EOF
set datafile separator char
EOF
plot tmp=$set_csv(",") FILE1,
tmp=$set_csv(";") FILE2
が紹介されています。つまり、set datafile の割り込みを、
plot 行で許されている「変数定義」にもぐりこませることで実行する、
というものです。
なお、ドキュメント的には厳密には、
plot tmp=$set_csv(","), FILE1,
tmp=$set_csv(";"), FILE2
のように変数定義と描画のファイル指定の間は
カンマ (,) を書くべきだと思うのですが (help plot 参照)、
実際にはカンマ (,) がなくてもちゃんと動作するようです。
(cf. 「情報やメモ (08/29 2023)」)
05/21 頃に gnuplot-5.4.7 が公開されました。 5.4.7 での新規機能、変更、修正は以下のようです。
今回は細かい修正のみです。 なお、これが 5.X 系列としては最後のリリース版で、 次期リリース版のバージョンは 6.0 になる予定です (今度こそ)。
5.4.7 の all.dem の出力も置いておきます。
前回の 5.4.6 用のもの (「情報やメモ (02/13 2023)」) と比較すると、419 ページ目のもの (pm3d.dem) が、 419 ページ目と 420 ページ目の 2 つに変更されているようです。 5.4.6 では「set pm3d at bstbst」のサンプルだったものを、 「set pm3d at bst border lt -1 lw .3」で境界をつけて、さらに 「set pm3d depthorder」としたものと「set pm3d interp 2,2」としたものの 2 つのサンプルに変更した、といった感じです。
今回は、昔書いた、横向きの帯グラフ (ヒストグラム) (「情報やメモ (02/07 2015)」) に関する別解を考えてみたいと思います。 実は、以下のようなものをたまたまネット上で見つけたのがきっかけです。
これは、私が以前 「情報やメモ (02/07 2015)」 に書いた、「文字を回転することで擬似的にグラフは縦に描いて できた画像を回転する」という方法ではなく、 「with boxxyerrorbars を利用して自前で横向きのグラフを描く」 という方法を用いています。 なるほどと思いましたので、過去に描いたものをそれでやるとどうなるか とやってみました。
まず、gnuplot 5.0 以前の「boxxyerrorbars」という名前は、 gnuplot 5.2 以降では「boxxyerror」に変更されていることに注意が必要です。
boxxyerror は、4 列、または 6 列のデータを必要としますが、4 列ならば、 「x, y, xdelta, ydelta」で、(x,y) を中心とする、 それぞれの辺の長さが 2*xdelta, 2*ydelta の長方形を描きます。 よって、長方形の中心と幅を計算する関数を使えば、 横向き棒グラフを描くことができます。データは、前と同じ、
年号 第一次産業 第二次産業 第三次産業 1920 54.9 20.9 24.2 1940 44.6 26.2 29.2 1960 32.7 29.1 38.2 1980 10.9 33.6 55.4 2000 5.1 29.8 65.1を利用します。 例えば 1920 年のところの最初の棒グラフ (第一次産業) は、
x = 54.9/2, y = 1920, xdelta = 54.9/2, ydelta = 5に描き、2 つ目の棒グラフ (第二次産業) は、
x = 54.9 + 20.9/2, y = 1920, xdelta = 20.9/2, ydelta = 5として描くことになります。よって、各 j = 2,3,4 列のデータに対して、
csum(n) = sum [i=2:n] column(i)
pcj(j) = csum(j-1) + column(j)*0.5
xdel(j) = column(j)*0.5
svalue(j) = sprintf("%.1f%%", column(j))
のような関数を用意します。
なお、 「情報やメモ (02/07 2015)」 では、この csum(j) は再帰を利用して作っていました (colsum(n)) が、 ここでは gnuplot 4.6 以降に実装されている sum を利用しています。 これで、以下のようにすれば、ヒストグラムの部分は完成します。
set term wxt
set title "産業別就業者数(15歳以上)の構成率の変化"
font ",16"
ydel = 5 # ydelta
set ytics 1920, 20, 2000
set yrange [2020:1880] # 逆向きにして上を少し空ける
csum(n) = sum [i=2:n] column(i)
pcj(j) = csum(j-1) + column(j)*0.5
xdel(j) = column(j)*0.5
svalue(j) = sprintf("%.1f%%", column(j))
set style fill solid 0.5 border -1
set xrange [0:100]
set noxtics
set x2tics 20 # 軸の刻みを上に書く
set grid noxtics noytics x2tics lt -1 # grid は縦のみ
set x2label "(%)"
set ylabel "(年)" rotate by 0
# rotate by 0 がないと wxt では横になるし、かっこも全角でないと化ける
plot for [j=2:4] "fille"
using (pcj(j)):(column(1)):(xdel(j)):(ydel) \
with boxxyerror title columnheader(j),\
for [j=2:4] ""
using (pcj(j)):(column(1)):(svalue(j)) with labels
font ",8" notitle
案外簡単に棒グラフ部分が再現されていることがわかります。 後は接続線です。概念としては、with vectors (x,y,xdelta,ydelta) を使って、
for [j=2:4] "" using (前の行の csum(j)):
(前の行の column(1) + ydel):\
(csum(j) - 前の行の csum(j)):
(column(1) - ydel - 前の行の column(1) - ydel) with vectors \
nohead lt -1 dt 2 not
のようにすればいいのですが、前の行の値をどう保存するかが問題です。
それは、for との兼ね合いがあるからですが、実験してみると、
ファイルの行の処理と for [j=2:4] の処理は、以下の順に処理されるようです。
(j, 行) = (2,2), (2,3), (2,4), (2,5), (2, 6),つまり、j=2 に対する plot を実行し、 次に j=3 に対する plot を実行し、 最後に j=4 に対する plot を実行する、 という順で行っているようです。 ということは、カンマ演算子で、現在の値を別な変数に残す、 ということをやっていけばなんとかなりそうですが、 最初の行に対する描画が行われないようにする必要がありますので、 そこだけ NaN で初期化するようにします。
(3, 2), (3,3), (3,4), (3,5), (3, 6),
(4, 2), (4,3), (4,4), (4,5), (4, 6)
ylast = 0
plot ... ,
for [j=2:4] "" using
(xlast=(column(0)==0)?NaN:xlast, xlast):\
(ylast + ydel):\
(xl=xlast, xlast=csum(j), csum(j) - xl):\
(yl=ylast, ylast=column(1), column(1) - yl - 2*ydel)\
with vectors ...
のようにすればいけそうです。column(0) はデータの行番号を示し、
データの先頭行でそれは 0 になるので、
各 j に対する plot の最初の行で xlast は NaN
に初期化されることになります。
カンマ演算子を多用しているので、少しややこしいですが、
例えば j=2 では、文字列を除くデータ行で、
with vectors の (x, y, xdelta, ydelta) 以下のように認識され、
xlast, ylast には以下のように保存されていきます。
これで適切な接続線が描かれることがわかると思います。 そして次に j=3 では以下のようになります。
1 行目の y や ydelta は不正な値になりますが NaN があるので描画されず、 2 行目から正しい値になるのでこれで適切な接続線が描かれます。 結局以下のようにして接続線付きの帯グラフが完成します。
set term wxt
set title "産業別就業者数(15歳以上)の構成率の変化"
font ",16"
ydel = 5 # ydelta
set ytics 1920, 20, 2000
set yrange [2020:1880] # 逆向きにして上を少し空ける
csum(n) = sum [i=2:n] column(i)
pcj(j) = csum(j-1) + column(j)*0.5
xdel(j) = column(j)*0.5
svalue(j) = sprintf("%.1f%%", column(j))
set style fill solid 0.5 border -1
set xrange [0:100]
set noxtics
set x2tics 20 # 軸の刻みを上に書く
set grid noxtics noytics x2tics lt -1 # grid は縦のみ
set x2label "(%)"
set ylabel "(年)" rotate by 0
# rotate by 0 がないと wxt では横になるし、かっこも全角でないと化ける
ylast = 0
plot for [j=2:4] "fille"
using (pcj(j)):(column(1)):(xdel(j)):(ydel) \
with boxxyerror title columnheader(j),\
for [j=2:4] ""
using (pcj(j)):(column(1)):(svalue(j)) with labels
font ",8" notitle,\
for [j=2:4] ""
using (xlast=(column(0)==0)?NaN:xlast,xlast):(ylast+ydel):\
(xl=xlast,xlast=csum(j),csum(j)-xl):\
(yl=ylast,ylast=column(1),column(1)-yl-2*ydel) \
with vectors nohead lt -1 dt 2 not
以前の回転による方法よりも見通しはいいですし、 wxt terminal でも容易に確認ができるのがいいです。 key の自作も必要ありません。 この方法であれば、色々な横向き棒グラフ、 ヒストグラムが実現できそうです。
(cf. 「情報やメモ (09/29 2023)」)
最新の開発版 (git) の all.dem の出力を置いておきます。
「情報やメモ (01/25 2023)」 の時点でのデモ (755 ページ) に比べると、かなり変更があります。
concave_hull.dem, sectors.dem は今回新規に導入された機能で、 そのための多くのデモが追加されています。 498 ページに追加されているのは、2 つの曲面の滑らかな交差のデモで、 2 曲面のグラフや、自分自身と交差する曲面、 平面と交差する曲面のグラフデモなどは従来もありましたが、 この形のものは今まではなかったようです。 また、他にも入れ替わってはいなくても、 表示が少し変更されているものもあります (例えば 756-759 ページ等)。
この間 (2023-01-25 以降) の git 版の改変としては、 以下のようなものがあるようです。 なお、ドキュメントの差分で見ているので、 変更はほかにもあると思います。
1. は新しい描画スタイルで、データの各点に対し、 バームクーヘンのかけらのような扇片を描きます。 線ではなく図形を描く、という点では with circles や with ellipses に近いものと言えますが、 この with sectors は扇型を方向θと半径 r、 方向の変位Δθと半径の変位Δr、 そして必要ならば中心座標 cx,cy を指定して描画できるものです。 座標系は、直交座標上でも極座標上でも描けます。
これにより、円グラフ/円環グラフも描けますし、鶏頭グラフや色見本、 ダイヤルチャートなども簡単にかけます。 しかも、直交座標上で複数の円グラフが簡単に描けるので、 表現できることがだいぶ増えます。 デモの 134-147 ページをご覧ください。 なお、開発したのは日本の方 (Hiroki Motoyoshi さん) のようで、 開発版のマニュアルでは、開発者リストに新規に名前が加えられています。
2. は 3 次元グラフの z 方向のクリッピングで、 その境界が滑らかになるように切ります。 ドキュメントには、これと do for を組み合わせたアニメーションの例が載っています。 3 次元グラフを上から順番に水平に切り落としていくようなものです。
3. は、「convex hull」(凸包) なら知っていますが、 「concave hull」(凹包) は私は初耳です。 既に実装されている convexhull フィルタに対応して新設されたフィルタです。 chi_length というパラメータがあり、 それに応じて形も変化するもののようで、 一般には凸とは限らない図形になります。 指定したデータを全部中に含むような閉曲線であることは凸包と同じですが、 そこから作られるドロネー三角形分割から、 パラメータに応じて三角形をいくつか削除して作られるχ-形状 (chi-shape) と呼ばれる閉曲線を作成するようです。 点集合全体のおおまかな形を知るためには、 凸包よりもいいのかもしれません。
4. は、追加列で arrowstyle の index 番号を 指定できるようになったものです。 これで with vectors や with arrows による 1 回の plot で、 多くの種類のベクトルや矢を表示できるようになります。
(cf. 「情報やメモ (05/30 2023)」)
gnuplot による単振り子のシミュレーションの例を紹介します。 これは import を使用するので、そのサンプルにもなると思います。 なお、import のサンプルは、以下の、例えば松田さんのサイト、 米澤さんのサイトでも紹介されています。
単振り子は、長さ l の軽いひもに質量 m のおもりをつけて原点に結んで 揺らした振り子の運動です。\(u\) を鉛直方向に対する振れ角とすると、 おもりの位置は \((x,y) = l(\sin u,\cos u)\) となり、 重力加速度を g とすると、まさつや空気抵抗を無視すれば、 \(u=u(t)\) (t: 時刻) に対する運動方程式は \[ mlu'' = -g\sin u \] となります。 初期値を \(u(0)=u_0\in(0,\pi), u'(0)=0\) とすると、 この方程式の解は楕円関数で表現できることが知られています。 \(k=\sin(u_0/2)\) とすると、振り子の周期は \(T=4K(k)\sqrt{l/g}\) で、 \(K(k) = F(\pi/2,k)\) は第一種完全楕円積分、 \(F(\phi,k)\) は第一種不完全楕円積分 \[ F(\phi,k) = \int_0^{\phi}\frac{d\phi}{\sqrt{1-k^2\sin^2\phi}} \] であり、解は、 \[ u=2\sin^{-1}(k\times \mathrm{sn}(K(k)(1-4t/T)),k)) \] となります。ここで、\(\mathrm{sn}(u,k)\) はヤコビの楕円関数で、 \(u=F(\phi,k)\) の \(\phi\) に関する逆関数 \(\phi=F^{-1}(u;k)\) を用いて \[ \mathrm{sn}(u,k) = \sin(F^{-1}(u;k)) \] と表すこともできます。 なお、\(\mathrm{sn}(u,k)\) は、 複素変数の関数と考えれば二重周期関数ですが、 実変数の関数としては、周期は 4K(k) です。
gnuplot には完全楕円積分 \(K(k)\) は用意されていますが、 \(F(\phi,k)\) や \(\mathrm{sn}(u,k)\) は用意されていません。 それを、数値ライブラリの GNU gsl を利用し import して用いることにします。
なお、高校の物理等では、この単振り子の方程式は、 振れ角 \(\theta\) が小さい場合を考え \(\sin\theta\) を \(\theta\) で近似し 単振動として考えて等時性などを示したりします。 その場合、周期は \(T=2\pi\sqrt{l/g}\)、解は \[ u=u_0\cos(2\pi t/T) \] です。比較のためにこれも合わせてシミュレートしてみます。
gnuplot で import するためには、 gnuplot と gsl とのなかだちをする共有ライブラリが必要で、 C 言語で gnuplot 用のインターフェースを備えた関数を作る必要があり、 その書き方はサンプルが demo/plugin 内に demo_plugin.c として含まれているので、それを参考にすればいいでしょう。 なお、そこには Makefile.am もありますが、 これは autoconf 用のファイルで、 同様のものを書いて Makefile を生成させることも可能ですが、 直接 Makefile を書くことも難しくはないので、 ここでは Makefile のサンプルも紹介します (FreeBSD 用)。 また、demo/plugin に含まれる gnuplot_plugin.h も必要です。
gsl ライブラリは /usr/local/ にインストールされているとしていて、 FreeBSD の場合は -lgsl の後ろに -lgslcblas も必要です。 gmake clean として gmake とすると gsl1.so ができます。 使用している gsl の関数等については、 gsl1.c のコメントを参照してください。 そして、これを import すれば、 gnuplot 内で第 1 種不完全楕円積分を myincF(t,k)、 ヤコビの楕円関数は mysn(u,k) として利用できます。
単振り子の周期を T1, 線形近似の周期を T2 として、 以下のようにして両者の振れ角を表示できます。
import myincF(t, k) from "gsl1"
import mysn(t, k) from "gsl1"
myK(k) = EllipticK(k) # gnuplot の第一種完全楕円積分
g = 9.8
l = 1.0
u0 = 0.25*pi
k0 = sin(0.5*u0)
T1 = 4.0*myK(k0)*sqrt(l/g)
T2 = 2.0*pi*sqrt(l/g)
u1(t, k) = 2*asin(k*mysn(myK(k)*(1.0-4.0*t/T1), k))
u2(t) = u0*cos(2.0*pi*t/T2)
set grid
set samples 500
plot [0:6*T1] u1(x, k0) t "単振り子の振れ角",\
u2(x) t "線形近似の振れ角"
グラフを見ると、初期角 u0 が 0 には近くないため、 線形近似とはずれがあり、 単振り子の周期の方が線形近似の周期よりも少し長いことがわかります。 u0 をさらに大きくすれば、線形近似とのずれはより大きくなります。
さらに以下のようにして、 振り子の振れをアニメーションで再現することもできます。
set size square
set xrange [-l*1.2:l*1.2]
set yrange [-l*1.2:l*1.2]
Tlast = 6.0*T1 # 出力最終時刻
N = 100 # 時間分割数
set object 1 circle at 0,0 size l \
arc [(-u0-pi/2)*180/pi:(u0-pi/2)*180/pi] \
fs empty border lt -1
# 振り子の軌道
dt = Tlast/N
csz = 0.05 # おもりのサイズ
do for [j=0:N] {
unset arrow 2; unset object 3; unset arrow 4;
unset object 5
t = j*dt
set title sprintf("t=%.3f*T1", t/T1)
u = u1(t, k0)
a = l*cos(u - pi/2.0); b = l*sin(u - pi/2.0)
set arrow 2 from 0,0 to a,b nohead lt 1 lw 2
set object 3 circle at a,b size csz fs solid fc lt 1
# arrow と circle で単振り子を表現
u = u2(t)
a = l*cos(u - pi/2.0); b = l*sin(u - pi/2.0)
set arrow 4 from 0,0 to a,b nohead lt 2 lw 2
set object 5 circle at a,b size csz fs solid fc lt 2
# こちらは線形近似
plot 1/0 w l lt 1 lw 3 t "正確な単振り子", \
1/0 w l lt 2 lw 3 t "単振動の近似振り子"
# 1/0 の空打ちで arrow, object の描画と key の描画
}
pause 0.1
」などを適宜入れてみるといいでしょう。
なお、正確な単振り子と単振動による近似的な振り子の違いは、 上の例では周期の違いが際立って出てしまいますが、 周期以外にもずれがあります。 それを見るには、上の u2 の定義内の T2 を T1 に変えて、 周期を u1 と同じにしてしまって、特に u0 を 0.75*pi や 0.9*pi のような 大きな値 (pi に近い値) にするとよくわかります。 u2 と u1 の差をグラフに描いたり、 または擬似的なアニメーションで見比べるとわかると思いますが、 正確な単振り子の方が、振れの両端 (u0, -u0 になるところ) にとどまっている時間が、 単振動に比べるとやや長めになっています。
02/11 頃に gnuplot-5.4.6 が公開されました。 5.4.6 での新規機能、変更、修正は以下のようです。
新規機能は、開発版からのバックポートですが、 変更や修正はそれほど多くはありません。 なお、これが 5.X 系列としては最後のリリース版で、 次期リリース版のバージョンは 6.0 になる予定です (確か)。
5.4.6 の all.dem の出力も置いておきます。
前回の 5.4.3 用のもの (「情報やメモ (01/11 2022)」) と比較すると、
の、いずれも追加された 2 つのデモファイルの分だけ 6 頁分増えています。 今回の変更点はそれほど多くはないですが、 今回の 5.4.6 と次期バージョンの 6.X とは、 すでに開発版に関する紹介でいつくか示していますが、 だいぶ違いがあります。 リリース版しか利用できない方は、もうしばらくお待ちください。
なお、ドキュメントに関しても 6.X からはだいぶ良くなる予定で、 デフォルトの Makefile に日本語の PDF の作成ルールが追加されますし (lualatex を利用)、 texinfo や latex2html を必要としない HTML 形式のマニュアルも 付属の doc2web というプログラムで作れるようになる予定です。 HTML 形式のマニュアルはこんなやつです。
まだ若干リンクがおかしいところがあったりするようですが、 doc2web によるマニュアルの日本語化もそれほど難しくはないので、 そのうちに紹介したいと思います。
最新の開発版 (git) の all.dem の出力を置いておきます。
「情報やメモ (09/28 2022)」 の時点でのデモ (740 ページ) に比べると、かなり変更が追加されています。
最後の watchpoints.dem は、前の 「情報やメモ (09/28 2022)」 の時点でもあり、all.dem にも入っていたはずなのですが、 なぜか前回のデモでは出力されていませんでした。 また、all.dem には入っていませんが、 function_block.dem, spotlight.dem などのデモも追加されています。
2022 09/27 以降の git 版の改変としては、以下のようなものがあるようです (ドキュメントの差分より)。
2. は、より複雑な関数を定義する機能の新設です。 従来は、gnuplot での関数定義は「f(x)=...」のような形だけで、 3 項演算子などを使って ある程度複雑な関数も無理矢理定義したりしていましたが、 今回の仕組みにより、プログラミング言語などの関数定義に近い形のものが 行えるようになります。ドキュメントには、以下のような例が出ています。
function $sinc(arg) << EOFヒアドキュメント形式での定義で、 関数が呼び出されたときにそのブロックが評価されるので、 処理は早くはありません。 速度が必要な場合はプラグイン機能を利用すべきです。 なお、この関数ブロックで定義する関数の引数は ARGC, ARGV[] でもアクセスできるので、 可変引数の関数も容易に作ることができます。 ドキュメントには、以下のような例が出ています。
if (arg == 0) { return 1.0 }
return sin(arg) / arg
EOF
function $max << EOFlocal というのが局所変数の定義で、この関数ブロック用に導入されました。 この関数ブロックの機能により、 より高度で、可読性の高い gnuplot スクリプトが書けるようになると思います。
local max = real("-Inf")
if (ARGC == 0) { return NaN }
do for [i=1:ARGC] {
if (max < ARGV[i]) {
max = ARGV[i]
}
}
return max
EOF
3. と 4. はセットのようなもののようですが、 実はあまりよく理解していません。ドキュメントでは、 2 次元の極座標描画 (polar plotZ) での温度分布図 (heatmap) を描くための機能のようです。
5. は、関数のピーク (極) がとがっている場合、 それを with lines で描画するときに、 標本点数 (sample) が少ないとそのピークをまたいで線分を描いてしまうと ピークがだいぶ下ってしまいますが、 それを改善するためのオプションです。
このオプションをつけると、本当の極を二分法で見つけ、 その点を標本点に追加することでピークがとがったグラフを描いてくれます。
(cf. 「情報やメモ (04/07 2023)」)