Maxima によるグラフ作成 draw2d 編

Maxima を使って,関数のグラフを描くことができます。また,数値データもグラフにすることができます。

Maxima の2次元グラフ作成は plot2d() でもできますが,ここでは,draw2d() について説明します。
draw2d() でプロットできるオブジェクトは以下のとおりです。

  • 陽関数 $y = f(x)$:
    • explicit(f(x), x, xmin, xmax)
  • 陰関数 $f(x, y) = 0$:
    • implicit(f(x, y) = 0, x, xmin, xmax, y, ymin, ymax)
  • 媒介変数表示 $x(t), y(t)$:
    • parametric(x(t), y(t), t, tmin, tmax)
  • 曲座標表示 $r(\phi)$:
    • polar(r(phi), phi, 0, 2*pi)
  • 点,$x$ 座標 $y$ 座標の数値データ:
    • points([[x1, y1], [x2, y2], ... ]) または
    • points([[x1, x1, ...], [y1, y2, ...]])
  • ベクトル,始点 $x_0, y_0$ からベクトル成分 $v_x, v_y$:
    • vector([x0, y0], [vx, vy])

また,2本の陽関数で挟まれた領域を塗りつぶすこともできます。

陽関数のグラフ

例として,$y = \sin x$ のグラフを $−2\pi \leq x \leq 2\pi$ の範囲で描きます。基本的な定数の一つである円周率 $\pi$ は Maxima では %pi と書きます。

In [1]:
draw2d(explicit(sin(x), x, -2*%pi, 2*%pi))$

いくつかオプションを設定する例。

In [2]:
/* オプションの設定例 */
draw2d(
  /* フォント設定 */
  font = "Arial", font_size = 16, 
  /* 表示範囲。描画範囲と別に指定可能。 */
  xrange = [-10, 10], yrange = [-1.1, 1.1],
  /* x 軸 y 軸の表示 */
  xaxis = true, yaxis = true, 
  /* グリッド */
  grid=true,

  /* 凡例 */
  key = "正弦関数", 
  /* 色 */
  color = red, 
  /* 線の太さ */
  line_width = 2,
  explicit(sin(x), x, -2*%pi, 2*%pi)  
)$

color

color は線や点などの色を指定します。デフォルトは blue。利用可能な色の名前は:

white            black            gray0            grey0
gray10           grey10           gray20           grey20
gray30           grey30           gray40           grey40
gray50           grey50           gray60           grey60
gray70           grey70           gray80           grey80
gray90           grey90           gray100          grey100
gray             grey             light_gray       light_grey
dark_gray        dark_grey        red              light_red
dark_red         yellow           light_yellow     dark_yellow
green            light_green      dark_green       spring_green
forest_green     sea_green        blue             light_blue
dark_blue        midnight_blue    navy             medium_blue
royalblue        skyblue          cyan             light_cyan
dark_cyan        magenta          light_magenta    dark_magenta
turquoise        light_turquoise  dark_turquoise   pink
light_pink       dark_pink        coral            light_coral
orange_red       salmon           light_salmon     dark_salmon
aquamarine       khaki            dark_khaki       goldenrod
light_goldenrod  dark_goldenrod   gold             beige
brown            orange           dark_orange      violet
dark_violet      plum             purple

色はまた "#rrggbb" のような16進コードでも指定でき,面倒な場合は以下のような数値(0~17)でも指定可能です。

In [3]:
draw2d(
  xlabel = "", ylabel = "", line_width = 4,
  xrange = [-10, 10], yrange = [-18, 1],
  makelist([color = i, 
            key = concat("color = ", i), 
            explicit(-i, x, -10, 0)], 
           i, 0, 17)
)$
system("cp ~/.maxplot.svg ./maxdraw03.svg")$

陰関数のグラフ

例として,$x^2 + y^2 = 1$ のグラフを描きます。$y$ について解いて陽関数の形にしたり,以下で述べるような媒介変数表示にしなくても,陰関数のまま,グラフに描くことができます。

In [4]:
/* ip_grid を設定しないと線がガタガタになる場合も。 */
draw2d(
  /* 滑らかにするために ip_grid を多めに */
  ip_grid = [200, 200], 
  implicit(x**2 + y**2 = 1, x, -1.2, 1.2, y, -1.2, 1.2)  
)$

