MePoTeXによる図形グラフの作成

in [TeXの部屋]

MePoTeXを利用した図形やグラフの作成手順を取りまとめました。

MePoTeXを活用して,図形とグラフを究めよう!

(注1) MathJaxを使用しているので、 スマホでは表示に時間がかかることがあります。
(注2) 図やコードが文章に被って表示されるときは「再読み込み」して下さい。
(注3)モバイル利用(Android)でのメニュー選択は、 SiteMapを利用するか、 「長押し」から「新しいタブを開く」を選択してください。
■MePoTeXによる図形やグラフの作成法  [Map]


[御案内] TeXを利用して数学プリントを作成するとき, いろいろな図形やグラフを作成する必要があります. それを作成するアプリはTeXのシステムにすでに含まれています. 「MetaPost」です.さらに,それをTeXソースの中で利用できるようにした パッケージが「MePoTeX」(概要)です.詳細なマニュアルもあるのですが, TeXを使い慣れていない場合は全体像を把握しにくいかもしれません.
 そこで,ここでは,TeXを使い始めた方を念頭に, MePoTeXを用いた図形やグラフの作成方法について解説します. ただし,TeXのインストールはすでになされており, TeXによる通常文書は作成できるレベルにあることを前提とします. emathと類似したコマンドで 曲面の描画まで行うことができ、 図形をGhostscriptを経由しないEPSファイル(MPS)で保存することができます。

  • 「emath」+「MePoTeX」があれば、 数学教材の作成には十分ではないかとさえ思えます。
  • 下記解説の詳細は、 MePoTeXやMetaPostのマニュアルを 参照してください。
  • MePoTeXの作者「みなも」氏には、 多大の敬意を表します。ver1.00は2000年に発表され、 最新版は2022年1月のver4.50です。 MePoTeXが広く利用されるようになることを祈念します。


■いろいろな応用操作

(注) Web上での表示の都合上、 空白は全角を使用しています。 以下のコードをコピーして実行するときは、 半角の空白かtabで置き換えて実行してください。


複素数の計算
MetaPostでpair宣言された2次元ベクトルは、 平面上の点の座標やベクトルの成分を表すだけではなく、 複素数として扱うこともできます。 初字「z」から始まる変数は、 pair宣言をしなくても そのような変数として扱うことができます。

たとえば、z1=(a,b)、z2=(c,d) とするとき、 和は z3=z1+2 により求められます。 積を z4 とすると、積は「z4=z1 zscaled z2」により計算されます。 商は、MetaPostは連立1次方程式を 解くことができることを利用します。 z5=z2/z1 とすると、z5は「z2=z5 zscaled z1」により定まります。 MetaPostは、 この式から定まる成分の連立1次方程式を 自動的に解いて z5 を求めます。

以下は、\(\small z1=3+i,~z2=2+3i\) の場合を計算しています。 \(\small z3=z1+z2=5+4i\)、\(\small z4=z1 z2=3+11i\)、 \(\small z5=\frac{z2}{z1}=\frac9{10}+\frac7{10} i\) です。

  • \begin{MPpic}<1cm>(5,4) \sendMP{ % [A]数値変数と座標 numeric naga[],kaku[]; z1=(3w,h);z2=(2w,3h); z0=origin;z3=z1+z2; z4/w=z1/w zscaled z2/w; z2/w=z5/w zscaled z1/w; % [B]平行四辺形の描画 xdraw() z0--z1--z3   --z2--cycle; xdraw(hasen()) z0--z3; xdraw(1pt,red)   z0--z4/abs(z4)*w; xdraw(1pt,blue)   z0--z5/abs(z5)*w; % [C]対角線の長さ naga1=abs(z1/w);  (以下、略) % [D]角度 kaku1=angle(z1);  (以下、略) % [E]座標と数値の保存 SavePointName   (z0,z1,z2,z3,z4,z5); SaveNumeric   (naga1,naga2,naga3,    naga4,naga5); SaveNumeric   (kaku1,kaku2,kaku3,    kaku4,kaku5);} % [F]座標と値の表示 \mptLabel{z0}[tr]<0mm,-2mm>   {z0\UseNumeric{z0}} \mptLabel{z1}[bl]<1mm,-3mm>   {z1\UseNumeric{z1}} \mptLabel{z2}[tl]<-5mm,5mm>   {z2\UseNumeric{z2}} \mptLabel{z3}[tl]<0mm,2mm>   {z3\UseNumeric{z3}}  (以下、略) \end{MPpic}
[A]では、最初に長さと角度(度)を納める変数を宣言して、 z1, z2を単位付きで定義しています。 そのあとで、和 z3 を計算し、積 z4 と商 z5 は 単位「w」を省いた式で定義しています。 ここでは、w=h=1cm です。「1cm」といっても、 実際には「cm」は変数であり、1cm=28.34645bp であるようです。 MetaPostでの長さの単位は「bp」(ビッグポイント)が用いられているので、 単位付きの計算は、 実際には28倍した値で計算されています。

たとえば、単位をつけたz2の長さは、 \(\small \sqrt{2^2+3^2}=\sqrt{13}\) ではなく、 \(\small \sqrt{(2\cdot 28.3\cdots)^2+(3\cdot 28.3\cdots)^2}\)(bp) が計算され、場合によってはオーバーフローになります。 このような値は単位を省いて計算する必要があります。 単位は、描画の直前につけるように留意する必要があります。 z4とz5には単位「w」をつけていないので、 [B]では、描画するときに「w」をつけています。 また、積や商を原点z0と結ぶ線は、 そのまま描画すると長くなりすぎるので単位ベクトルにして繋いでいます。

[C]では長さを求めています。z1,z2,z3 は単位付き、z4, z5は単位無しなので 注意してください。 z1の長さは、 w で割って単位を省いて計算しています。 [D]では「angle」により角度が「度」で求まります。 [E]で求めた座標や数値を保存し、[F]で「\UseNumeric」を利用して値を表示 しています。表示された数値を見ると、 \(\small |zw|=|z| |w|\), \(\small \arg(zw)=\arg(z)+\arg(w)\) など、 複素数の性質が満たされていることが分かります。 なお、値を表示する箇所では、開始位置が揃うように微妙な調整をしています。

▲戻る(トップメニューマップ)

picture値変数
MetaPostで扱うことのできる変数に 「picture」で宣言される変数があり、画像を変数に格納することができます。 「xdraw」や 「xfill」は、 MetaPostのもともとの機能である「draw」や「fill」を、 いろいろなオプションを簡単に追加できるように 「みなも」氏によりマクロ化されたものです。 それによりいろいろな図形が描かれますが、 それは「currentpicture」というデフォルトで定まっているpicture値変数に 書き込まれています。しかし、MetaPostの機能では、 任意のpicture値変数に書き込むことはできません。 MePoTeXでは、任意のpicture値変数に書き込むことができるように 機能が拡張されています。picture値変数を「pct」とするとき、 「drawpic(pct) z1--z2;」「xfillpic(pct)(red) z1--z2--z3--cycle;」 などのように利用します。( )内のオプションは、xdraw( )、xfill( ) の場合と同じものが利用できます。

