gnuplot で2曲線の描画範囲を個別に設定して plot と塗りつぶし

同一の描画範囲で2本の曲線を plot

陽関数の plot では,2つの曲線を同時にグラフにする場合,通常,以下のように描画範囲を共通にとります。

以下の例では $y=\cos x$ と $y=\sin x$ を $0 \leq x \leq 2 \pi$ の範囲で plot します。

In [1]:
reset
# 以後 reset しない限り凡例非表示。
set key off

plot [0:2*pi] cos(x), sin(x)

2本の曲線の描画範囲を個別に設定して plot

2つの曲線の描画範囲をそれぞれ別に,また曲線の描画範囲とグラフの表示範囲を独立に設定することもできます。

以下の例では,グラフの表示範囲を横軸 [-0.2:pi+0.2],縦軸 [-0.1:1.1] にし,

  • [0:pi/4] の範囲で $y=\cos x$
  • [0:pi] の範囲で $y=\sin x$

を plot します。sample とするのがキモです。

help plot sample からの引用:

例:

以下のコマンドにはあいまいさが含まれます。先頭の範囲は、多分最初の関数の標本化のみに向けたのだと思いますが、実際はそうではなく、すべての描画要素に適用するように解釈されます:

    plot [0:10] f(x), [10:20] g(x), [20:30] h(x)

以下のコマンドは、上の例のあいまいさを除くためにキーワード sample を追加したもので、その範囲指定を plot 全体に適用しないようにしています:

    plot sample [0:10] f(x), [10:20] g(x), [20:30] h(x)
In [2]:
plot [-0.2:pi+0.2] [-0.1:1.1] sample \
  [0:pi/4] cos(x), \
  [0:pi] sin(x)

曲線と横軸に平行な直線の間を塗りつぶす

$0 \leq x \leq \frac{\pi}{4}$ つまり [0:pi/4] の範囲で $y=\cos x$ と $y=\sin x$ に囲まれた領域を塗りつぶしてみます。両方が曲線のときはちょっと書式が複雑になります。

まず,片方が $x$ 軸に平行な直線,たとえば領域が

  • 曲線 $y=\cos x$ と
  • $x$ 軸に平行な直線 $y=\cos\frac{\pi}{4}$

で囲まれている場合は,

  • [0:pi/4] cos(x)
  • with filledc (filledcurves) y=cos(pi/4)

をつけて plot します。

In [3]:
plot [-0.2:pi+0.2] [-0.1:1.1] sample \
  [0:pi/4] cos(x) with filledc y=cos(pi/4), \
  [0:pi] sin(x)

同様にして $0 \leq x \leq \frac{\pi}{4}$ つまり [0:pi/4] の範囲で曲線 $y=\sin x$ と直線 $y=\cos\frac{\pi}{4}$ で囲まれた領域の場合は,[0:pi/4] sin(x)

  • with filledc (filledcurves) y=cos(pi/4)

をつけて plot します。

In [4]:
plot [-0.2:pi+0.2] [-0.1:1.1] sample \
  [0:pi/4] cos(x) with filledc y=cos(pi/4), \
  [0:pi/4] sin(x) with filledc y=cos(pi/4), \
  [0:pi] sin(x)

塗りつぶし色の設定

fc (fillcolor) で同じ色に設定すれば,あたかも1回で懸案の領域を塗りつぶしたように見えます。

In [5]:
plot [-0.2:pi+0.2] [-0.1:1.1] sample \
  [0:pi/4] cos(x) with filledc y=cos(pi/4) fc 'yellow', \
  [0:pi/4] sin(x) with filledc y=cos(pi/4) fc 'yellow', \
  [0:pi] sin(x)

陽関数で表された2曲線の間を塗りつぶす

$x_1 \leq x \leq x_2$ つまり [x1:x2] の範囲で2曲線 $y=f(x)$,$y=g(x)$ で囲まれた領域を1回で塗りつぶすには,以下のようにします。書式は

  • plot [x1:x2] '+' using 1:(f($1)):(g($1)) with filledc

以下では [0:pi/4] の範囲で $y=\cos x$ と $y=\sin x$ で囲まれた領域を 'yellow' で塗りつぶします。

塗りつぶし後,くっきり縁取りをするために,lw (linewidth) 2lc (linecolor) を変えて [0:pi/4] cos(x) および [0:pi] sin(x) しています。

In [6]:
reset

plot [-0.2:pi+0.2] [-0.1:1.1] sample \
  [0:pi/4] '+' using 1:(cos($1)):(sin($1)) \
               with filledc fc 'yellow' notitle, \
  [0:pi/4] cos(x) lc 'black' lw 2 title 'cos x', \
  [0:pi]   sin(x) lc 'red' lw 2 title 'sin x'

横軸の目盛位置と目盛ラベルの設定