縦横比・サイズの設定

縦横の比 proportional_axes = xy を設定して円らしく見えるようにします。size も変更します。弘大 JupyterHub ではグラフを svg でインライン表示させているので, user_preamblesize 600, 600 などと設定します。

In [5]:
/* オプションの設定例 */
draw2d(
  /* 滑らかにするために ip_grid を多めに */
  ip_grid = [200, 200], 
  /* 縦横比 */
  proportional_axes = xy,
  /* x 軸 y 軸の表示 */
  xaxis = true, yaxis = true, 
  /* サイズの設定 */
  user_preamble = "set term svg font \",14\" size 600,600;",
  
  line_width = 2, 
  implicit(x**2 + y**2 = 1, x, -1.2, 1.2, y, -1.2, 1.2)  
)$

媒介変数表示のグラフ

半径 $1$ の円の方程式は $x^2 +y^2 = 1$ です。この円を以下のような媒介変数表示にして描きます。

$$ x=\cos t, \quad y=\sin t \quad (0 \leq t \leq 2\pi) $$

In [6]:
/* オプションの設定例 */
draw2d(
  /* 滑らかにするために nticks を多めに */
  nticks = 200, 
  /* 縦横比。*/
  proportional_axes = xy,
  /* 表示範囲 */
  xrange = [-1.5, 1.5], yrange = [-1.1, 1.1],
  /* x 軸 y 軸の表示 */
  xaxis = true, yaxis = true, 
  
  parametric(cos(t), sin(t), t, 0, 2*%pi)
)$

点・数値データのグラフ

以下の例では,最初(左側)の数値を $x$ 座標の値,次(右側)の数値を $y$ 座標の値として 6 個の点 からなるリスト data の各点をつないだ折れ線グラフを描きます。

In [7]:
data: makelist([i, i^2], i, 0, 5);
Out[7]:
\[\tag{${\it \%o}_{13}$}\left[ \left[ 0 , 0 \right] , \left[ 1 , 1 \right] , \left[ 2 , 4 \right] , \left[ 3 , 9 \right] , \left[ 4 , 16 \right] , \left[ 5 , 25 \right] \right] \]
In [8]:
draw2d(points(data))$

以下のように,$x$ 座標のみの数値データ,$y$ 座標のみの数値データをプロットしてもよいです。

In [9]:
X: makelist(i, i, 0, 5);
Y: makelist(i**2, i, 0, 5);
Out[9]:
\[\tag{${\it \%o}_{16}$}\left[ 0 , 1 , 2 , 3 , 4 , 5 \right] \]
Out[9]:
\[\tag{${\it \%o}_{17}$}\left[ 0 , 1 , 4 , 9 , 16 , 25 \right] \]

オプションを設定して,各点を線でつないで draw する例。

ここでは,points_joined = true を設定して線でつないで描きます。オプションには, point_typepoint_sizecolor などを設定できます。

In [10]:
/* オプションの設定例 */
draw2d(
  /* 表示範囲 */
  xrange = [-0.2, 5.2], yrange = [0, 28],

  /* 点を塗りつぶした丸に */
  point_type = 7,
  /* 点の大きさ,色 */
  point_size = 1, color = purple, 
  /* 線でつなぐ */
  points_joined = true,
  /* x 座標のみのリスト, y 座標のみのリスト */
  points(X, Y)
)$

point_type

point_type には以下の種類があります。

none (-1)
dot (0)
plus (1)
multiply (2)
asterisk (3)
square (4) 
filled_square (5)
circle (6)
filled_circle (7)
up_triangle (8)
filled_up_triangle (9)
down_triangle (10) 
filled_down_triangle (11)
diamant (12)
filled_diamant (13)

ベクトルを描く

原点を始点とし,$v_x = 0.5, v_y = 1$ のベクトルを描きます。

In [11]:
/* head オプションを指定しないと変なベクトルになるかも */
draw2d(
  /* ベクトルの矢の設定 */
  head_length = 0.1, head_angle  = 20, 

  vector([0, 0], [0.5, 1])
)$