picture値変数を宣言するには、\sendMP内で「newpic(pct);」とします。 これにより、「picture pct;」という変数宣言と、 「pct:=nullpicture;」という初期化が行われます。 単に変数宣言だけでは書き込むことはできず初期化する必要があるので、 「newpic(pct);」の形で利用するのがよいでしょう。 複数のpicture値変数を用いたいときは、 「newpic(pct)("1upto3");」あるいは「newpic(pct)("1,2,3");」 のように宣言します。これにより、pct1, pct2, pct3の宣言と 初期化が行われます。

以下に、簡単な利用例を示します。
  • \begin{MPpic}<1cm>(4,4) \sendMP{ % 変数宣言 path pth[]; newpic(pct)("1,2,3"); % パス値の設定 pth1=(0,0)--(w,0)--(w,h)   --(0,h)--cycle; pth2=(w,0)--(2w,0)--(2w,h)   --(w,h)--cycle; pth3=(0,h)--(2w,h)--(2w,2h)   --(0,2h)--cycle; % pth1を描画  drawpic(pct1) pth1;  draw pct1; % pth2を描画  xfillpic(pct2)(red) pth2;  draw pct2; % pth3を描画  xfilldrawpic(pct3)  (4pt*dir45)(blue,2pt) pth3;  draw pct3;} \end{MPpic}
最初に点を繋いだパス値を定義します。 pth1は左下の正方形、pth2はその隣の右下の正方形、 そしてpth3は上にある長方形です。 塗りつぶしを行うには「--cycle;」で閉じる必要があります。 次に、宣言したpicture変数に書き込みます。 pct1にはpth1を描画、pct2にはpth2を赤色で塗りつぶして描画、 そしてpct3には斜線塗りと外枠を青色にして描画しています。 picture値変数に書き込んだだけでは実際には表示されません。 描画したものを見えるように表示するには「draw pct1;」などとします。

▲戻る(トップメニューマップ)

線形代数
線形代数で学ぶ線形変換はベクトルに行列をかけることで得られる変換です。 授業で扱うときは、 平面上の正方格子模様が どのように変換されるかを示したいところですが、 単純ではあっても、その図を作成するのは面倒です。 しかし、MetaPostではアフィン変換の 成分を表す変数があります。 その変数を利用すると、正方格子の変形を簡単に行うことができます。 以下では、正方格子がどのように変換されるかを、 \[\small \begin{pmatrix}x'\\ y'\end{pmatrix} =\begin{pmatrix}2&1\\ 1&1\end{pmatrix} \begin{pmatrix}x\\ y\end{pmatrix}\] の場合について例示します。
  • \begin{MPpic}<0.7cm>(4|8,6|4) % [A] 正方格子 \mptDrawGrid  [linetype=dashed hasen(),   xmin=-3w,xmax=3w,   ymin=-3h,ymax=3h]  {-3w step w until 3w}  {-3h step h until 3h} \sendMP{ % [B]変数宣言  path pth[];  transform t; % [C]picture値変数の初期化  newpic(pct); % [D]transform値の定義  (2,1)=(1,0) transformed t;  (1,1)=(0,1) transformed t;  (0,0)=(0,0) transformed t; % [E]正方格子を変換する  drawpic(pct) currentpicture    transformed t; % [F]正方形のパスを指定  pth0=(0,0)--(w,0)--(w,h)    --(0,h)--cycle; % [G]正方形(黒)を変換して %   赤色で描画  pth1=pth0 transformed t;  xdraw(1pt) pth0;  xdraw(1pt,red) pth1; % [H]変換後の格子を描画  draw pct;} \end{MPpic}
MPpic環境を開くときの範囲は、\(\small -8\leqq x\leqq 4,~-4\leqq y\leqq 6\) に設定しました。例示した変換では格子模様が右斜め方向に 大きく伸びるので、その図形全体が表示されるように調整したためです。

[A]では、\(\small -3\leqq x\leqq 3\)、\(\small -3\leqq y\leqq 3\) の範囲で格子を描画しています。 MPpic環境で指定した領域内の一部に格子を描画するときは、 xmin, xmax などを指定する必要があります。 この段階で正方格子が描画され、「currentpicture」という デフォルトのpicture値変数に格納されます。 [B]ではパス値とtransform値の宣言をして、 [C]でpicture変数の宣言と初期化をおこなっています。 [D]では、tarnsform値「t」の定義を行い、 [E]では、[A]で正方格子が描画されたcurrentpictureを [C]で定めたtransform値で変換して、 [B]で宣言したpicture値変数「pct」に納めています。 [F]では1辺が1cmの正方形をパス値変数「pth0」に格納します。 以上のもとで、[G]では、正方形pth0と、それを変換した図形pth1を描画します。 そして、最後に[H]では、 [A]での正方格子を変換した[E]のpctを描画しています。

[D]の部分を変更するだけで、いろいろな行列で試してみることができます。


▲戻る(トップメニューマップ)

