第2回:▼ 複数のグラフを描く
■ リテラル
リテラル (literal) とは、 「文字の並び」の通りに解釈される量をいう。
1
や 1.1
はリテラルである。 それぞれ、整数 1
, 小数1.1
という値として評価されるからである。
■ 文字列
「文字の並び」として表される量が、文字列である。 文字列のリテラルは、ダブルクォート "
で囲まれた文字の並びである。
julia> "Hello world"
"Hello world"
文字列を連結するには、演算子 *
を用いる。
julia> h="Hello"
"Hello"
julia> w="world"
"world"
julia> h*w
"Helloworld"
julia> h*" "*w
"Hello world"
演算子 *
は、数同士に対して用いると乗算の意味になる。文字列同士に用いると文字列の連結の意味になる。このように、同じ演算子 *
に対して、複数の意味があり、適用する値の型(の組合せ)に応じて、適切な意味が選ばれて、計算される。
数字を表す文字列を作るには、string
関数を用いる。
julia> string(0)
"0"
julia> string(1)
"1"
julia> string(1.1)
"1.1"
▼ グラフに凡例を加える
グラフの凡例(lengend)は、グラフに描かれた曲線を区別するための説明である。 PyPlotパッケージで書かれたグラフに凡例を追加するには、以下のようにする。
まず、plot
関数に label=文字列
の形式で、 その曲線に付与する文字列を指定する。 全ての曲線を描いた後に、legend
関数を実行すると、グラフに凡例が追加される。
using PyPlot
xs=-1:0.1:1
plt.plot(xs,-1*xs, label="y=-x")
plt.plot(xs,2*xs.-1, label="y=2x-1")
plt.legend()
比例関係 $y = ax$ ($a=1,2,3,4,5$)のグラフを描こう。
using PyPlot
xs=-1:0.1:1
plt.plot(xs, xs, label="y= x" )
plt.plot(xs, 2*xs, label="y=2x" )
plt.plot(xs, 3*xs, label="y=3x" )
plt.plot(xs, 4*xs, label="y=4x" )
plt.plot(xs, 5*xs, label="y=5x" )
plt.legend()
▼ グラフに、水平線・垂直線を加える
式 $y=ax$ は全て原点 $(0,0)$ を通る。 水平線や垂直線の補助線を引いて、これを見やすくする。
PyPlotパッケージに用意された関数 axhline(y)
は、 縦座標 $y$ で水平線(horizontal line)を描く。 最初の引数には、水平線を引く $y$ 座標を指定する。 キーワード引数 color="k"
は、黒色(black)で描くことを指定し、lw=0.5
は線幅(linewidth)を指定する。
また、関数 axvline(x)
は、横座標 $x$ で垂直線 (vertical line)を描く。 最初の引数には、垂直線を引く $x$ 座標を指定する。
上のプログラムに続けて
# 水平線 y=0
plt.axhline(0, color="k", lw=0.5)
# 垂直線 x=0
plt.axvline(0, color="k", lw=0.5)
▼ グラフの描画範囲を指定する
plot
命令は、全ての点を表示しようとする。 グラフの描画範囲を調整するには、関数 xlim
と ylim
を用いる。
- 関数
xlim(a,b)
は、x軸の描画を a から b の範囲に限定する。 - 関数
ylim(a,b)
は、y軸の描画を a から b の範囲に限定する。
上のプログラムに続けて
# 描画範囲
plt.xlim(-3,3) # <=
plt.ylim(-3,3) # <=
別の描画範囲を指定してみる。 上のプログラムに続けて
# 描画範囲
plt.xlim(-0.5,0.5) # <=
plt.ylim(-0.5,0.5) # <=
▼ グラフのアスペクト比を等しくする
グラフの縦横の長さの比をアスペクト比という。
関数 plt.axes().set_aspect()
は、アスペクト比を指定する命令である。
何も指定しない場合は、plt.axes().set_aspect("auto")
であり、 アスペクト比を適当に調整する。
関数 plt.axes().set_aspect("equal")
は、アスペクト比を等しくする命令である。 通常は、前項の描画範囲の指定と同時に用いる。
アスペクト auto
の場合
using PyPlot
xs=-1:0.2:1
plt.plot(xs, xs)
plt.xlim(-1,1)
plt.ylim(-1,1)
plt.axhline(0, color="k", lw=0.5)
plt.axvline(0, color="k", lw=0.5)
# plt.axes().set_aspect("auto") # PyPlot起動時は指定しなくてもよい
アスペクト equal
を指定する。上のプログラムに続けて
plt.axes().set_aspect("equal") # <=
■ for文
Repeated Evaluation: Loops (section)
一つずつ要素を取り出すことができる量をコレクションという。 ベクトルやRangeは、コレクションである。
for
文を用いると、コレクションから要素を一つづつ取り出して、 end
文が出現するまでの文を繰り返して、計算を行うことができる。 この繰り返される部分をブロック (block)という。 ブロックは、字下げ (indent) で表記される。 が、字下げは見やすさのためだけである。
繰り返しをループ(loop)ともいう。
ブロックは、for文以外にも出現する (例えば、 ■ if文 )。 区別したいなら for
ブロックとも称する。
次の例では、変数 i
に、ベクトルの各要素を入れて、end
文までの計算を繰り返す。 コレクションの各要素が入る変数をループ変数 (loop variable)という。
julia> for i in [1,3,2]
@show i # 式 i の値を表示する
end
i = 1
i = 3
i = 2
@show i
は、式 i
の値を表示するマクロである。
Range型を用いた for
文の例を示す。
julia> for i in 1:5
println( string(i) )
end
1
2
3
4
5
string
関数の結果を表示する。 println
関数は、印字してから、改行する命令である。
▼ for 文でパラメータを変えて、複数のグラフを描く
▼ グラフに凡例を加える の後半のプログラムを再掲する。
using PyPlot
xs=-1:0.1:1
plt.plot(xs, xs, label="y= x" )
plt.plot(xs, 2*xs, label="y=2x" )
plt.plot(xs, 3*xs, label="y=3x" )
plt.plot(xs, 4*xs, label="y=4x" )
plt.plot(xs, 5*xs, label="y=5x" )
plt.legend()
上のプログラムを、for
文を用いた繰り返しで書き直してみよう。
次の例の for
文では、 ループ変数 a
に、1, 2, 3, 4, 5 の値が順番に入って、end
までの文が実行される。 すなわち、直前のプログラムと同等である。
using PyPlot
xs=-1:0.1:1
for a in 1:5
plt.plot(xs, a*xs, label="y="*string(a)*"x" )
end
plt.legend()
▼ 冪乗関数を描く
x^y
は、冪(べき, power)ないし冪乗(べきじょう)$x^y$を表す。 $x$ を底 (base)、$y$ を冪指数 (exponent)という。
julia> 2^2
4
julia> 2^3
8
julia> 2^4
16
スカラー c
とベクトル v
とに演算子 .^
を適用する c .^ v
と、 各々の冪指数に対して冪乗を計算したベクトルが得られる。
底が整数の場合は .^
の前に空白を入れる。
julia> 2 .^[2,3,4]
3-element Array{Int64,1}:
4
8
16
整数(底)の直後に .^
と書くと例外が出るので注意しよう。
julia> 2.^[2,3,4]
ERROR: syntax: invalid syntax "2.^"; add space(s) to clarify
底が小数の場合は、その直後に .^
と書いてよい。
julia> 2.0.^[2,3,4]
3-element Array{Float64,1}:
4.0
8.0
16.0
ベクトルとスカラーとに演算子 .^
を適用する v .^ c
と、 各々の底に対して、冪乗を計算したベクトルが得られる。
julia> [2,3,4].^2
3-element Array{Int64,1}:
4
9
16
julia> [2,3,4].^2
3-element Array{Int64,1}:
4
9
16
Range型とスカラーとに演算子 .^
を適用する v .^ c
と、 各々の底に対して、冪乗を計算したベクトルが得られる。
julia> (2:4).^2
3-element Array{Int64,1}:
4
9
16
julia> 2:4 .^2 # `^`は `:` よりも優先度が高い
2:16
区間 $x= [0,1]$ で、冪乗 $y=x^a, (a=2,3,4,5)$ のグラフを描こう。
plt.axes().set_aspect("equal")
は、 グラフの縦横比 (アスペクト比 aspect ratio) を等しくする命令である。
using PyPlot
plt.axes().set_aspect("equal")
xs=0:0.1:1
plt.plot(xs, xs.^2 )
plt.plot(xs, xs.^3 )
plt.plot(xs, xs.^4 )
plt.plot(xs, xs.^5 )
for文を使って、繰り返しの処理をまとめる。 区間を $x= [0,2]$ に拡大して、凡例を追加しよう。
using PyPlot
plt.axes().set_aspect("equal")
xs=0:0.05:2
for a in 2:5
plt.plot(xs, xs.^a , label="y=x^"*string(a) )
end
plt.legend()
# 描画範囲を設定
plt.xlim(-0.05,2)
plt.ylim(-0.05,2)
冪乗 $y=x^a, (a=2,3,4,5)$ は全て、点 $(1,1)$ を通る。$x=1$と $y=1$ の線を付与して、これを見やすくしよう。
using PyPlot
plt.axes().set_aspect("equal")
# 間隔を狭めた
xs=0:0.05:2
for a in 2:5
plt.plot(xs, xs.^a , label="y=x^"*string(a) )
end
plt.legend()
# 描画範囲を設定
plt.xlim(-0.05,2)
plt.ylim(-0.05,2)
# 水平線 y=1
plt.axhline(1, color="k", lw=0.5)
# 垂直線 x=1
plt.axvline(1, color="k", lw=0.5)
■ ベクトルの要素の加減算
ベクトル v
とベクトル u
とに 演算子 .+
や .-
を適用する v .+ u
, v .- u
と、 対応する要素同士を加減算した要素を持つベクトルが得られる。
julia> xs = [1,2,2,1]
4-element Array{Int64,1}:
1
2
2
1
julia> ys = [1,1,3,1]
4-element Array{Int64,1}:
1
1
3
1
julia> xs .+ ys
4-element Array{Int64,1}:
2
3
5
2
julia> xs .- ys
4-element Array{Int64,1}:
0
1
-1
0
■ ベクトルとRange型との加減算
Range型 v
とベクトル u
とに 演算子 .+
や .-
を適用する v +. u
, v .- u
と、 Range型とベクトルとの寸法 (要素の数)が等しいなら、 対応する要素同士を加減算した要素を持つベクトルが得られる。 ベクトルとRange型に演算子 .+
や .-
を適用しても同様である。 要素の数が異なると、例外 (exception, エラー)となる。
julia> xs = 1:1:5
1:1:5
julia> ys = [11, 13, 15, 17, 19]
5-element Array{Int64,1}:
11
13
15
17
19
julia> xs .+ ys
5-element Array{Int64,1}:
12
15
18
21
24
julia> ys .- xs
5-element Array{Int64,1}:
10
11
12
13
14
Range型をベクトルに変換してしまうと、元が等差数列であるという情報が欠落する。どうしても、ベクトルでないと困る場合だけ、ベクトルに変換しよう。
▼ ローレンツ関数を描く
以下の曲線を、 ローレンツ関数 (Lorentzian function)という。
パラメータを $x_0 = 0, \gamma = 2$ のように選ぶと、 以下のように簡単な形となる。
まず、この曲線を描いてみる。
Range型の各要素に対して加算や除算を行うため、1 / (xs.^2 +1)
では駄目である。/
と +
の前にピリオド .
を付与する。
julia> xs=-3:0.5:3
-3.0:0.5:3.0
julia> 1 ./ (xs.^2 .+1)
13-element Array{Float64,1}:
0.1
0.13793103448275862
0.2
0.3076923076923077
0.5
0.8
1.0
0.8
0.5
0.3076923076923077
0.2
0.13793103448275862
0.1
上のグラフを描こう。
using PyPlot
xs=-3:0.1:3
plt.plot(xs, 1 ./ (xs.^2 .+1) )
以下のように、パラメータ $\gamma$ を追加する。
三つのパラメータ $\gamma=0.5, 1, 2$ について、この曲線を描く。
using PyPlot
xs=-3:0.05:3
gamma=0.5
plt.plot(xs, (gamma/2) ./ (xs.^2 .+(gamma/2)^2), label=gamma )
gamma=1.0
plt.plot(xs, (gamma/2) ./ (xs.^2 .+(gamma/2)^2), label=gamma )
gamma=2.0
plt.plot(xs, (gamma/2) ./ (xs.^2 .+(gamma/2)^2), label=gamma )
plt.legend()
gamma
の値が変わっても、それぞれの曲線を描くための命令は変わらない。 for文を用いて、gamma
の値を変えてみよう(結果のグラフは変わらないので、省略する)。
using PyPlot
xs=-3:0.05:3
for gamma in [0.5,1.0,2.0]
plt.plot(xs, (gamma/2) ./ (xs.^2 .+(gamma/2)^2), label=gamma )
end
plt.legend()
ローレンツ関数には、次の性質がある。
- 点 $x=0$ で 最大値 $y = \dfrac{2}{\gamma}$
- 点 $x=\pm\dfrac{\gamma}{2}$ で、最大値の半分 $y = \dfrac{1}{2}\dfrac{2}{\gamma}$
2つ目の性質を観察するため、最大値に対する比を描いてみる。
using PyPlot
xs=-3:0.05:3
for gamma in [0.5,1.0,2.0]
plt.plot(xs,
(gamma/2) ./ (xs.^2 .+(gamma/2)^2) / (2/gamma),
label=gamma )
end
plt.legend()
plt.axhline(1/2, color="k", lw=0.5)
plot
関数の文は、複数の行に渡って記述しているが、行が更に続くことを示す記法は、特に用意されていない。構文が行末で終わらなければ、次の行まで読みに行くことになっている。
パラメータ $\gamma$は、半値全幅 (Full Width of Half Maximum, FWHM)と呼ばれる。 $\gamma$を非常に小さくすると、Diracのデルタ関数 (Dirac delta function)の近似(の一つ)となる。
■ 更新演算子
変数に四則演算などを行って、元の変数に再代入する場合には、 更新演算子を用いるとよい。 演算子の直後に =
の文字が入る。
julia> x=1
1
julia> # 再代入
x=x+1
2
julia> # 更新演算子
x+=1
3
演算子 +
, -
, *
, /
, ^
に対して、 更新演算子 +=
, -=
, *=
, /=
, ^=
が用意されている。
以下の例は、変数 gamma
を 2 で繰り返し割り算する。
julia> gamma=2
2
julia> for i=1:5
global gamma
gamma /= 2
@show gamma
end
gamma = 1.0
gamma = 0.5
gamma = 0.25
gamma = 0.125
gamma = 0.0625
更新演算子 /=
を利用して、ローレンツ関数のパラメータ gamma
を変えてみる。
for
文の次の global gamma
に注目してほしい。 対話型で実行する場合、for
文の外側で定義された変数の値を変更することは、 安全のために通常禁止されている。これを可能とするのが global
文である。
using PyPlot
xs=-3:0.05:3
gamma=2
for i in 1:5
global gamma
plt.plot(xs,
(gamma/2) ./ (xs.^2 .+(gamma/2)^2) / (2/gamma),
label=gamma )
gamma /= 2
end
plt.legend()
axhline(1/2, color="k", lw=0.5)
ベクトルをスカラー倍して更新するには、更新演算子 *=
を用いる。 ベクトルにスカラーを加減して更新するには、更新演算子 .+=
または .-=
を用いる。
julia> xs = [1,2,2,1]
4-element Array{Int64,1}:
1
2
2
1
julia> xs .+=1
4-element Array{Int64,1}:
2
3
3
2
julia> xs *= 2
4-element Array{Int64,1}:
4
6
6
4
前節の三角形を描く例題で、更新演算子 .+=
を用いて、図形を繰り返し並行移動してみよう。
for
文の中で、変数 xs
と ys
を更新するので、global xs, ys
の文が必要である。
using PyPlot
plt.axes().set_aspect("equal")
xs = [1.0,2.0,2.0,1.0 ]
ys = [1.0,1.0,3.0,1.0 ]
for i=1:5
global xs, ys
plt.plot(xs,ys)
xs .+= 0.5
ys .+= 0.5
end
plt.xlim(0,6)
plt.ylim(0,6)
▲ 練習
ローレンツ関数において、パラメータ $x_0$ を変えたグラフを作成せよ。 for文を使う方法、更新演算子を使う方法の、二つで描いてみよ。
★ 今回のまとめ
- 文字列
- for文
- グラフに凡例を加える
- 冪乗関数
- ローレンツ関数
- 更新演算子