今度は,以下のページにある例:
$\displaystyle \frac{\pi}{4} \leq x \leq \frac{5\pi}{4}$ の範囲で $y=\sin x$ と $y=\cos x$ で囲まれた部分を塗りつぶします。

横軸の目盛を $\frac{\pi}{4}$ ごとにつける設定をしてみます。

「理工系の数学B」の積分の練習問題で,「図の塗りつぶした部分の面積を求めよ。」なんていうときに使います。

In [7]:
reset

# 横軸 π/4 ごとに目盛
set xtics pi/4
# 目盛ラベルのフォーマット設定
set format x '%4.2P π'

plot [0:2*pi] [-1.1:1.3] sample \
  [pi/4:5*pi/4] '+' using 1:(sin($1)):(cos($1)) \
                    with filledc fc 'yellow' notitle, \
  [0:2*pi] cos(x) lc 'blue' lw 2 title 'cos x', \
           sin(x) lc 'red' lw 2 title 'sin x'

横軸の目盛の位置とラベルを手動で設定する例。

In [8]:
reset
# 目盛とラベルを手動で設定する例
set xtics ("0" 0,"π/4" pi/4,"π/2" pi/2,"3π/4" 3*pi/4,"π" pi,\
           "5π/4" 5*pi/4,"3π/2" 3*pi/2,"7π/4" 7*pi/4,"2π" 2*pi)

plot [0:2*pi] [-1.1:1.3] sample \
  [pi/4:5*pi/4] '+' using 1:(sin($1)):(cos($1)) \
                    with filledc fc 'yellow' notitle, \
  [0:2*pi] cos(x) lc 'blue' lw 2 title 'cos x', \
           sin(x) lc 'red' lw 2 title 'sin x'

グリッド(格子線)の設定(塗りつぶし部分も見えるように)

set grid で格子線を描きますが,以下のように塗りつぶした部分の格子が見えなくなる場合があります。

In [9]:
set grid

# 目盛とラベルを手動で設定する例
set xtics ("0" 0,"π/4" pi/4,"π/2" pi/2,"3π/4" 3*pi/4,"π" pi,\
           "5π/4" 5*pi/4,"3π/2" 3*pi/2,"7π/4" 7*pi/4,"2π" 2*pi)

plot [0:2*pi] [-1.1:1.3] sample \
  [pi/4:5*pi/4] '+' using 1:(sin($1)):(cos($1)) \
                    with filledc fc 'yellow' notitle, \
  [0:2*pi] cos(x) lc 'blue' lw 2 title 'cos x', \
           sin(x) lc 'red' lw 2 title 'sin x'

そんなときは set grid front とすることで,塗りつぶした部分の上(フロント)にグリッドが描かれます。

In [10]:
set grid front

# 目盛とラベルを手動で設定する例
set xtics ("0" 0,"π/4" pi/4,"π/2" pi/2,"3π/4" 3*pi/4,"π" pi,\
           "5π/4" 5*pi/4,"3π/2" 3*pi/2,"7π/4" 7*pi/4,"2π" 2*pi)

plot [0:2*pi] [-1.1:1.3] sample \
  [pi/4:5*pi/4] '+' using 1:(sin($1)):(cos($1)) \
                    with filledc fc 'yellow' notitle, \
  [0:2*pi] cos(x) lc 'blue' lw 2 title 'cos x', \
           sin(x) lc 'red' lw 2 title 'sin x'

set output "./gnuri09.svg"
replot
set output

縦線を引く

媒介変数表示にしないで縦線を引く例。

以下の例では,2曲線の交点の座標が書かれたテキストファイルを作成し,それを読み込んで with impulse で plot することで,交点から $x$ 軸までの縦線を描いています。

In [11]:
# 2曲線の交点の座標が書かれたテキストファイルを作成
set print "temp01.txt"
  print pi/4, "  ", cos(pi/4)
  print 5*pi/4, "  ", cos(5*pi/4)
set print
In [12]:
set grid front
# 座標軸の表示
set zeroaxis

# 目盛とラベルを手動で設定する例
set xtics ("0" 0,"π/4" pi/4,"π/2" pi/2,"3π/4" 3*pi/4,"π" pi,\
           "5π/4" 5*pi/4,"3π/2" 3*pi/2,"7π/4" 7*pi/4,"2π" 2*pi)

plot [0:2*pi] [-1.1:1.3] sample \
  [pi/4:5*pi/4] '+' using 1:(sin($1)):(cos($1)) \
                    with filledc fc 'yellow' notitle, \
  [0:2*pi] cos(x) lc 'blue' lw 2 title 'cos x', \
           sin(x) lc 'red' lw 2 title 'sin x', \
  "temp01.txt" with impulse lw 1.5 lc "black" notitle

with impulse では始点が $x$ 軸上に限られます。

始点と終点を設定した縦線を描く例。

