三項演算子を用いた条件分岐

gnuplotでは三項演算子? :を用いて、関数の定義やplotなどのコマンド中での条件分岐が出来ます。なお、この三項演算子はC言語などで用いられているものと同じ働きをします。

三項演算子とは

三項演算子? :は以下のように使います。

条件 ? 値1 : 値2

するとこの演算子は、条件が真のときは値1を、偽のときは値2をそれぞれ返します。

簡単な例を以下に示します。

(x > y) ? x : y

この例では、条件部分が(x > y)ですので、変数xの方がyよりも大きければxの値を、そうでなければyの値を返します。つまり、(x, y)の最大値を返すようになっています。

この三項演算子は関数定義やplotコマンドの中などで使うことが出来ます。例えば、上で挙げた例を以下のように関数定義として用いると、xyのうちの大きい方を返す関数max(x,y)を定義できます。

max(x,y) = (x > y) ? x : y

より巧妙な使用方法は以下で説明します。また、便利な文字列関数の項などでも3項演算子を用いています。

三項演算子の使用例1:滑らかでない関数

三項演算子を用いて、定義域によって値の異なる関数を定義することが出来ます。最も簡単な例として、x<0のとき0x>0のとき1を取るような、階段関数step(x)の定義方法を以下に示します。

step(x) = (x < 0.0 ? 0.0 : 1.0)
set samples 1000
set xrange [-10:10]
set yrange [-0.1:1.1]
plot step(x)

このスクリプトを実行すると、以下のように階段関数を描くことが出来ます。(なお、set samples 1000としているのは、標準設定のままだと関数を100点で描くために階段関数のエッジがなまって見えてしまうためです。)

三項演算子の使用例2:関数の一部分だけをプロット

ある関数の一部分だけをプロットするには、三項演算子と1/0を使います。1/0は定義されていない数であり、プロットコマンド中では無視されます。このことを利用して、関数の一部分のみをプロットすることができます。以下の例ではサイン関数のうち、sin(x)の値が0.5以上になる部分を除いてプロットしています。

set xrange [0:10]
set yrange [-1.1:1.1]
plot ( sin(x) < 0.5 ? sin(x) : 1/0 )

三項演算子の使用例3:データファイルへのフィルタ

三項演算子を用いて、データファイルのデータのうち、ある条件を満たすものだけをプロットすることができます。

例を以下に示します。以下の例では下のようなデータファイルternary-data.datを用いています。このデータは1列目にxの値、2列目にyの値が入っており、3列目には数字またはハイフンのいずれかであるcodeが、4列目にはokまたはerrという文字列が、それぞれ入っています。(1行目は#で始まっているので、コメント行として無視されます。)

#x	y	code	comment
0	2.5	0	ok
1	2.1	1	err
2	1.95	-	err
3	2.3	0	ok
4	2.0	1	ok
5	2.1	3	err
6	1.8	1	ok
7	1.85	3	err
8	1.4	-	err
9	1.5	0	ok

例えば、3列目のcodeの値が2以下の場合緑の●で、3以上の場合黒の×でプロットするには以下のようにします。

plot "ternary_data.dat" u 1:($3<=2 ? $2 : 1/0) w p pt 7 lc rgb "green" ps 2 title "code <= 2",\
     "ternary_data.dat" u 1:($3>=3 ? $2 : 1/0) w p pt 2 lc rgb "black" ps 2 title "code >= 3"

usingの引数の中でだけ使えるvalid()関数やstringcolumn()関数を用いると、より複雑なフィルタをかけることもできます。

valid()関数は整数値を引数にとります。その引数をnとすると、この関数はプロットしているデータファイルのn列目のデータが数値データであれば真、そうでなければ偽を返す関数です。以下の例ではcode列が数値データかどうか判断して、数値データである場合と無い場合に分けてプロットしています。valid()関数の引数が$3ではなく3であることに注意してください。

plot "ternary_data.dat" u 1:(valid(3)  ? $2 : 1/0) w p pt 7 lc rgb "red"   ps 2 title "valid code",\
     "ternary_data.dat" u 1:(!valid(3) ? $2 : 1/0) w p pt 2 lc rgb "black" ps 2 title "invalid code"

stringcolumn()関数は整数値を引数にとります。その引数をnとすると、この関数はプロットしているデータファイルのn列目のデータを文字列として返します。例えば、データファイルの1列目のデータが100だった場合stringcolumn(1)は文字列"100"を返しますし、以下の例のように4列目のデータがokならばstringcolumn(4)は文字列"ok"を返します。以下の例では4列目の文字列がokである場合とerrである場合に分けてプロットしています。stringcolumn()関数の引数が$4ではなく4であることに注意してください。

plot "ternary_data.dat" u 1:(stringcolumn(4) eq "ok"  ? $2 : 1/0) w p pt 9 lc rgb "blue"  ps 2 title "ok",\
     "ternary_data.dat" u 1:(stringcolumn(4) eq "err" ? $2 : 1/0) w p pt 1 lc rgb "black" ps 2 title "error"