In [12]:
/* オプションの設定例 */
draw2d(
  /* 表示範囲 */
  xrange = [-2, 2], yrange = [-2, 2],
  /* 縦横比。*/
  proportional_axes = xy,
  /* x 軸 y 軸,グリッドの表示 */
  xaxis = true, yaxis = true, grid = true,

  /* ベクトルの矢の設定 */
  head_length = 0.2, head_angle  = 20, 
  /* 線の太さ */
  line_width = 2,

  vector([0, 0], [0.5, 1])
)$

複数のベクトルやベクトル場などを描く例。

In [13]:
x(t):= t$
y(t):= t-0.25*t**2$

vx(t):= 0.5$
vy(t):= 0.5-0.25*t$

vecV: 
  makelist(
    vector([x(t), y(t)], [vx(t), vy(t)]), t, 0, 4)$

for v in vecV do(print(v))$
/* 以下のように vecV は 5本のベクトルのリストになっている */
\({\it vector}\left(\left[ 0 , 0 \right] , \left[ 0.5 , 0.5 \right] \right)\)
\({\it vector}\left(\left[ 1 , 0.75 \right] , \left[ 0.5 , 0.25 \right] \right)\)
\({\it vector}\left(\left[ 2 , 1.0 \right] , \left[ 0.5 , 0.0 \right] \right)\)
\({\it vector}\left(\left[ 3 , 0.75 \right] , \left[ 0.5 , -0.25 \right] \right)\)
\({\it vector}\left(\left[ 4 , 0.0 \right] , \left[ 0.5 , -0.5 \right] \right)\)
In [14]:
draw2d(
  xrange = [-0.5, 4.5], yrange = [-0.5, 2],
  proportional_axes=xy,
  xaxis = true, yaxis = true, grid = true,
  /* y 軸の目盛を 1 ごとに */
  ytics = 1, 
  head_length = 0.1, head_angle  = 20, 
  line_width = 2,
  
  vecV
)$

さらには以下のようなベクトル場のグラフも描くことができます。参考までに。

複数のグラフを重ねて表示

複数のグラフを重ねて表示する例を示します。

$y = x^2 – 1$ と $y = 4 x – 5$ の 2つの陽関数のグラフを重ねて描きます。

In [15]:
draw2d(
  explicit(x**2 - 1, x, -5, 5),
  explicit(4*x - 5, x, -5, 5)
)$

plot2d() の場合と違い,自動で色を変えてはくれません。いくつかオプションを設定して描く例です。それぞれの関数を explicit() で描く直前に,それぞれのオプションを指定します。

In [16]:
/* オプションの設定例 */
draw2d(
  /* 表示範囲 */
  xrange = [-5, 5], yrange = [-5, 10],
  xaxis = true, yaxis = true, 
  /* 凡例の位置 */
  user_preamble = "set key bottom",

  color = 1,
  line_width = 3,
  key = "x^2 - 1",
  explicit(x**2 - 1, x, -5, 5),
  
  color = 2,
  line_width = 1,
  key = "4 x - 5",
  explicit(4*x - 5, x, 1, 3)
  /* x の範囲も別個に設定可能 */
)$

数値データファイルを読み込む

Maxima では,あらかじめ作成された数値データファイルを読み込んでグラフを描くこともできます。

In [17]:
/* 読み込むデータファイルを作成しておく */
tmp: makelist([i, i^2], i, 0, 5)$
write_data(tmp, "data.txt")$

データファイルを読み込む Maxima の関数は,read_nested_list を使います。

In [18]:
dat: read_nested_list("data.txt");
Out[18]:
\[\tag{${\it \%o}_{38}$}\left[ \left[ 0 , 0 \right] , \left[ 1 , 1 \right] , \left[ 2 , 4 \right] , \left[ 3 , 9 \right] , \left[ 4 , 16 \right] , \left[ 5 , 25 \right] \right] \]

リスト dat に読み込んだ数値データをグラフにします。

In [19]:
/* オプションの設定例 */
draw2d(
  /* 表示範囲 */
  xrange = [0, 6], yrange = [0, 28],
  user_preamble = "set key top left", 
  
  point_type = 7, 
  point_size = 1,
  key = "データ",
  points(dat)
)$

数値データと理論曲線を重ねて表示

前節の数値データファイル test.dat と理論曲線 $y = x^2$ の 2 つのグラフを重ねて表示してみます。