微分方程式
勾配場
1階の微分方程式が \(\small y'=\dfrac{g(x,y)}{f(x,y)}\) の形で表されていると、 その解が分からなくても 指定した点 \(\small (x,y)\) を通る解曲線の接線の傾きは右辺を 計算すれば簡単に分かります。そこで、平面上の各点で右辺の値を求めて 対応する接線を短い線分で描けば、解が分からなくても解曲線の大まかな様子を 知ることができます。そのような図は勾配場と呼ばれます。 MePoTeXには、この勾配場を描くマクロとして「drawVectorField」があります。 6つの引数を持ち、 「drawVectorField(1)(2)(3,4,5,6)」の形で使用します。 線分ではなく矢印を置くこともできます。 それぞれの引数は、次のような内容です。
  1. 線分を置く座標を指定します。
  2. 勾配場の式で \(\small (f(x,y), g(x,y))\) を、 変数を \(\small s, t\) を用いて指定します。 分母の式が最初にきます。
  3. 配置する線分の始点を「0」、終点を「1」としたとき、 「1」の座標に線分のどの部分を置くかを 0〜1 の値で指定します。
  4. 長さ1のベクトルを配置するときの実寸を、w や h を用いて指定します。
  5. 線分の最大長を指定します。
  6. 矢印を描画する場合に、矢尻の長さを「4pt」のように 指定します。線分だけでよいときは、「0」を指定します。
ただし、このコマンドでは(1)の点にしか線分が描画されません。 指定した領域全体で描画するには、 繰返し処理を行う「for--endfor」を 利用することになります。 下記は、円 \(\small x^2+y^2=a^2\) の満たす微分方程式です。 具体的には、 \(\small x+yy'=0\) つまり \(\small y'=-x/y\) です。 この場合は、(2)は「\(\small (t, -s)\) 」と指定することになります。 分母が最初にくることに注意してください。 ステップ幅を 0.5w にすると原点で分母が0になるので、 ちょっとずらして 0.499w にしています。
  • \begin{MPpic}<1cm>(4|4,4|4) \sendMP{  for x=-4w step 0.499w   until 4w:   for y=-4h step 0.499h    until 4h:  drawVectorField((x,y))   (-t,s)   (0.2w, 0.5, 0.4w, 0);   endfor;  endfor;} \end{MPpic}
以下に、幾つかの典型例を示します。 \(\small (-t,s)\) の部分を変更するだけです。
  • \(\small y+xy'=0\) を \(\small (-s, t)\) した場合。
  • \(\small y'+y=x\) を \(\small (1,s-t)\) した場合。
  • \(\small y'=\dfrac{xy}{x^2+y^2}\) を \(\small (s*s+t*t,s*t)\) した場合。

▲戻る(トップメニューマップ)

ベクトル場
\(\small x, y\) が媒介変数 \(\small u\) を用いて 連立微分方程式で \[\small \begin{align*}&\frac{dx}{du}=f(x,y)\\ & \frac{dy}{du}=g(x,y)\end{align*}\] と表されていると、解が分からなくても 点 \(\small (x,y)\) における接線ベクトルが定まり、 媒介変数 \(\small u\) の増加する方向に矢印がつきます。 このように、点の進む方向に矢印をつけた図はベクトル場と呼ばれます。 MetaPostでは独立変数として \(\small s, t\) が使用されるので、 ここでは媒介変数を \(\small u\) としています。 このとき、解曲線の接線の傾きは \[\small \frac{dy}{dx}=\dfrac{dy/du}{dx/du}=\dfrac{g(x,y)}{f(x,y)}\] により求められるので、 この場合も「drawVetorField」を利用することができます。

また、定数係数斉次2階微分方程式 \(\small y''+py'+qy=0\) の場合は、 \(\small y'=z\) とおくと、\(\small y''=z'=-pz-qy\) となるので、\(\small x\) を媒介変数とした連立微分方程式 \[\small \frac{dy}{dx}=z,~\frac{dz}{dx}=-qy-pz\] となり、変数を置き換えると \[\small \frac{dx}{du}=y,~\frac{dy}{du}=-qx-py\] と同じことです。


以下に、2階微分方程式の場合に幾つかの例を示します。 この場合は接線ベクトルで矢印がつくので、 6番目の引数を「4pt」にしています。 ただし、\(\small (y, y')\) に関する場が描画されており、 解曲線自体の接線方向ではないので注意が必要です。 このような平面は「相平面」と呼ばれています。
  • \(\small y''+y=0\) の場合は \(\small (t,-s)\) と指定。
  • \(\small y''-y=0\) の場合は \(\small (t,s)\) と指定。
  • \(\small y''-2y'+y=0\) の場合は \(\small (t,2t-s)\) と指定。

▲戻る(トップメニューマップ)

定数係数連立線形微分方程式
周知のように、連立微分方程式が \[\small \frac{d}{du}\begin{pmatrix}x\\ y\end{pmatrix} =\begin{pmatrix}a& b\\ c& d\end{pmatrix} \begin{pmatrix}x\\ y\end{pmatrix}\] の形で表される場合、解の様相は係数行列の固有値の取り方により 分類されます。 以下に幾つかの例を示します。 この場合は、解曲線の接線方向の矢印になります。
  • \(\small (5s+3t,3s+5t)\) の場合は、2つの正の固有値 \(\small 2, 1/2\) を持つ。
  • \(\small (s+2t,2s-2t)\) の場合は、正と負の固有値 \(\small 2, -3\) を持つ。
  • \(\small (-2s+t,-s)\) の場合は、負の2重解 \(\small -1\) を固有値に持つ。
  • \(\small (3s-2t,4s-t)\) の場合は、虚数解の固有値 \(\small 1\pm 2i\) を持つ。
  • \(\small (s-t,2s-t)\) の場合は、純虚数の固有値 \(\small \pm i\) を持つ。

▲戻る(トップメニューマップ)

解曲線
■勾配場と解曲線
微分方程式の解曲線は、 その解を解析的に求めてグラフ表示すれば描くことができます。 たとえば、ロジスティック方程式 \(\small y'=y(1-y),~y(0)=0.5\) の解は \(\small y=\dfrac{e^{x}}{1+x^{x}}\) で表されますが、 勾配場と重ねて描くと次のようになります。 下記では、\(\small y\) 軸方向を3倍して描画しています。
  • \begin{MPpic}<1cm,3cm>   (4|4,1.5|0.5) \mptXaxis[l]<1mm,0mm>{$x$} \mptYaxis[b]<0mm,1mm>{$y$} \sendMP{  for x=-4w step 0.5w   until 4.1w:   for y=-0.5h step 0.2h   until 1.5h:    drawVectorField((x,y))    (1,t*(1-t))    (0.2w, 0.5, 0.4w, 0);   endfor;  endfor;} % 解曲線の描画 \sendMP{  xdraw() kansu  (exp(t)/(1+exp(t)))   (-4,4,40);} \end{MPpic}
下記は、\(\small y''-2y'+y=0\) について \(\small (y,y')\) に関する相平面と、\(\small y(0)=0, y'(0)=1\) を満たす解の軌道です。 一般解は \(\small y=(a+bx)e^{x}\) なので、 与えられた初期条件を満たす特殊解は \(\small y=xe^{x}\) です。 \(\small y'=(1+x)e^{x}\) であるので、相平面では \(\small (xe^x, (1+x)e^x)\) の軌道が描かれます。 媒介変数の場合の「kansuP」を利用して描いています。
  • \begin{MPpic}<1cm>(2|2,3|1) \mptNumSys{double} \mptXaxis[l]<1mm,0mm>{$x$} \mptYaxis[b]<0mm,1mm>{$y$} \sendMP{  for x=-4w step 0.5w   until 4.1w:   for y=-4h step 0.5h    until 4.1h:    drawVectorField((x,y))    (t,2t-s)    (0.2w, 0.5, 0.4w, 4pt);   endfor;  endfor;} % (y,y')の描画 \sendMP{ xdraw(1pt) ClipPATH( kansuP(t*exp(t), exp(t)+t*exp(t)) (-2,2,20));} \end{MPpic}
ここで、冒頭にある「\mptNumSys{double}」というコマンドは、 倍精度で計算することを指定しています。 MetaPostの「numeric」で宣言される数は、 デフォルトでは4096未満で、1/65536 の整数倍で表される数です。 デフォルトのままで大きな数を計算させると あっという間にオーバーフローしてしまうので、 数が大きくなりそうなときは「\mptNumSys{double}」を指定して、 倍精度で計算するようにしておく必要があります。 ここでは指数関数が出てくるので倍精度にしています。

▲戻る(トップメニューマップ)

数値解法(1階・2階微分方程式)
微分方程式の解を解析的に求めることが難しい場合は、 解を近似的に数値解で求めることになります。 そのような方法としては、 オイラー法やルンゲ・クッタ法がよく知られています [参照]。 MePoTeXのVer4.50では、1階・2階の場合の微分方程式を ルンゲ・クッタ法で解くマクロが新設されました。
■ 1階微分方程式
1階は \(\small \dfrac{du}{dt}=F(u,t)\) の場合を考えます。 書式は、次の通りです。

rungekutta(F(u,t))(始点, 終点, 刻み幅)(初期値)

始点、終点、刻み幅には、それぞれ \(\small t\) の値をいれます。 始点を与える \(\small t\) での値が初期値です。 これにより、解曲線のパスが得られます。 たとえば、勾配場で例示した ロジスティック曲線のパスは、

\(\small t\ge 0\)  rungekutta(u*(1-u))(0, 4, 0.2)(0.5)
\(\small t\le 0\)  rungekutta(u*(1-u))(0, -4, -0.2)(0.5)

により得られます。 刻み幅が正の値のときは始点から初めて \(\small t\) の値が増加する方向、 刻み幅が負の値のときは始点から初めて \(\small t\) の値が減少する方向の パスが得られるので、 それを xdraw() を利用して描画することになります。 当然ながら、例示したグラフと同じグラフが得られます。 このコマンドを利用すると、微分方程式の右辺の式と初期値を 与えるだけで解曲線を描画できますが、 初期値の与え方によっては、 右側と左側を別々に指定する必要があります。
  • \begin{MPpic}<1cm,3cm>  (4|4,1.5|0.5)  \mptXaxis[l]<1mm,0mm>{$x$}  \mptYaxis[b]<0mm,1mm>{$y$} %勾配場の描画  (中略) % 解曲線の描画 \sendMP{  xdraw(0.8pt)   rungekutta(u*(1-u))    (0, 4, 0.2)(0.5);  xdraw(0.8pt)   rungekutta(u*(1-u))    (0, -4, -0.2)(0.5);} \end{MPpic}
■ 2階微分方程式
2階は \(\small \dfrac{d^2u}{dt^2}=G(u,u',t)\) の場合を考えます。 ただし、\(\small u'\) のままMetapostに引き渡すことができないので、 \(\small v\) におきかえて利用します。 書式は、次の通りです。

rungekutta(G(u,v,t))(始点, 終点, 刻み幅)(初期値)

始点、終点、刻み幅には、それぞれ \(\small t\) の値をいれます。 始点を与える \(\small t\) での値が初期値です。 ただし、2階なので、始点を \(\small t_0\) とすると \(\small u(t_0), u'(t_0)\) の値を与えることになります。 たとえば、勾配場で例示した 2階微分方程式は \(\small y''=2y'-y\) であり、 初期値を \(\small y(0)=0, y'(0)=1\) とすると、

\(\small t\ge 0\) rungekutta(2*v-u)(0, 2, 0.2)(0, 1)
\(\small t\le 0\) rungekutta(2*v-u)(0, -4, -0.2)(0, 1)

となります。これにより、始点から終点までの部分のパスが得られるので、 それを xdraw() を利用して描画することになります。 ここでは、相平面での軌道ではなく解曲線が描かれます。
  • \begin{MPpic}<1cm>(2|4,4|1) \mptNumSys{double} \mptXaxis[l]<1mm,0mm>{$x$} \mptYaxis[b]<0mm,1mm>{$y$} % 解曲線の描画 \sendMP{  xdraw(0.8pt) ClipPATH(   rungekutta(2*v-u)    (0, 2, 0.2)(0, 1));  xdraw(0.8pt) ClipPATH(   rungekutta(2*v-u)    (0, -4, -0.2)(0, 1));} \end{MPpic}

▲戻る(トップメニューマップ)

数値解法(n質点系)
MePoTeXには、\(\small n\)質点系の運動方程式を ルンゲ・クッタ法で解くマクロ「RungeKutta」もあります。 ここでは、このマクロの利用法を解説します。
■ n 質点系の運動方程式 [参照]
n 質点系の運動方程式は、 \(\small n\) 個の質点の質量を \(\small m_i\)、 位置ベクトルを \(\small \mathbf{q}_i\) とするとき、\(\small i\) 番目の質量に働く外力を \(\small \mathbf{F}_i\)、 他の質点から作用する力の和を \(\small \sum_{k\neq i}\mathbf{G}_{ki}\) と すると、\(\small i=1,2,\ldots,n\) とするとき、次の式で表されます。 \[\small m_i\dfrac{d^2\mathbf{q}_i}{dt^2}(t) =\mathbf{F}_i(t)+\sum_{k\neq i}\mathbf{G}_{ki}(t)\] この式は、\(\small \dfrac{d\mathbf{q}_i}{dt}=\mathbf{p}_i\) とおくと、 次のような連立微分方程式で表されます。 \[\small \begin{align*} &\dfrac{d\mathbf{q}_i}{dt}=\mathbf{p}_i\\ &m_i\dfrac{d\mathbf{p}_i}{dt}=\mathbf{F}_i(t)+\sum_{k\neq i}\mathbf{G}_{ki}(t) \end{align*}\] MePoTeXのマクロ「RungeKutta」では、これを一般化して、 \[\small \begin{align*} &\dfrac{d\mathbf{q}_i}{dt}=\mathbf{p}_i\\ &\dfrac{d\mathbf{p}_i}{dt}=f_i(\mathbf{q}_1,\mathbf{q}_2,\ldots, \mathbf{p}_1,\mathbf{p}_2,\ldots,t) \end{align*}\] の形の場合の数値解を求めることができます。次の形で利用します。 \[\small {\rm RungeKutta}(1)(2,3,4)(5)(6)(7)\] それぞれの引数は、次のような内容です。
  1. \(\small \dfrac{d\mathbf{p}_i}{dt}\)の右辺の式を、 q1,q2,・・・,p1,p2,・・・,t の式で記述します。 式の組が複数あるときは、「,」で区切って記述します。 q1,q2,・・・,p1,p2,・・・は、数値(numeric)かペア(pair)型の変数です。 1階連立微分方程式の場合は、 ローレンツアトラクターでの解法のように $\small \mathbf{p}_i$ のみを用いることになります。
  2. 運動の開始時刻。
  3. 運動の終了時刻。
  4. 差分近似して求めるので、その時間間隔。
  5. 数値かペア型変数 q1,q2,・・・の初期値の列。「,」で区切って入力する。
  6. 数値かペア型変数 p1,p2,・・・の初速度の列。「,」で区切って入力する。
  7. 結果を格納するパス値変数名。たとえば「pth」とすると、 q1,q2,・・・の軌跡が pth1, pth2,・・・に、p1, p2, ・・・の軌跡が pth[-1], pth[-2], ・・・に格納されます。

▲戻る(トップメニューマップ)

■ 1質点系の運動
ここでは、MePoTeXのマニュアル[1] (p70, 図122)で取り上げられている1質点系の運動の例を紹介します。 これは、距離が \(\small 2L\) だけ離れた2つの梁に、 同じバネ定数 \(\small k\) を持ち自然長が \(\small L_0\) のバネの1端を 固定します。そして、もう一方のバネの1端を1つの質点と繋ぎます。 そして、それを特定方向に引っ張ったときの質点の描く軌跡を 求めるものです。

完全な物理の問題ですが、 質点Pの位置ベクトルを \(\small \mathbf{x}\)、 2つの梁のバネを留める場所をA, Bとして 位置ベクトルを \(\small \mathbf{a}_1\)、\(\small \mathbf{a}_2\) とします。 重力加速度を \(\small \mathbf{g}\) とすると、質点はバネに引っ張られるので、 \(\small \vec{\rm PA}\)方向と\(\small \vec{\rm PB}\)方向の力、 さらには重力方向の力が加わります。 バネの力は自然長 \(\small L_0\) との差の部分に比例するので、 運動方程式は次のようになります。 \[\small \begin{align*} &\dfrac{d^2\mathbf{x}}{dt^2}=k(|\mathbf{a}_1-\mathbf{x}|-L_0) \dfrac{\mathbf{a}_1-\mathbf{x}}{|\mathbf{a}_1-\mathbf{x}|}\\ &+k(|\mathbf{a}_2-\mathbf{x}|-L_0) \dfrac{\mathbf{a}_2-\mathbf{x}}{|\mathbf{a}_2-\mathbf{x}|} -\mathbf{g} \end{align*}\] RungeKutta法を利用すると、この運動方程式の軌跡を描くことができます。 マニュアルの例にならい、個々の値や位置ベクトルを次のように定めます。 つまり、原点は2つの梁の中央にあります。 \[\small k=3, L=5, L_0=2, g=9.8\] \[\small a1=(L,0), a2=(-L,0)\] 下記の軌跡は、質点Pを \(\small (2, -5)\) まで引っ張った場合を、 時間間隔 0.05 で計算した場合です。 運動方程式の右辺の\(\small \mathbf{x}\) を q1 として 記述することになります。
  • \begin{MPpic}<1cm>(6|6,1|6) % 格子描画 \mptDrawGrid  [linetype=dashed hasen(),   xmin=-3w, xmax=3w]  {-3w step w until 3w}  {-6h step h until h} \sendMP{ % 宣言と変数定義  numeric K,L,Lo,g;  pair a[];  K:=3; L:=5; Lo:=2; g:=9.8;  a1:=(L,0); a2:=(-L,0); % ルンゲ・クッタ法  RungeKutta(   K*(length(a1-q1)-Lo)   *unitvector(a1-q1)+   K*(length(a2-q1)-Lo)   *unitvector(a2-q1)-(0,g))   (0,8*PI,0.05)    ((2,-5))((0,0))(pth);} % 結果に単位をつけて格納 \mptPath{ptha}  {pth1 scaled w} % 軌跡を描画 \sendMP{xdraw(red) ptha;} \end{MPpic}
上段の図は、 \(\small t\) の範囲を \(\small 0\sim 8\pi\) とした場合、 下段は \(\small 0\sim 16\pi\) の場合です。 MePoTeXのパッケージをダウンロードすると、 この質点の動きをバネの動きとともに 429頁のパラパラ漫画にしてPDFファイルを生成するソースファイルが登録されています。生成されるPDFファイルは「こちら」です。 プレゼンテーションモードでページ送りキーを押し続けてみて下さい (「みなも」さんより公開の許可をいただきました)。

▲戻る(トップメニューマップ)

■ ローレンツアトラクター
ローレンツアトラクターは気象学者ローレンツにより発見されたもので、 3次元空間で次の微分方程式で表される解軌道です。 \[\small \begin{align*} &\dfrac{dx}{dt}=a(y-x)\\ &\dfrac{dy}{dt}=bx-y-xz\\ &\dfrac{dz}{dt}=xy-cz \end{align*}\] 式から分かるように、これは非線形の連立微分方程式です。 ローレンツは、 具体的には \(\small a=10\)、\(\small b=28\)、\(\small c=8/3\) の場合を 検討しています。具体的な気象現象から立式しているにもかかわらず、 初期値を与えて解曲線を描かせると周期性は見られず、 さらには初期値の微妙な変化で軌道が大きく異なります。 きちんとした式で表現できているのに結果が見通せないことは、 当時の科学界に大きな衝撃を与えました。 この軌道はローレンツアトラクターと呼ばれ、 カオス現象が発見された頃の先駆的なものです。 [ 参照1参照2参照3参照4参照5参照6 ]

MePoTeXのマクロ「RungeKutta」を利用すると、 この連立微分方程式の解を求めてその軌道を描画することができます。 微分方程式の右辺の式を引き渡すため、 空間ベクトル \(\small (x,y,z)\) を \(\small (p1,p2,p3)\) とするとき、 このベクトルの個々の成分 p1, p2, p3 の満たす1階の 3元連立微分方程式を考えます。 \[\small \begin{align*} &\dfrac{dp_1}{dt}=a(p_2-p_1)\\ &\dfrac{dp_2}{dt}=bp_1-p_2-p_1p_3\\ &\dfrac{dp_3}{dt}=p_1p_2-cp_3 \end{align*}\] この関係を「RungeKutta」で処理すると、 解が引数(7)で 指定するパス変数(たとえば「pth」) に格納され、 p1, p2, p3 の軌跡は それぞれ pth[-1], pth[-2], pth[-3] に格納されます。 たとえば、pth[-1] は、 p1 と対応する t を成分に含むペア型変数を 繋いで得られるパスです。 同じ時刻 t の座標をまとめて空間座標 (p1,p2,p3) を得て、 その点の時刻を変えることで得られる軌跡が求める解軌道です。 つまり、得られた3個のパスから座標成分だけを取り出して一つにまとめて、 3次元空間の点として再構成します。 しかし、MetaPostには、空間の点を繋いでパスを構成する機能がありません。 そこで、MePoTeXでは、空間の点として再構成した点を 射影して平面上の点とします。そして、 その平面上の点を繋ぐことでパスを構成しています。 それを行うマクロが「projpath」です。 「projpath(pth[-1],pth[-2],pth[-3])」とすることで、 空間における解曲線の点を平面に射影した点のパスが得られます。


▲戻る(トップメニューマップ)

以上をもとに、\(\small a=10\)、\(\small b=28\)、\(\small c=8/3\) の 場合の軌道を求めると、次のようになります。 マニュアル[1] の図124(p72)を簡略化したもので、 時間間隔を 0.01 として、\(\small 0\sim 10\) の範囲の軌道です。
  • \begin{MPpic}<1cm>  (5|5,8)(0,1) \sendMP{ % [A]変数宣言と定義  numeric a,b,c;  a:=10; b:=28; c:=8/3; % [B]ルンゲ・クッタ法  RungeKutta(   a*(p2-p1),b*p1-p2-p1*p3,   p1*p2-c*p3)   (0,10,0.01)(0,0,0)   (6,9,20)(pth); % [C]視点を(3,0,1)方向に設定  SetProjDir(3,0,1)(blue); } % [D]平面のパスとして再構成 \mptPath{ptha}  {projpath(pth[-1],pth[-2],   pth[-3]) scaled 0.2w} % [E]軌道の描画 \sendMP{  xdraw() ptha;} % [F]座標軸 \mptXTaxis|0w==5w>[r]  <1mm,0mm>{$x$} \mptYTaxis|0w==5w>[r]  <1mm,0mm>{$y$} \mptZTaxis|0w==10w>[r]  <0mm,0mm>{$z$} \end{MPpic}
ここでは、[A]により使用する係数を変数宣言して値を代入しています。 [B]では、マクロ「RungeKutta」の引数を指定します。 マニュアル[1]の図124(p70)では、 初期値を \(\small (6,9,20)\) としています。 [C]では、視点を \(\small (3,0,1)\)方向に指定しています。 \(\small yz\)平面への射影状況が分かります。 [D]では、得られた p1,p2,p3 の解から空間の点 (p1,p2,p3) を構成して、 それを「projpath」を利用して平面に射影して繋いで パス値「ptha」を作成しています。 その上で、[E]で軌道「ptha」を描画し、[F]で座標軸を書き入れています。

2番目の図は、視点を \(\small (0,3,1)\) 方向とした場合です。 \(\small xz\) 平面への射影状況が分かります。 3番目は、視点を \(\small (1,1,4)\) とした場合です。 上から覗いた感じになります。 最初の図は、蝶の羽のように見えなくもありません。 左側と右側を「不規則に」行ったりきたりします。


▲戻る(トップメニューマップ)

パラパラ漫画
このローレンツアトラクターの軌道を, 「パラパラ漫画」にしてみましょう. コマ数を $\small n$ とするとき, 前述のコードを「\mptparapara{n}」と「\repeat」で囲って, 「\sendMP」内で「\mptgetkoma{n}」によりコマ数を受け取り, その値をもとに任意コマのグラフを描画するように修正するだけです. 下記では,$\small [0, 10]$ の区間を100分割し, $\small tm=\dfrac{i}{100}\cdot 10$ とするとき, $\small i$ コマ目は $\small [0, {\rm tm}]$ の範囲での グラフを描画するように指定しています. $\small i$は明示的には示されていませんが, 「tm:=(n/100)[0,10]」とすることで, tm の値が 0 から n まで自動的に変わり, 計(n+1)枚のページが生成されて1つのPDFにまとめられます. 大量の画像ファイルが生成されるので, 保存フォルダーは「\mptSaveDir」 を利用して指定しておきます.
\mptparapara{100}
begin{MPpic}<1cm>
 (5|5,8)(0,1)
 \mptgetkoma{n}
 \sendMP{
% [A]変数宣言と定義
 numeric a,b,c,tm;
 a:=10; b:=28; c:=8/3;
 tm:=(n/100)[0,10];
% [B]ルンゲ・クッタ法
 RungeKutta(
  a*(p2-p1),b*p1-p2-p1*p3,
  p1*p2-c*p3)
  (0,tm,0.01)(0,0,0)
  (6,9,20)(pth);
% [C]視点を(3,0,1)方向に設定
 SetProjDir(3,0,1)(blue);}
% [D]〜[F]は前述と同じ
\end{MPpic}
\repeat
PDFで表示するとき,プレゼンテーションモード, つまり「表示」の仕方は「単一ページ表示」とし 「ズーム」は「ページレベルにズーム」としておくと, ページ送りキーを押し続けるとパラパラ漫画風に表示されます. このように,MePoTeXを利用すると, TeXの中でローレンツアトラクターを描画でき, さらには,そのパラパラ漫画化までが簡単にできることになります.

生成されたPDFを下記に登録しておきます。 頁数を増やすときは、「tm:=(n/100)[0,10]」の「100」と「10」の箇所も 同時に修正する必要があります。 500頁にしたら、400頁を超えたあたりでオーバーフローで止まってしまいました。 400頁まではうまくいきますが、2時間近くかかりました。


▲戻る(トップメニューマップ)

統計グラフ
MetaPostは統計ソフトではありませんが、 図の作成に必要な値が与えられると、 いろいろなグラフを描画することができます。
ヒストグラム
ヒストグラム(柱状グラフ)は、データの分布の様子を棒グラフで示すものです。 必要な値は、柱の横幅と高さです。柱の幅を共通とすると、 その柱を配置するための位置(階級値)も指定する必要があります。 高さは、度数、相対度数、確率密度の場合がありますが、 それは縦軸の目盛りで調整できます。

以上のことを踏まえて、柱の幅は「HisWd」、 ヒストグラムは「Histogram(階級値, 高さ)(色)」で指定します。 実際に描画するには、生データから度数分布表を作成しておいて、 その値をもとに個々のヒストグラムを記述することになります。

たとえば、次のような度数分布表を考えます。

階級階級値度数
0〜30 252
30〜40 351
40〜50 455
50〜60 554
60〜70 658
70〜80 7512
80〜90 8516
90〜  952
50

ヒストグラムの柱を描画するには「Histgram」を利用し、 個々の柱を

Histgram(階級値,度数)(属性列)

の形で指定します。 属性列では、1個の数値か、2個のcolor値を指定できます。 数値の場合は柱の枠の太さを指定でき、color値の場合は枠内と枠線の色を 指定できます。
  • \begin{MPpic}<0.07cm,0.2cm>   (100,20) % [A] 格子描画 \mptDrawGrid  [linetype=dashed hasen(),  xmin=20w,xmax=100w,ymax=15h]  {20w step 10w until 100w}  {0 step 5h until 15h} \sendMP{ % [B] 変数宣言と柱の太さ  color Sora;  Sora:=hsb(0.5,0.2,1);  HisWd:=10w; % [C] ヒストグラム  Histogram(25,2)(Sora);  Histogram(35,1)(Sora);  Histogram(45,5)(Sora,blue);  Histogram(55,4)(Sora);  Histogram(65,7)(Sora);  Histogram(75,12)(Sora);  Histogram(85,14)(red);  Histogram(95,5)(Sora); % [D] 一つの柱だけ斜線入り  xfill(2pt*dir45)   (40w,0)--(50w,0)   --(50w,5h)--(40w,5h)   --cycle; % [E] 左の縦軸  xdraw(0.4pt)   (20w,0)--(20w,15h);} % [F] 軸に数値記入、ラベル \mptCoord(20,0)(10,0){9}[t]   <0mm,-0.5mm>{\xcoord} \mptCoord(20,5)(0,5){3}[r]   <-.5mm,0mm>{\ycoord} \mptLabel{(19w,14h)}[tr]   <.5mm,0mm>{\small (人)} \mptLabel{(100w,-1.5h)}[tr]   <3mm,-1mm>{(点)} \end{MPpic}
ここでは、縦横の範囲が大きいので、 単位あたりの長さを <0.07cm, 0.2cm> として詰めています。 [A]では、指定した範囲の一部領域に対する格子描画なので、 その範囲を xmin などを利用して指定します。 [B]では、カラー値変数の宣言をして、 具体的な色を HSB形式で 指定しています。この指定はマニュアル[1] の図93(p59)の指定を そのまま利用しています。 [C]では個々のヒストグラムを指定します。一部のヒストグラムでは、 内部の色や枠の色を変えています。 [D]は、一つの柱を(意味はありませんが)斜線塗りにしました。 「Histogram」のコマンドでは対応できないので、 xfill()を利用して描画しています。 [E]では縦線を引き、[F]では座標の数値を書き込んでいます。

相対度数で示したいときは、「度数」の箇所を相対度数で指定します。 小数値で指定してもよいですが、面倒なので全度数で割る形で指定した方が 簡単ですみます。ただし、縦軸は最大でも 1 以内にする必要があるので、 縦軸の単位や y 座標について修正する必要があります。 縦軸の刻み幅は小数値になりますが、 MetaPostの扱うことのできる小数は 1/65536 の整数倍の数値です。 あまり小さい数を扱う必要があるときは \mptNumSys{double} を指定して 倍精度にしておいた方が良いでしょう。 また、座標軸の箇所に表示するときは、桁数を丸めて表示します。 その場合の丸める小数点以下の桁数は、 「\mptRound{桁数}{変数}」で指定することができます。 以下は、相対度数で描画した場合です。 桁数は、{\ycoord}の前の ( ) 内で指定します。

  • \begin{MPpic}<0.07cm,10cm>  (100,0.4) \mptDrawGrid  [linetype=dashed hasen(),  xmin=20w,xmax=100w,  ymax=0.3h]  {20w step 10w until 100w}  {0 step 0.1h until 0.31h} \sendMP{  color Sora; HisWd:=10w;  Sora:=hsb(0.5,0.2,1);  Histogram(25,2/50)(Sora);  Histogram(35,1/50)(Sora);  Histogram(45,5/50)(Sora,blue);  xfill(2pt*dir45) (40w,0)--   (50w,0)--(50w,.1h)--   (40w,.1h)--cycle;  Histogram(55,4/50)(Sora);  Histogram(65,7/50)(Sora);  Histogram(75,12/50)(Sora);  Histogram(85,14/50)(red);  Histogram(95,5/50)(Sora);  xdraw(0.4pt)   (20w,0)--(20w,0.35h);} \mptCoord(20,0)(10,0){9}[t]  <0mm,-0.5mm>{\xcoord} % y座標の桁数を指定する \mptCoord(20,0.1)(0,0.1){3}[r]  <-.5mm,0mm>  (\mptRound{2}{\ycoord})  {\ycoord} \mptLabel{(100w,-0.03h)}[tr]  <3mm,-1mm>{(点)} \end{MPpic}

▲戻る(トップメニューマップ)

散布図
散布図の描画を行うマクロは「ScatterPlot」であり、 「ScatterPlot(描画命令)(点列)」の形で利用します。 「点列」は、散布する点の座標 (a,b) を「,」で区切って指定します。 描画命令は、指定した点にどのような図形を書き込むかを指定します。 その図形は、原点を中心とした path値で指定します。 たとえば、原点を中心とした半径 2pt の円を青 く塗りつぶして配置するには、 描画命令は「xfill(blue) circle(origin,2pt)」となります。 下図は、たとえば補習該当者を赤の三角印にしています。
  • \begin{MPpic}<0.05cm>  (100|8,100|8) % [A] 格子描画 \mptDrawGrid  [linetype=dashed hasen(),  xmin=0,xmax=100w,  ymin=0,ymax=100h]  {0w step 20w until 100w}  {0h step 20h until 100h} % [B] 青丸の配置 \sendMP{  ScatterPlot(xfill(blue)    circle(origin,2))  ((80,87),(58,45),(38,66),   (47,70),(70,56),(48,56))} % [C] 赤三角の配置 \sendMP{  path pth;  z0=(-sqrt(3),-1);  z1=(sqrt(3),-1);  \SetTriangle(z0,z1,z2)   (1,1,1);  pth=z0--z1--z2--cycle;  ScatterPlot   (xfill(red) pth)   ((15,20),(34,21),    (26,38),(30,47))} % [D] 軸の数値 \mptCoord(0,0)(20,0){6}[t]   <0mm,-0.5mm>{\xcoord} \mptCoord(0,20)(0,20){5}[r]   <-.5mm,0mm>{\ycoord} \end{MPpic}
[C]での赤三角は、最初にパス値変数の宣言を行い、 底辺の2点 z0, z1 の座標を定義します。 その上で、もう一つの頂点 z2 を、 3辺の比が \(\small 1:1:1\) の三角形の頂点として定めます。 そして、頂点を結んで得られる三角形を pth とした上で、 その三角形を「xfill(red) pth」により赤で塗りつぶしています。

▲戻る(トップメニューマップ)

箱ひげ図
箱ひげ図は、データの分布の様子を、 最小値・最大値と3つの四分位数を用いて図示したものです。 箱ひげ図を描くマクロは「HakoHige」で、次のような書式です。

HakoHige(min,Q1,Q2,Q3,max,位置)(属性列)

min と max はデータの最小値と最大値、Q1〜Q3は第1四分位数から第3四分位数、 そして箱ひげ図を横に描いた場合の縦方向の位置です。 そこで指定した値に「h」をつけた位置に図が描かれます。 属性列では、numeric値が最大3個、color値は最大2個指定できます。 数値の場合、1つ目はひげの太さ、 2つ目は横置きにした場合の端点(最小・最大)の縦の長さの半分の値、 3つ目は箱の線の太さです。 color値は、1つ目は内部の色、2つ目は枠の色です。

たとえば、下記のようになります。

  • \begin{MPpic}<0.7mm,5mm>   (100,4)(20,0) \mptDrawGrid  [linetype=dashed hasen(),   xmin=20,xmax=100]  {20w step 10w until 100w}{} \sendMP{  HakoHige(20,45,62,72,95,   1)();  HakoHige(32,40,52,62,85,   3)(1pt,green,red);} \mptCoord(20,0)(20,0){4}[t]   <0mm,-2mm>{\xcoord} \mptXaxis|20w==100w>[l]   <0mm,0mm>{} \end{MPpic}
上記では、高さ「1h」の箇所に下の図が、 「3h」の箇所に上の図が描かれています。

▲戻る(トップメニューマップ)

外部ファイルの利用
分析するデータから基本統計量が求まっているときは、 前述のような形でヒストグラムや箱ひげ図を描くことができます。 一方で、データ数が多い場合の散布図は、 その座標をいちいち書き込むのは面倒です。 そのような場合には、データを外部ファイルとして用意しておいて、 それを読み込むような形で利用することができます。
■外部ファイルの読み込み
統計データはcsv形式とすることが多いので、 ここでは CSV形式(カンマ区切り)による数値データの読み込みで利用します。 それを行うマクロは「ReadCSV」です。 書式は、次のような形です。 タブ区切りのデータでは「ReadTSV」を利用します。

zz:=ReadCSV("data.csv")(v)

CSVファイルは、カンマ区切りの(数値)データ行列です。 上記により、v にその行列データが格納され、 その行数と列数がペア型変数 zz に「(列数, 行数)」の形で返され、 データ行列の (i,j) 成分は、v[j][i] の形で参照することができます。 したがって、v[j] だけで j列が得られます。 行と列の指定が逆になっていることに注意して下さい。 zz からは、「xpart zz」により列数を、「ypart zz」により行数を 取り出すことができます。xpart(zz) などとしてもかまいません。


■外部ファイルを利用した散布図
「ReadCSV」を利用して、 散布図のときのデータを 「samplc.csv」 として保存して読み込んでみましょう。 このファイルは、2列からなる10個ずつのデータ、 すなわち (10,2)型の行列です。
  • \begin{MPpic}<.5mm>  (100|8,100|8) % マクロ「ReadCSV」の利用例 \sendMP{ numeric nn,v[][]; pair zz; zz=ReadCSV("samplc.csv")(v); nn=ypart(zz); for ii=1 upto nn: xfill(blue)    circle(origin,2pt)    shifted    (w*v[1][ii],h*v[2][ii]); endfor;} % グリッドの描画 (中略) \end{MPpic}
上記のコードでは、 「ypart(zz)」により行数を取り出して nn とし、 ii を 1 から nn まで変えながら、 座標が (v[1][ii], v[2][ii]) の箇所に青丸を配置しています。 元データでいうと、x 座標は (ii,1)成分、y 座標は (ii,2)成分です。

青丸は、原点(orijin)を中心とする半径2ptの円を塗りつぶしたものです。 その円を読み取った座標の箇所に「shifted」で移動すれば、 ScatterPlotを利用しなくても散布図を描くことができます。 ただし、その際は単位の w, h をつける必要があります。 グリッドや軸の数値の描画は、散布図の箇所の [A][D]と同一です。 \sendMP の外側(前半でも後半でもかまわない)で記述します。


▲戻る(トップメニューマップ)

■回帰直線
読み込んだデータ「v」から、 平均・標準偏差・共分散を求めて回帰直線を描画することもできます。 2つの変量の平均・標準偏差・共分散・相関係数を求めるマクロは「MvSdCov」で、

MvSdCov(配列1)(配列2)(番号列)

の形で使用します。 これにより、2つの変量の平均・標準偏差・共分散・相関係数が得られます。 全部で 6 個の値が返されるので、 transform宣言をした変数で 受け取る必要があります。 たとえば、v をデータ行列として、 2つの変量 \(\small x, y\) を1列目と2列目とするとき、 S を transform宣言した変数とすると

S:=MvSdCov(v[1])(v[2])(1 upto ypart(v))

により各変数の統計量が得られ、 個々の具体的な値は次のようにして取り出すことができます。 3番目の引数は、統計量を計算するデータの範囲を指定しています。 たとえば、(1 upto 10) などを指定すると、 最初の10個のデータについて計算されます。

ただし、統計計算はかなり大きな桁数になったりするので、 これらのマクロを使用する\sendMPの前では 倍精度の指定(\mptNumSys{double})をした方が安全でしょう。 なお、倍精度の指定を行う場合、変数に「e」は使用できません。

統計量取り出し方
\(\small x\) の平均 xpart S
\(\small y\) の平均 ypart S
\(\small x\) の標準偏差 xxpart S
\(\small y\) の標準偏差 yypart S
\(\small x, y\) の共分散 xypart S
\(\small x, y\) の相関係数  yxpart S

これらの値が求められると、回帰直線の式が分かります。 その式を求めるマクロが「Regression」です。 前述の transform値 S に値が入っていることを前提として、 「Regression(5)(S)」により、 \(\small x=5\) のときの回帰直線上の \(\small y\) の値が求められます。 \(\small x\) の箇所を変数 \(\small t\) に置き換えると \(\small t\) の1次式になるので、 直線のパスを生成するマクロ「linear」 に引き渡すことで回帰直線のパスが 得られ、xdraw() を通すことで回帰直線が描画されます。 下記のコードで最後の (0,100)(0,100) は、 回帰直線を描画する範囲の、左右と上下を指定しています。
  • \begin{MPpic}<.5mm>   (100|8,100|8) % マクロ「ReadCSV」の利用例 \sendMP{  numeric nn,v[][];  pair zz;  transform S;  zz=ReadCSV("samplc.csv")(v);  nn=ypart(zz);  for ii=1 upto nn:  xfill(blue) circle(origin,2pt)   shifted (w*v[1][ii],h*v[2][ii]);  endfor; % 平均・標準偏差等の取得  S:=MvSdCov(v[1],v[2])   (1 upto nn); % 回帰直線の描画  xdraw(red)   linear(Regression(t)(S))    (0,100)(0,100);} % グリッドの表示 (中略) \end{MPpic}
■平均と標準偏差
2変量ではなく、1変量の平均や標準偏差を求めるマクロは「MvSd」です。 たとえば、「numeric v[];」として v を1次元配列として宣言し、 ss と zz をペア宣言として 「zz:=ReadCSV("data.csv")(v)」によりデータを読み取ったとします。 v のデータ数を nn とすると、

ss:=MvSd(v)(1 upto nn)

により、ss には v の平均と標準偏差が「(平均, 標準偏差)」の形で返されます。 「numeric v[][];」として v を2次元配列とした場合は、 v[i] で i 列を参照できるので、nn を v[i] のデータ数とすると

ss:=MvSd(v[i])(1 upto nn)

とすることで、i 列の平均は xpart(ss),標準偏差は ypart(ss) により得られます。

▲戻る(トップメニューマップ)

copyright