縦線の始点と終点の座標が書かれたテキストファイルを作成し,それを読み込んで plot します。
with lines (w l) で点を直線でつなぎますが,ファイルに空行があると,そこは線でつなげないため,複数の直線を描くことができます。

In [13]:
# 縦線の始点と終点の座標が書かれたテキストファイルを作成
set print "temp02.txt"
  # 1本目の始点
  print pi/4, -1.1
  # 1本目の終点
  print pi/4, "  ", cos(pi/4)
  # 2本目とつなげないように空行
  print ""
  # 2本目の始点
  print 5*pi/4, -1.1
  # 2本目の終点
  print 5*pi/4, "  ", cos(5*pi/4)
set print
In [14]:
set grid front
# 座標軸の表示
set zeroaxis

# 目盛とラベルを手動で設定する例
set xtics ("0" 0,"π/4" pi/4,"π/2" pi/2,"3π/4" 3*pi/4,"π" pi,\
           "5π/4" 5*pi/4,"3π/2" 3*pi/2,"7π/4" 7*pi/4,"2π" 2*pi)

plot [0:2*pi] [-1.1:1.3] sample \
  [pi/4:5*pi/4] '+' using 1:(sin($1)):(cos($1)) \
                    with filledc fc 'yellow' notitle, \
  [0:2*pi] cos(x) lc 'blue' lw 2 title 'cos x', \
           sin(x) lc 'red' lw 2 title 'sin x', \
  "temp02.txt" w l lw 1.5 lc "black" notitle

set output "./gnuri11.svg"
replot
set output

いらなくなったデータファイルは削除しておきます。

In [15]:
system("rm temp??.txt")

異なる範囲での塗りつぶしの例

もう一つの例。$y=f(x)$ と $x$ 軸の間を,$0.5 \leq x \leq 2$ までは黄色で,$2 \leq x \leq 2.5$ までは灰色で塗りつぶしてみます。

In [16]:
reset
set key off
set grid front
set zeroaxis

f(x)= 0.6*x + 0.4*cos(x)

plot [-0.2:3.5][-0.2:1.5] sample \
  [0.5:2] f(x) with filledc y=0 fc 'yellow', \
  [2:2.5] f(x) with filledc y=0 fc 'gray', \
  [0.2:2.8] f(x) lw 2 lc 'blue'

グラフを pdf ファイルに保存

直前のグラフを pdf ファイルに保存する例。なるべく見た目をそのまま pdf に保存したいので,予め show term で設定状況を確認し,それらしく set term pdf しよう。

In [17]:
show term
Out[17]:
   terminal type is svg size 600,450 fixed enhanced font 'Noto Sans CJK JP,14' butt dashlength 1.0 

In [18]:
set term pdf size 6, 4.5 font 'Noto Sans CJK JP,14'
set output "mygraph.pdf"
replot
set output
Out[18]:
Terminal type is now 'pdfcairo'
Options are ' transparent enhanced font "Noto Sans CJK JP,14" fontscale 0.5 size 6.00in, 4.50in '

ふたたび Jupyter Notebook のインラインで表示させたい場合は,set term ... で,予め show term で確認しておいた状況に戻します。

In [19]:
set term svg size 600,450 fixed enhanced font 'Noto Sans CJK JP,14'
Out[19]:
Terminal type is now 'svg'
Options are 'size 600,450 fixed enhanced font 'Noto Sans CJK JP,14' butt dashlength 1.0 '
In [20]:
replot

参考:gnuplotでグラフを書いて、その中身を塗りつぶしたいのですがどのようにしたらいいですか? – Yahoo!知恵袋

例えば以下の領域を塗りつぶしたいという話。

$$D = \{(x, y) | 1 \leq x \leq 2, \ \frac{1}{x} \leq y \leq 2 \}$$

ベストアンサー

ベストアンサーは,gnuplot の三項演算子(if then else 的な条件分岐)を入れ子にし,定義されていない数 1/0 (プロットコマンドでは無視される)を使ったユニークな例です。

参考までに,以下にコピペしておきます。

In [21]:
reset

# 1 <= x <= 2 のときにだけ 1/x を返す関数
# x < 1 や x > 2 の時は定義されていない数 1/0 を返すのでプロットされない
f(x) = (x < 1) ? 1/0 : ((x > 2) ? 1/0 : 1/x)

set xrange [0:4]
set yrange [0:4]
plot f(x) with filledcurve y2=2, 1/x, 2

塗りつぶし範囲を個別に指定した別解

塗りつぶしの範囲とグラフの描画範囲を個別に設定して描く例。sample と宣言するのがキモでした。この場合は三項演算子を駆使した関数定義をする必要はありません。

In [22]:
reset

plot [0:4][0:4] sample [1:2] 1/x with filledc y=2, [0:4] 1/x, 2