In [20]:
draw2d(
  user_preamble = "set key top left",
 
  /* 数値データを点で */
  point_type = 7, 
  point_size = 1,
  color = 1, 
  key = "データ",
  points(dat), 

  /* 曲線を陽関数で */
  color = 2,
  key = "理論曲線 y = x^2", 
  explicit(x**2, x, 0, 5)
)$

海王星と冥王星の軌道

焦点を原点とした楕円のグラフ

太陽からの万有引力を受けて運動する惑星は,太陽(二体問題では質量中心)を焦点の一つとした楕円運動を描いて運動します。
焦点の一つを原点とし,長半径 $a$,離心率 $e$ の楕円の方程式は,極座標 $r$,$\varphi$ を使って以下のように表すことができます。

$$ r= \frac{a (1−e^2)}{ 1 + e\cos\varphi}$$

さて,かつては第9惑星,現在では準惑星の一つである冥王星も楕円軌道を描きます。冥王星の軌道長半径 $𝑎_P=39.445 \mbox{au}$,離心率 $𝑒_P=0.250$
を使って冥王星の軌道を描きます。

まず,極座標表示の楕円の式を関数として定義します。

In [21]:
r(a, e, phi):= a*(1-e^2)/(1+e*cos(phi));
x(a, e, phi):= r(a, e, phi)*cos(phi);
y(a, e, phi):= r(a, e, phi)*sin(phi);
Out[21]:
\[\tag{${\it \%o}_{43}$}r\left(a , e , \varphi\right):=\frac{a\,\left(1-e^2\right)}{1+e\,\cos \varphi}\]
Out[21]:
\[\tag{${\it \%o}_{44}$}x\left(a , e , \varphi\right):=r\left(a , e , \varphi\right)\,\cos \varphi\]
Out[21]:
\[\tag{${\it \%o}_{45}$}y\left(a , e , \varphi\right):=r\left(a , e , \varphi\right)\,\sin \varphi\]

媒介変数表示でプロット

冥王星の軌道長半径と離心率を入れて,媒介変数表示でプロットしてみます。

In [22]:
aP: 39.445$
eP: 0.250$
In [23]:
draw2d(
  /* 滑らかにするためにサンプリングを多めに */
  nticks = 200, 
  /* 縦横比。*/
  proportional_axes = xy,
  /* 表示範囲 */
  xrange = [-50, 50], yrange = [-50, 50],
  /* x 軸 y 軸の表示 */
  xaxis = true, yaxis = true, 

  key = "冥王星",
  parametric(x(aP, eP, phi), y(aP, eP, phi), phi, 0, 2*%pi)
)$

では,この冥王星の軌道と,その内側をまわる海王星の軌道を重ねて描いてみましょう。

海王星の軌道長半径は $a_N=30.181 \mbox{au}$,離心率は $e_N=0.0097$ と小さいので簡単のために $e_N=0$ として扱います。

実際の2つの天体の軌道は同じ平面上にありませんが,太陽からの距離のみをみるために,ここでは同一平面上に描きます。

In [24]:
aN: 30.181$
eN: 0$
In [25]:
draw2d(
  /* 滑らかにするためにサンプリングを多めに */
  nticks = 200, 
  /* 縦横比。*/
  proportional_axes = xy,
  /* 表示範囲 */
  xrange = [-50, 50], yrange = [-50, 50],
  /* x 軸 y 軸の表示 */
  xaxis = true, yaxis = true, 

  key = "冥王星",
  color = blue,
  parametric(x(aP, eP, phi), y(aP, eP, phi), phi, 0, 2*%pi), 
  
  key = "海王星",
  color = red,
  parametric(x(aN, eN, phi), y(aN, eN, phi), phi, 0, 2*%pi)
)$

参考:極座標表示でプロット

極座標表示でプロットする例。

In [26]:
draw2d(
  nticks = 200, 
  proportional_axes = xy,
  xrange = [-60, 60], yrange = [-40, 40],
  xaxis = true, yaxis = true, 

  color = 1, key = "冥王星", 
  polar(r(aP, eP, phi), phi, 0, 2*%pi), 
  color = 2, key = "海王星",
  polar(r(aN, eN, phi), phi, 0, 2*%pi)
)$

月別平年気温の関数フィット

弘前市の月別平年気温のデータを使ってリスト HiroT を作ります。

In [27]:
HiroT: [
[1, -1.5],
[2, -1.0],
[3, 2.3],
[4, 8.6],
[5, 14.3],
[6, 18.3],
[7, 22.3],
[8, 23.5],
[9, 19.4],
[10, 12.9],
[11, 6.5],
[12, 0.8]
];
Out[27]:
\[\tag{${\it \%o}_{56}$}\left[ \left[ 1 , -1.5 \right] , \left[ 2 , -1.0 \right] , \left[ 3 , 2.3 \right] , \left[ 4 , 8.6 \right] , \left[ 5 , 14.3 \right] , \left[ 6 , 18.3 \right] , \left[ 7 , 22.3 \right] , \left[ 8 , 23.5 \right] , \left[ 9 , 19.4 \right] , \left[ 10 , 12.9 \right] , \left[ 11 , 6.5 \right] , \left[ 12 , 0.8 \right] \right] \]

このデータをグラフに描いてみます。

In [28]:
draw2d(
  point_type = 7, point_size = 1,
  points(HiroT)
)$

グラフを見ると,月別平年気温は 12 ヶ月周期の三角関数でフィットできるようにみえます。

では,以下のように関数フィットをしてみましょう。

まず,最小二乗法のパッケージ lsquares をロードします.これは lsquares_estimates を 初めて使う際,最初に 1 回だけ行えばよいです。

In [29]:
load(lsquares)$

次に,以下のような関数を定義して,最小二乗法でパラメータ a, b, c を求めます。

$$f(x) = a + b \sin\left(\frac{2\pi}{12}\right)+ c \cos\left(\frac{2\pi}{12}\right)$$

In [30]:
f(x):= a + b*sin(%pi*x/6)+ c*cos(%pi*x/6);
Out[30]:
\[\tag{${\it \%o}_{60}$}f\left(x\right):=a+b\,\sin \left(\frac{\pi\,x}{6}\right)+c\,\cos \left(\frac{\pi\,x}{6}\right)\]

最小二乗法を行う関数 lsquares_estimates には数値データを行列として入れてやる必要があります。

このために apply('matrix, HiroT) でリスト HiroT を行列に変換しています。

In [31]:
/* 以後の少数表示は 5 桁くらいで... */
fpprintprec: 5$
/* 元に戻すには fpprintprec: 0$ */

lsquares_estimates(
  apply('matrix, HiroT), [x, y], y=f(x), [a, b, c]
)$
float(%);
Out[31]:
\[\tag{${\it \%o}_{63}$}\left[ \left[ a=10.533 , b=-8.3403 , c=-9.1611 \right] \right] \]

最小二乗法によって求めた a, b, c の値を f(x) に代入して fit とし,数値データと合わせて,この関数のグラフも描きます。

In [32]:
fit: ev(f(x), %);
Out[32]:
\[\tag{${\it \%o}_{64}$}-8.3403\,\sin \left(\frac{\pi\,x}{6}\right)-9.1611\,\cos \left(\frac{\pi\,x}{6}\right)+10.533\]
In [33]:
draw2d(
  xrange = [0.8, 12.2], yrange = [-5, 28],
  xaxis = true, yaxis = true, 
  user_preamble = "set xtics 1", 
  xlabel = "月", 
  ylabel = "°C",
  title = "弘前市の月別平年気温",

  color = 1, key = "月別平年気温",
  point_type = 7, point_size = 0.6,
  points(HiroT), 
  
  color = 2, key = "関数フィット", 
  explicit(fit, x, 1, 12)
)$

領域の塗りつぶし

$y = f(x)$ と $y = g(x)$ ($f(x) \geq g(x)$)で囲まれた領域を塗りつぶす例。

In [34]:
f(x):= 0.6*x + 0.4*cos(x)$
g(x):= 0$

draw2d(
  xrange = [-0, 2.5], yrange = [-0.2,1.5],
  xaxis = true,
  /* 塗りつぶす色の指定。*/
  fill_color = yellow, 
  
  /* 上の線。*/
  filled_func = f(x), 
  
  /* 下の線と範囲の指定。*/
  explicit(g(x), x, 0.5, 2), 
  
  /* 塗り潰し終了 */
  filled_func = false, 
  
  /* あらためて y = f(x) を描く */
  color = blue, 
  line_width = 2, 
  explicit(f(x), x, 0.25, 2.25)
)$