第5章 グラフィックス

専修大学人間科学部 情報処理心理学実習 で使用している教科書 『MATLAB プログラミング入門』 の補足説明を行います.

注意:数式が適切に表示されるまで,少し時間がかかるかもしれません.

5.1 関数の姿を見る

5.1.1 1変数関数を描く:plot

例題 ex5101 はグラフの横軸が適切に設定されていません. スキップして,例題 ex5102 に進めばよいでしょう.

5.1.2 横軸を正す

例題 ex5102 は第1章の例題 ex1105(p.7)と同じです(第1刷では誤植があり, 例題 ex1106 となっています).

例題 ex5102 の変数 X にはベクトル 0:pi/100:2*pi すなわち, 0 π 100 2 π 100 2 π が代入されています.変数 Y にはベクトル sin 0 sin π 100 sin 2 π 100 sin 2 π が代入されています.

グラフを描くための最も基本的な関数は plot 関数です. 2つのベクトル X および Y があるとき, plot(X, Y) というコードは, 横軸を X ,縦軸を Y として,X と Y の値の組を点としてプロットして,折れ線で結びます. 例題 ex5102 では, 0 sin 0 π 100 sin π 100 2 π 100 sin 2 π 100 , ..., 2 π sin 2 π という点をプロットして,これらの点を折れ線で結んでいます. たくさんの点をプロットしているので, 点は曲線でなめらかに結ばれているように見えます.

5.1.3 複数の関数を描く(その1):figure

グラフを描画するウィンドウを Figure ウィンドウ と呼びます. 新しい Figure ウィンドウを作成するには figure 関数を用います.

例題 ex5103 の最後にある plot(X, Y) を実行しないようにすると(直前に % をつけます), 2つ目の Figure ウィンドウである Figure 2 が開かれていることがわかります. 最後の plot(X, Y) が実行されると,ここにグラフが描かれます.

ex5103Figure2

例題 ex5103 の4行目で X に代入されているベクトルは 0 π 100 2 π 100 79 π 100 です.コマンドウィンドウで


X = 0:pi./100:(2 .* pi).^0.5
79 .* pi./100

とキーインしてみてください.ベクトル X の最後の成分が 79 π 100 = 2.4819 であることがわかります.

ex5103

X に代入されるベクトルの最後の要素は,コードでは (2 .* pi).^0.5 となっています. これは 2 π であり,コマンドウィンドウでその値を確認すると 2.5066 となります.

(2 .* pi).^0.5

成分が等差数列をなすベクトルを作成する式 a:d:b での b は, 初項 a に公差 d を順に加えていってできる数になっていなくてもかまいません. この場合,数列において b を超えない最後の数が末項となります. 例題 ex5103 では 79 π 100 = 2.4819 2 π を超えない最後の数となります.なお, 80 π 100 = 2.5133 です.

5.1.4 複数の関数を描く(その2):hold

データベクトル X1 と Y1,X2 と Y2,...,Xn と Yn という組み合わせを同じ座標軸でプロットするときには, 例題 ex5104a で示されているように


plot(X1, Y1, X2, Y2, ..., Xn, Yn)

と書きます.

ここまで plot 関数の引数はベクトルでしたが,この関数は引数に行列をとることができます. その一例が例題 ex5104b です.

例題 ex5104b での「Y は列ベクトルになるようにしておく」というテキストの記述は, Y は行列なので少し奇妙な感じがします. 縦軸でプロットする3種類のデータを列方向(縦方向)に並べた行列 Y を plot 関数の第2引数として与えるということです.

しかし,行列 Y は,3種類のデータを行方向(横方向)に並べて作成しても問題ありません. すなわち,


Y = [sin(X); sin(2.*X); sin(4.*X)];

と書くことができます.plot 関数についての MATLAB のドキュメンテーション(R2919b)には,以下のような記述があります.

X または Y のどちらかがベクトルで他方が行列の場合、 行列の次元はいずれかの辺がベクトルの長さと等しいような次元でなければなりません。 行列の行数とベクトルの長さが等しい場合、 関数 plot はベクトルに対して行列の各列をプロットします。 行列の列数とベクトルの長さが等しい場合、 この関数はベクトルに対して行列の各行をプロットします。 行列が正方行列の場合、この関数はベクトルに対して各列をプロットします。

正方行列(行数と列数が等しい行列)の場合を考慮すると, テキストが述べているように,縦軸にプロットするデータは列方向に並べる習慣にしておくほうがよさそうです.

例題 ex5104c で用いられている関数 hold は, on で既存の座標軸のプロットを保持し,off で保持を解消します.

テキストでの「plot を呼び出すたびに新しいウィンドウが開かれてしまう」という記述は, hold 関数を使用しないと3つのウィンドウが開かれるように読めるので, 適切ではないでしょう.例題 ex5104c のコードから hold onhold off を消去してプログラムを実行してみてください. 開かれるのは Figure 1 というウィンドウだけです. 最初に plot(X, Y1) が実行されてグラフが描画されます. 次に,plot(X, Y2) が実行されて,グラフが上書きされます. その前に描かれていたグラフは消去されます. 最後に,plot(X, Y3) が実行されて,描かれたグラフが最終的に残ります.

テキストでは「曲線はすべて同じ色で描かれます」と述べられていますが, MATLAB の最近のバージョンでは色分けされます.

数学的内容についてひとつ説明しておきます. 関数 y = sin a x のグラフは, y = sin x のグラフに比べると,x 軸方向に 1 a 倍の拡大・縮小がされます.たとえば, y = sin 2 x のグラフは 1 2 倍に縮小され,振幅が 1 2 になります.

5.1.5 複数の関数を描く(その3):subplot

組み込み関数 subplot の基本的な使い方は,グラフ描画領域を m 行 n 列に分割し, 指定された位置 p に座標軸を描画するというものです. 引数は


subplot(m, n, p)

という順序で与えます.位置 p がどこなのかわかりにくいと思います. 次のコードをコマンドウィンドウに1行ずつキーインして, Figure ウィンドウの変化を観察してください.


subplot(2, 3, 1)
subplot(2, 3, 3)
subplot(2, 3, 5)
subplot(2, 3, 6)

Figure ウィンドウは最終的に下図のようになります.

ex5105 subplot function

例題 ex5105 では,subplot 関数が描画した座標軸にグラフを描くのは plot 関数の仕事です. この例題では subplot 関数の直後に plot 関数を使っていますが, 順序を崩さなければ,この2つの関数は連続していなくても問題ありません. たとえば,この例題のプログラムの冒頭部分は


X = 0:pi/100:2*pi;
subplot(2, 3, 1);
Y = sin(X);
plot(X, Y);

と書くことができます.

グラフ描画領域の分割を途中で変更することは,実際にはあまり行わないでしょうが, エラーにはなりません. たとえば,例題 ex5105 の最後を


Y = sin(4.*X);
subplot(2, 2, 4);
plot(X, Y);

にすると,描画領域の再分割がなされ,Figure ウィンドウの内容は下図のようになります. 2行3列に分割していたときの位置5に描画されていたグラフは, 描画領域を再分割して描かれるグラフと重なるので,消去されています. 再分割して描かれるグラフと重ならないグラフは残されています.

ex5105

5.1.6 曲線を描く

このセクションでは MATLAB についての新しい学習事項はありません. グラフを描画する関数の式の与え方がこれまでと異なるだけです. 変数 x および y が, いずれもパラメータ t の関数として与えられます.

パラメータ(日本語で「媒介変数」と表記されます)による関数の表現は高校数学で学習します. たとえば,円

x 2 + y 2 = r 2

は,パラメータ θ ( 0 θ 2 π ) を用いて,

{ x = r cos θ y = r sin θ

と書くことができます.

簡単な練習問題として,円

x 2 + y 2 = 1

のグラフを,パラメータ t ( 0 t 2 π ) を用いて描いてください.グラフの縦横比を調整しないと楕円に見えるので, plot 関数でグラフを描いた後に


axis square

と記述してください.これについては 5.2.5 節で学習します.

5.1.7 式を与えて描く:fplot

例題 ex5107 のプログラムでは,fplot 関数の第1引数に, プロットする関数前(sin)を引用符で囲んだ文字列で与えています. 第1引数に関数名を文字列として与えるこの書き方は, 将来的に廃止予定です. 実際,このプログラムの1行目をコマンドウィンドウでキーインすると, 警告が出ます(下図は MATLAB R2020a でのメッセージ).

ex5107 warning

関数名を文字列として与えるかわりに,4.2.6 節で学習した 関数ハンドル を使います. 例題 ex5107 のプログラム1行目を


fplot(@sin, [0 2*pi])

あるいは


fplot(@(X) sin(X), [0 2*pi])

としてください.演算子 @ は関数ハンドルを作成します. 組み込み関数である sin の場合は関数名に @ を適用して @sin とすれば,sin 関数の関数ハンドルが作られます. 無名関数 を定義する方法を用いて @(X) sin(X) と書くこともできます.

第2引数を省略して


fplot(@sin)

あるいは


fplot(@(X) sin(X))

とすると,グラフの横軸範囲が自動的に [-5 5] になります.

例題 ex5107 のプログラムでは,2行目で無名関数を定義し,その関数ハンドルを変数 F に代入しています. プログラム3行目は,この関数ハンドルをそのまま使って


fplot(F, [0 2*pi]); hold off

と書くことができます.あるいは,2行目の書かずに,3行目を


fplot(@(X) sin(X) + sin(5*X), [0 2*pi]); hold off

と書くこともできます.

5.1.6 節でパラメータを用いた関数を描画しました. こうした関数は fplot 関数でも描画できます. たとえば,例題 ex5106 の fplot 関数バージョンは


X = @(t) cos(3*t);
Y = @(t) sin(2*t);
fplot(X, Y, [0 2*pi]) % fplot(X, Y) でもよい

となります.

5.2 グラフを修飾する

5.2.1 節から 5.2.6 節まで,グラフの修飾はグラフを描いた後で行います. 5.2.7 節から 5.2.11 節まで,グラフの修飾は plot 関数の引数で行います. 5.2.12 節では,figure 関数で Figure ウィンドウの位置と大きさを指定します.

5.2.1 タイトルとラベルを付ける:title, xlabel, ylabel

タイトル,x 軸ラベル,y 軸ラベルの入れ方は簡単でしょう. グラフを描画した後に,title 関数,xlabel 関数, ylabel 関数を使います. タイトルあるいは軸ラベルとなる文字列は引用符(')で囲みます. 日本語も使用できます.

作成したグラフをレポートや論文に使用するときには必ず軸ラベルを入れるようにしてください. 測定単位がある場合にはそれも示します.たとえば「身長(cm)」とします.

タイトルあるいは軸ラベルとなる文字列には TeX(テフ)あるいは LaTeX(ラテフ)のコードを使用できます. TeX あるいは LaTeX は数式のある文書を美しく組版するために開発されたソフトウェアです. キーボードから入力できる文字で数式を記述した文書を TeX システムで処理すると, 美しい数式を使って組版がされます.

デフォルトでは,タイトルあるいはラベルの数式は TeX のコードとして解釈されます. これにより,例題 ex5201 での2乗の表記など,簡単な数式を表示させることができます.

複雑な数式をタイトルに表示させるには,title 関数での Interpreter という名前の引数の値を latex とします(この引数のデフォルト値は tex です). 複雑な数式の表示を行う前に,簡単な数式を試してみます. 例題 ex5201 で,title 関数の引数を以下のように書き換えてプログラムを実行してみてください. 数式を囲む $ と,sin の前の \ を追加し,Interpreter 引数の値を latex に設定します.


title('$ y = \sin^2(x) $', 'Interpreter', 'latex');

すると,タイトルは下図のように表示されます.

ex5201

複雑な数式をタイトルに表示する例を以下に示します. このプログラムはハートを描きます.


X = -1:1/100:1;
Y1 =  (X.^2).^(1/3) + sqrt(1 - X.^2);
Y2 =  (X.^2).^(1/3) - sqrt(1 - X.^2);
plot(X, Y1); hold on
plot(X, Y2); hold off
axis square
title('$ x^2 + (y - \sqrt[3]{x^2})^2 = 1 $', ...
    'Interpreter', 'latex');
xlabel('x'); ylabel('y');

heart function

5.2.2 説明文を入れる:text

グラフの描かれている座標で,点 x y を始点として説明テキスト txt を追加するには,text 関数を用いて


text(x, y, txt)

と書きます.この関数も,グラフを描画した後に使います.

5.2.3 グリッドを付加する:grid

グリッドの付加は,グラフを描いた後で,grid 関数を使って行います. これは容易でしょう.

5.2.4 座標軸を設定する:axis

テキスト p.131 の記述に誤植が2か所あります(改訂版第1刷). 「つぎに上のグラフが表示され」を「つぎに下のグラフが表示され」に修正してください. この記述のすぐ下の行で, 「[-1.5, +1.5] と変わります」を「[-1.2, +1.2] と変わります」に修正してください.

グラフを描く座標軸の範囲の設定は,グラフを描画した後に, axis 関数を使って行います.

例題 ex5204 のプログラムを実行すると, 1行目の plot 関数により下図のグラフが表示されます(MATLAB R2020a).

ex5204

ここで,2行目の pause 関数がプログラムの実行を一時的に停止します. 何かキーを押すと,3行目の axis 関数が座標軸を描きなおします. 座標軸が変化したことを確認してください.

5.2.5 縦横比を等しくする:axis

例題 ex5205 のプログラムにおそらく誤植と思われるところがあります(改訂版第1刷). 2行目の title('Circle') は不要でしょう. 次ページの図にこのタイトルはありません.

グラフの座標の縦横比を等しくするには,グラフを描画した後で,


square equal
 

とします.座標軸を消すには


square off
 

とします.例題 ex5205 のプログラム3行目では,これらの設定を同時に行っています.

5.2.6 凡例をつける:legend

凡例は,グラフを描いた後に,legend 関数によって挿入します.

凡例の位置は.legend 関数の Location 引数で設定できます. この引数の値はデフォルトで northeast に設定されており, 凡例は座標軸内の右上部に配置されます.上下は north と south, 左右は west と east であらわされます. よって,凡例の位置が左上部なら northwest, 右下部なら southeast,左下部なら southwest とします. 例題 ex5206 のプログラム3行目で,legend 関数の引数を


legend('sin(X)', 'sin(2x)', 'sin(3x)', 'Location', 'southeast')

と書いてみてください.凡例は座標軸内の右下部に配置されます. 他の位置も試してみてください.

5.2.7 線のタイプを指定する

5.2.7 節から 5.2.11 節まで,グラフの修飾は plot 関数の引数で行います.

例題 ex5207 の4行目では線のスタイルの プロパティ を鎖線('--')に設定しています. テキストの印刷では - が2つではなくダッシュに見えますので注意してください. (誤植かもしれません)

線のスタイルは何も指定しなければデフォルトで実線ですので, このセクションの最後での「なし 線を表示しない」という記述はわかりにくいです. 線のスタイルを指定せずにマーカー(5.2.9 節)を指定すると, 線は表示されずにマーカーだけが表示されます.

線のスタイルのプロパティを設定するための plot 関数の引数名は LineStyle です.この引数名を明示した方が,記述は長くなりますが, 線のスタイルの設定であることが分かりやすいかもしれません. たとえば, 例題 ex5207 のプログラム3行目は


plot(X, 0.8 * sin(X), 'LineStyle', ':');

と書くことができます. ただし,この書き方は,plot 関数を1回だけ使って X と Y の複数のペアを指定し, それぞれのグラフで線のスタイルを変える場合には使えません. たとえば,plot(X1, Y1, 'LineStyle', '--', X2, Y2, 'LineStyle', ':'); という書き方はエラーになります.

5.2.8 線の色を指定する

例題 ex5203a のように,plot 関数を1回だけ使って X と Y の複数のペアを指定し, それぞれのグラフで色を変える場合には,RGB 値での色の指定はできません. 引数名 Color も使えないので注意してください.たとえば, plot(X, sin(X), 'Color', 'r', X, sin(2.*X), 'Color', 'g'); と書くとエラーになります. ただし,複数のグラフの色を統一する場合には,RGB 値と引数名を使えます. たとえば,すべてのグラフを緑色とする場合に, plot(X, sin(X), X, sin(2.*X), 'Color', [0 1 0]); と書くことができます.

例題 ex5203b のように, 線の色を RGB 値で指定する場合には,引数名 Color は省略できません.

5.2.9 マークで描く

例題 ex5209 では,線のスタイル,色,マーカーを, plot 関数のひとつの引数で同時に指定できることに注目してください. 文字列 'rx' は,赤色の x 印のマーカーを意味します. 線のスタイルは指定されていません. 線のスタイルを指定せずにマーカーを指定すると, 線は表示されずにマーカーだけが表示されます. 文字列 '-gp' は,緑色の実線と星形のマーカーを意味します.

5.2.10 線の太さを指定する:LineWidth

線の太さを指定するとき,引数名 LineWidth は省略できません.

2本グラフを太さを変えて重ね書きする場合, plot(X, sin(X), 'LineWidth', 3, X, sin(2.*X), 'LineWidth', 6) と書くことはできません.ただし,太さを同じにして, plot(X, sin(X), X, sin(2.*X), 'LineWidth', 6) と書くことはできます.

5.2.11 もっとたくさん修飾する

例題 ex5211 では,線のスタイル,色,マーカーを,青い実線と円形に指定しています( '-bo'). その後,プロパティの名前と,プロパティの値を順に並べています.

5.2.12 ウィンドウを修飾する:figure

例題 ex5212a では,figure 関数の Position プロパティの値を指定して, ディスプレイでの特定の位置に特定の大きさの Figure ウィンドウを開いています. これは第1章の例題 ex1701 で一度体験しています.

Figure ウィンドウには, 色,名前,表示位置とサイズなどのプロパティがあります. これらプロパティにはあらかじめデフォルト値が設定されています. 単に figure とキーインすると, これらデフォルト値を使って Figure ウィンドウが作成されます. あるプロパティ(たとえば,ウィンドウの位置とサイズ)に関して特定の値を使いたければ, figure 関数を使うときに,そのプロパティの名前と値を引数として与えます.

プロパティとその値は複数指定できます.一般的な書式は


figure('名前1', 値1, '名前2', 値2, '名前3', 値3, ...)

となります. プロパティの「値」は単一の数値であるとは限りません. 数値を集めたベクトルであったり,文字列であったりします. 開かれる Figure ウィンドウの位置と大きさを決める Position プロパティの値は4つの数値から構成されるベクトルです.

コンピュータのスクリーン,および,そこに開かれる Figure ウィンドウは, グラフィックスオブジェクト です. グラフィックスオブジェクトはそれぞれ ハンドル(handle)を持っています. ハンドルはグラフィックスオブジェクトに結びつけられた「ひも」のようなものと考えるとよいでしょう. あるいは,文字通り「取っ手」と考えてもよいでしょう. ひも,あるいは,取っ手をつかめば, グラフィックスオブジェクトにアクセスしてプロパティを操作することができます.

スクリーンは ScreenSize というプロパティを持っています. この値は,Figure ウィンドウの Position プロパティと同じく,4つの数値から構成されるベクトルです. 最初の2つの数値はスクリーン左下の座標であり, 1 1 です.3番目の数値がスクリーンの幅,4番目の数値がスクリーンの高さです. 幅と高さの単位はピクセルです.

スクリーンの大きさを知るには, グラフィックスオブジェクトのプロパティを調べる get 関数を用いて


get(0, 'ScreenSize')

とキーインしてください.第1引数の 0 はスクリーンを意味する番号です, 第2引数はオブジェクト(ここではスクリーン)のプロパティ名です. すると,下図のようにスクリーンのサイズが表示されます. 幅が1440ピクセル,高さが900ピクセルであることがわかります.

ScreenSize

MATLAB のバージョンが R2014b 以降なら, groot とキーインすると, 下図のようにスクリーンサイズの情報が得られます.

groot function

この出力で Root とはスクリーンのことです(5.3.1 節で学習します). 関数 groot はスクリーンのプロパティとその値を参照します.

例題 ex5212b で,スクリーンのプロパティ名である ScreenSize と, ハンドルを保持する変数 ScreenSize を,混同しないように注意してください. プロパティ名は引用符で囲まれています. 変数 ScreenSize にはスクリーンの ScreenSize プロパティの値が保持されています. この値は4つの数値から構成されるベクトルですので, ScreenSize(3) とすればベクトルの第3の成分が得られます. これはスクリーンの幅です. 同様に,ScreenSize(4) とすればベクトルの第4の成分が得られます. これはスクリーンの高さです.

例題 ex5212b では,Figure ウィンドウの Position プロパティの値を


figure('Position', ...
    [ScreenSize(3)./4, ScreenSize(4)./4, ...
    ScreenSize(3)./2, ScreenSize(4)./2]
)

と指定しています.スクリーンの幅が1440,高さが900だとすると,これは


figure('Position', ...
    [360, 240, ...
    720, 480]
)

と指定したことになります.

5.3 グラフィックスの仕組み

5.3.1 グラフィックスを知る:get, set

注意: グラフィックスにかかわるハンドルの仕様が MATLAB 2014b で変更になったため, テキストの記述には現在の仕様と一致していないものがあります. 特に,Parent プロパティおよび Children プロパティの値が数値ではないことに注意してください. たとえば,Figure ウィンドウの Parent プロパティの値は [1 × 1 Root] となります. Children プロパティの値は [1 × 1 Axes] となります.

5.1.4 節で学習したように,plot 関数の引数 X と Y のうち,一方をベクトル, もう一方を行列とすると,グラフを重ね書きすることができます. テキスト p.142 では,


plot((0:10)', [(0:2:20)', (10:20)'])

として2本のグラフを描いています. 引数 X は列ベクトル (0:10)' ですが,これは行ベクトルとしてもかまいません.

スクリーン,Figure ウィンドウ,座標軸,グラフはすべて MATLAB の グラフィックスオブジェクトです. 5.2.12 節で学習したように,グラフィックスオブジェクトはそれぞれハンドルを持ちます.

グラフィックスオブジェクトには包含関係に基づく階層構造があります. オブジェクト A がオブジェクト B を含むとき,A は 親オブジェクト, B は 子オブジェクト と呼ばれます. たとえば,座標軸は Figure ウィンドウに含まれるので, Figure ウィンドウが親オブジェクト,座標軸が子オブジェクトとなります. テキスト p.142 のグラフを描いたあとで, このグラフの Figure ウィンドウとスクリーンとの親子関係を確認してみましょう. コマンドウィンドウで,


HF = gcf

とキーインしてください.組み込み関数 gcf は, 現在アクティブになっている Figure ウィンドウのハンドルを返します. この関数名は get the current figure handle という意味です. 現在アクティブになっている Figure ウィンドウとは, 最後に描画されたか,あるいはマウスで選択されたウィンドウです. 例題 ex5303a で学ぶように,figure 関数で指定することもできます. テキストのように,


HF = get(gcf)

とキーインしてもよいですが, get 関数の引数にグラフィックスオブジェクトのハンドル(gcf 関数によって返されます)だけを与えると, ハンドルで指定されたグラフィックスオブジェクトのプロパティ, および,プロパティ値をすべて返すので,出力が長くなります. あまり気にする必要はありませんが,変数 HF に保存される情報の構造も異なります.

グラフを描いた Figure ウィンドウのハンドルを得たら(変数 HF に保存しました),親オブジェクトを調べてみましょう. コマンドウィンドウで


get(HF, 'Parent')

あるいは


HF.Parennt

とキーインしてください(後者の,ハンドルとプロパティをドットでつなぐ構文は, MATLAB 2014b から導入されました). ハンドル HF で指定されたオブジェクトの Parent プロパティの値が返されます. このプロパティの「値」は,ひとつの数値ではなく, 親オブジェクトのさまざまな情報を含んでいます.

the parent object of a figure object

「Graphics Root のプロパティ」が示されたことから, グラフを描いた Figure ウィンドウの親オブジェクトは Root であることがわかります. Root オブジェクト とはスクリーンのことです. スクリーンはグラフィックスオブジェクトの階層構造での根(つまり,大元)です. テキスト p.145 では「figure が属している「親」が存在しない」と記述されていますが, これは誤りです.開かれた Figure ウィンドウはすべて, 親オブジェクトとして Root を持ちます.

次に,スクリーンの子オブジェクトを調べてみましょう. スクリーンのハンドルは groot 関数で得られます.コマンドウィンドウで,


r = groot;
get(r, 'Children')

あるいは


r = groot;
r.Children

とキーインしてください. Root オブジェクト(スクリーン)の Children プロパティの値が表示されます.

a child object of the root object

「Figure (1) のプロパティ」が示されたことから, スクリーンの子オブジェクトはひとつだけ開かれている Figure ウィンドウであることがわかります. 実際,Figure ウィンドウのハンドル(変数 HF に保存されています)を用いて, Figure ウィンドウの番号(Number プロパティ)と位置(Position プロパティ)を調べると, Root オブジェクトの Children プロパティと一致した情報が得られます. Figure ウィンドウは Figure オブジェクト と呼ばれます.

properties of a figure object

Figure オブジェクトはいくつかの異なった種類の子オブジェクトを持つことができます. そのひとつが座標軸です. グラフを描いた Figure ウィンドウの子オブジェクトを調べてみましょう. コマンドウィンドウで,


get(HF, 'Children')

あるいは


HF.Children

とキーインしてください.

an Axes object as a child of a igure object

「Axes のプロパティ」が示されました. この Figure ウィンドウの子オブジェクトが Axes オブジェクト であることがわかります. Axes オブジェクトはグラフの座標軸です.

この座標軸にはグラフが描かれています. このとき,Axes オブジェクトは子オブジェクトとしてグラフの線分を持ちます. コマンドウィンドウで,


HA = gca;
get(HA, 'Children')

あるいは


HA = gca;
HA.Children

とキーインしてください.ここで用いている gca 関数は,現在アクティブになっている Axes オブジェクトのハンドルを返します. この関数名は get the current axes handle という意味です.

Line Array

座標軸に2本のグラフを描いていますので, これら2本のグラフのハンドルが2行1列の配列(行列)にまとめられ, Axes オブジェクトの子オブジェクトとなっています. グラフの線分は Line オブジェクト と呼ばれます.

2本のグラフのプロパティの値を調べるには, これら Line オブジェクトのハンドルがまとめられた配列の要素をひとつづつ取り出します. 第1の直線のプロパティの値は


HC = get(gca, 'Children');
HC(1)

あるいは


HA.Children(1)

とすれば得られます.XData および YData というプロパティの値を見ると, プロットされているデータがわかります.

line object 1

第2の直線については,


HC(2)

あるいは


HA.Children(2)

とします.

5.3.2 もう1つの修飾方法:set

例題 ex5302b のプログラム2行目に誤植があります. HCHL に修正してください.

例題 ex5302a で,変数 HC にはグラフの座標軸の Cildren プロパティの値が格納されています. プログラムを実行した後,コマンドウィンドウで HC とキーインしてみてください.このCildren プロパティの値は2行1列の配列で, 配列の要素はそれぞれ座標軸に描かれたグラフ(Line オブジェクト)に対応していることが分かります.

ex5302a HC

グラフィックスオブジェクトのプロパティを設定する set 関数を用いると,グラフの修飾を行うことができます. 例題 ex5302a での座標軸の Cildren プロパティの値は2行1列の配列なので, 2つの Line オブジェクトのプロパティの値も2行1列の配列(セル配列)で指定します. たとえば,Color プロパティの値は {'r', 'g'}' と指定しています. 最後についている転置の演算子(')を忘れないようにしてください (忘れると1行2列のセル配列となり,エラーとなります).

線のスタイル(LineStyle プロパティ)の設定では,テキストの印刷が {'-.', '-'}' に見えますが, {'-.', '--'}' ですので注意してください. それぞれ,1点鎖線と鎖線です(p.135 を参照してください). 例題 ex5302b および ex5302c でも同じです.

例題 ex5302a と ex5302b で,プロパティの指定順序が異なっていることはややこしいですね. 特に,例題 ex5302a では,グラフを描いた順序とプロパティの指定順序が逆順になっており, 誤りやすいです. 座標軸(Axes オブジェクト)の Children プロパティが Line オブジェクトの配列であるとき, グラフはこの配列の下から上の順で描かれています. 一方,例題 ex5302b のように,plot 関数でグラフを描画したときにそのハンドルを取得した場合には, ハンドルが配列であることは同じですが, グラフは配列の上から下の順で描かれています. このことを,例題 ex5206 を改変した次のプログラムで確かめてみましょう. Line オブジェクトの DisplayName は凡例のラベルを設定します.


clear
X = 0:pi./100:2.*pi;
HL = plot(X, sin(X), X, sin(2.*X), X, sin(3.*X));

HL(1).DisplayName = 'sin(X)';  % 凡例のラベルを設定
HL(2).DisplayName = 'sin(2X)';
HL(3).DisplayName = 'sin(3X)';
legend()  % 凡例を挿入

HL
HC = get(gca, 'Children')

プログラムを実行すると下図の結果が得られます. 配列での Line オブジェクトの並びが逆になっていることがわかります.

ex5206 modified

5.3.3 ウィンドウを操る

例題 ex5303a で学習するのは,親オブジェクトを選択して, 子オブジェクトを配置する手法です. たとえば,Figure ウィンドウを選択して座標軸を描くことや, 座標軸を選択してグラフを描きます. 親オブジェクトを選択することを,そのオブジェクトを カレント にすると言います.

Figure ウィンドウ(Figure オブジェクト)をカレントにするには figure 関数を用います. 選択したいウィンドウのハンドルを引数とします. たとえば,例題 ex5303a のプログラム6行目では, figure(FH1) として,ハンドルが FH1 である Figure ウィンドウをカレントにしています. ハンドルは,このウィンドウを描画したときに,figure 関数の出力として得られています. 選択したウィンドウで座標軸を描くには axes 関数を用います. たとえば,例題 ex5303a のプログラム7行目から8行目では, Position プロパティと Color プロパティの値を指定して座標軸を描いています.

座標軸(Axes オブジェクト)をカレントにするには axes 関数を用います. 選択したい座標軸のハンドルを引数とします. たとえば,例題 ex5303a のプログラム14行目では, axes(AH11) として,ハンドルが AH11 である座標軸をカレントにしています. ハンドルは,この座標軸を描画したときに,axes 関数の出力として得られています. 選択した座標軸でグラフを描くために,例題 ex5303a のプログラムでは line 関数を用いています. この関数は plot 関数と同じように使います.違いは, plot 関数は既存のグラフを新しいグラフで置き換える 高水準関数(high-level function)であるのに対して, line 関数は既存のグラフにできるだけ変更を加えずにグラフィックスオブジェクトを追加する 低水準関数(low-level function)であることです.

例題 ex5303a はプログラムが少し長いので, 長いプログラムは部分的に書き,テストを繰り返して完成させるという原則に従って, 段階的に作成してもよいでしょう. たとえば,選択するオブジェクトごとに,5行目まで,6行目から9行目,10行目から13行目, 14行目から16行目,17行目から18行目,19行目から20行目と分けて, 順に書いていきます. 部分的な実行を繰り返すとき,すでに描かれている Figure ウィンドウは消えず, 新しいウィンドウが開かれます. すでに描かれている Figure ウィンドウを閉じてから, 次の実行を行うとよいでしょう. ワークスペースにある変数も消去した方がよいでしょうから, clear 関数と, ウィンドウを閉じる close 関数を用いましょう. コマンドウィンドウで


close all
clear all

とキーインしてください.

例題 ex5303b で学習するのは,必要なオブジェクトをデフォルトのプロパティで描画しておき, 後で set 関数を用いて細かな調整を行う方法です.

例題 ex5303b は,プログラム6行目までを, セミコロンの区切りごとにコマンドウィンドウでキーインしてみると, 何が起きるのかわかりやすいと思います. プログラム6行目まで,figure 関数,axes 関数,line 関数が呼び出されるたびに. Figure ウィンドウ,座標軸,グラフが新たに描画されます. たとえば,プログラム1行目と2行目では, FH1 = figure; で Figure ウィンドウ, AH11 = axes; で座標軸,LH111 = line; でグラフが描かれます. 引数なしで line 関数を呼ぶと,点 (0,0) から (1,1) への直線が,既定のプロパティ設定で描画されます.

すでに描かれているオブジェクトに重ねて新たなオブジェクトが描かれると, 何も変化がなかったり,描かれていたオブジェクトが消去されたりするように見えます. しかし,実際には,先に描画されたオブジェクトは残っており, 新しいオブジェクトが前のオブジェクトを隠しているだけです. たとえば,プログラム2行目の LH112 = line; を実行すると何も変化がないように見えますが, これは直前の LH111 = line; で描かれた直線の上に同じ直線が描かれたためです. 1本に見えますが,2本の直線が存在しています. プログラム7行目以降でオブジェクトそれぞれの設定を変更していくと, 重なっていたオブジェクトが分けられて,見えるようになります.

例題 ex5303b のプログラム17行目までを実行すると, 2つの Figure ウィンドウは下図のような状態になります.

ex5303b the first figure

ex5303b the second figure

このあと,プログラムの18行目以降では,Line オブジェクトの設定を繰り返して, 例題 ex5303a と同じ結果が得られます. Line オブジェクトの設定では,Xdata および YData というプロパティの値を変更しています. これにより,プロットされているデータが変更されます.

例題 ex5303c では,オブジェクトのハンドルはいつでも取得できるということを示します. プログラムの実行は pause 関数によって一時停止されますので, 続行するときには何かキーを押してください. キーを押したとき,Figure オブジェクトでの描画がどのように変化するかを観察してください.

5.4 3次元グラフィックス

5.4.1 曲線で曲面を描く

例題 ex5401 で使用している meshgrid 関数および mesh 関数は,第1章の 1.7.1 節で一度学習しました.

テキストの説明で,meshgrid 関数のふるまいは理解できるでしょう. 2つのベクトル

X X = x 1 x n
Y Y = y 1 y m

から,mn 列の2つの行列

X = x 1 x n x 1 x n
Y = y 1 y 1 y m y m

を作ります.たとえば,

X X = 1 2 3
Y Y = 4 5 6 7

からは

X = 1 2 3 1 2 3 1 2 3 1 2 3
Y = 4 4 4 5 5 5 6 6 6 7 7 7

が作り出されます.コマンドウィンドウで


XX = [1 2 3];
YY = [4 5 6 7];
[X Y] = meshgrid(XX, YY)

とキーインして確かめてください.

以上のことは理解できても,これがなぜ "meshgrid" なのか,よくわからないかもしれません. 英単語の mesh は「網の目」,grid は「格子」という意味ですね. 実際,meshgrid 関数は2次元あるいは3次元の格子座標を返す関数です.

上述の例での2つの行列 X および Yで, 同じ位置にある成分を組み合わせると,

1 4 2 4 3 4 1 5 2 5 3 5 1 6 2 6 3 6 1 7 2 7 3 7

となります.このようにしてできる点をすべてプロットしてみましょう. 以下のコードを実行してください.


XX = [1 2 3];
YY = [4 5 6 7];
[X Y] = meshgrid(XX, YY)
plot(X, Y, 'ro');
xlabel('X');
ylabel('Y');
set(gca, 'XLim', [0 4], 'YLim', [3 8], 'XTick', 0:4, 'YTick', 3:8);
grid on

下図のように,網目の格子点が得られていることがわかります. X X = 1 2 3 は行ベクトルで並べて行列 X を作り, Y Y = 4 5 6 7 は列ベクトルにして並べて行列 Y を作ったのは, 座標の横軸と縦軸に対応していたのです.ただし, 縦軸は上に行くほど数値が大きいですから, 行列 Y とは上下が逆になっています.

meshgrid

格子点 x i y j それぞれに実数 z i j を対応させる関数 z = f x y を定義したら,mesh 関数を使って関数のグラフを描くことができます. あたかも,上図の網目が自由に伸縮する糸でできており,格子点での z の値に応じて高さを変えたようなグラフが描かれます. MATLAB のドキュメンテーションでは,この関数を次のように説明しています.

mesh(X,Y,Z) は,メッシュ プロットを作成します。これは,色付きの実線のエッジと, 色なしの面をもつ 3 次元表面です.この関数は行列 Z の値を, X と Y で定義される x-y 平面のグリッドの上の高さとしてプロットします. エッジの色は,Z で指定された高さに従って異なります.

グラフが描画されたら,座標内をマウスで左クリックしてやると, グラフを自由に回転させることができます(クリックしたまま動かします). 下図は x-y 平面を真上から見たもので,メッシュがわかります.

ex5401 mesh

5.4.2 曲面を描く:surf

例題 ex5402 で使われている surf 関数は, 網目の面が色で塗りつぶされる以外は,例題 ex5401 で用いた mesh 関数と同じです.

5.4.3 関数値を色で見る:colorbar, colormap

関数地と色の対応を示すカラーバーは colorbar 関数で表示します. 例題 ex5403a では,surf 関数で描いたグラフにカラーバーを表示しています. 5.4.1 節で学習した mesh 関数で描いたグラフにも表示できます.

例題 ex5403b のプログラム4行目は, colormap 関数の引数にカラーマップを指定して, colormap('hot') と書くこともできます.

指定できるカラーマップの一覧で,map は誤植です.このような指定はありません.

5.4.4 グリッドを消す:shading

例題 ex5404 で使用している shading 関数は,描画されている特定のタイプのオブジェクトの, 色のシェイディングにかかわるプロパティを操作します. 引数として,flat の他に facetedinterp が指定できます. デフォルトは faceted であり,shading 関数を使用しなければ, デフォルトのプロパティ値でオブジェクトが描画されます. 下図は interp を指定しての描画です.

ex5404 interpolated shading

5.4.5 空間曲線:plot3

例題 ex5405 で使用している plot3 関数は, 第1章の 1.7.1 節で一度学習しました. これまで何度も使ってきた plot 関数の3次元版であり, 3次元でのラインをプロットします(点のプロットもできます).

5.5 いろいろなグラフ

5.5.4 節,5.5.9 節, 5.5.10 節はスキップしてもらってかまいません.

5.5.1 関数で曲線を描く:ezplot

例題 ex5501 で関数のグラフを描くのに使用されている ezplot 関数 (eazy-to-use function plotter という意味)は, 現在の MATLAB では推奨されていません. かわりに,5.1.7 節で学習した fplot 関数を使用することが推奨されています. 例題 ex501 のグラフを fplot 関数で描画するには,


F = @(X) sin(X) + sin(3*X); % 関数ハンドルを作成
fplot(F, [0, pi]);

とします.第1引数は関数ハンドルとします.

5.5.2 関数で曲面を描く:ezsurf

例題 ex5502 で曲面を描くのに使用されている ezsurf 関数 (Easy-to-use 3-D colored surface plotter という意味)は, 現在の MATLAB では推奨されていません. かわりに,fsurf 関数を使用することが推奨されています. 例題 ex501 のグラフを fsurf 関数で描画するには,


F = @(X, Y) -X.^2 - Y.^2;
fsurf(F, [-6, 6, -6, 6]);

とします.第1引数は関数ハンドルとします.第2引数を省略すると, デフォルトで [-5 5 -5 5] という設定になります.

5.5.3 等高線:contour

テキスト p.167 の最終行に書かれているように, contour 関数は,等高線行列と,グラフィックスオブジェクトのハンドルを返します. 例題 ex5503a および例題 ex5603b では,プログラム3行目で, 輪郭線行列を変数 C に,ハンドルを変数 H に保存しています.

等高線行列(テキストでは「輪郭線行列」)は,何本か描かれる等高線ごとに, 等高線の高さ,等高線の頂点の数,等高線の頂点の (X, Y) 座標を保持した行列です.

グラフィックスオブジェクトのハンドル(ここでは変数 H に保存)を用いて, 描画されたグラフィックスのプロパティを調べることができます(下図).

ex5503a contour object property

同じことは,5.3.1 節で学習した gca 関数を用いて行うこともできます.

ex5503a contour object property (gca)

等高線に関数値を表示するには,テキストで説明されている clabel 関数を用いる方法の他に, contour 関数の引数で ShowText プロパティを on に設定する方法があります. すなわち,


[C, H] = contour(X, Y, Z, 'ShowText','on');

とします.

5.5.5 棒グラフ:bar

例題 ex5505 は棒グラフの高さとなる数値を乱数で生成しているので, データとグラフ(棒)との対応関係が少しわかりにくいですね. それに,実際の棒グラフでは必要となる軸ラベルや凡例が挿入されていません. もう少しわかりやすく,実際に近い棒グラフを作成するために, 以下のプログラムをエディターで書いて実行してください


Y = [1 2 3; 4 5 6; 7 8 9];

bar(categorical({'A', 'B', 'C'}), Y);

% 古いバージョンではこうする
%bar(Y);
%tcksX={'A', 'B', 'C'};
%set(gca, 'XTickLabel',tcksX ,'XTick',1:length(tcksX));

set(gca, 'YLim', [0 10]); % Y 軸範囲の設定
xlabel('変数X'); % GNU Octave では日本語を使わないこと
ylabel('度数');
legend('第1列', '第2列', '第3列', 'Location', 'northwest');

下図の棒グラフが描画されます.

an example of bar chart

例題 ex5505 では棒グラフを描画する bar の引数にデータだけを与えていましたが, このコードでは横軸上に表示するラベルも指定しています. ラベルがカテゴリの場合には,categorical 関数(MATLAB 2013b で導入)を使って, カテゴリカル配列(categorical array)と呼ばれる構造のラベルを作成します. 上のプログラムでは categorical({'A', 'B', 'C'}) としています. 横軸上に数値を配置する場合は通常のベクトルを使います.

データ Y が行列で与えられると,各列がひとつの系列(カテゴリ)に対応します. たとえば,成績分布のグラフを男女別に描画したければ,第1列が男性の度数分布, 第2列を女性の度数分布とします.

実際のデータを分析するときには, データは Microsoft Excel のような表計算ソフトウェアで入力して保存されており, それを読み込んで分析することが一般的でしょう. たいていは,各列がひとつの変数に対応しているはずです. 数値で測定されている変数もあれば,性別などカテゴリが記録されている変数もあるでしょう.

このようなデータを保存した CSV ファイルを読み込み, カテゴリカルな変数について棒グラフを作成する例を示します. データの例として,山田・村井・杉澤『R によるやさしい統計学』(オーム社)の 指導法データ を使います.リンク先の CSV ファイルをダウンロードし, MATLAB の作業ディレクトリ(コマンドウィンドウで pwd とキーインすると表示されます)に保存してください. このファイルは Windows 版の Microsoft Excel で作成したものです. 文字コードは Shift-JIS です.

スプレッドシートで作成された CSV ファイルを読み込むには, MATLAB 2013b で導入された readtable 関数を使うのが最もよい方法だと思います. コマンドウィンドウで,


T = readtable('shidouhou.csv', 'Encoding', 'Shift-JIS')

とキーインしてください.下図のように,table 型 という構造のデータが変数 T に保存されます. 第1行は CSV ファイルの1行目に記録されていた変数名です.

readtable function

各列の変数にアクセスするには, table 型のデータが保存されている変数名 T と,データ中の変数名をドット(.)でつなぎます. たとえば,変数 math にアクセスするには,


T.math

とキーインします.変数 math には数学の好き嫌いが,stat には統計学の好き嫌いが記録されています. こうしたカテゴリカル変数にアクセスすると,セル配列という構造で測定値の集合が得られます.

cell array

数学と統計学それぞれについて,好きと嫌いの度数をひとつの座標軸での棒グラフにしてみましょう, これは「対応のあるデータ」(2変数の測定値は同一の人から得られている)なので, データの視覚化の方法としてはクロス集計表やモザイク・プロットの方が適切ですが, ここでは棒グラフを描画する練習をします.

「好き」および「嫌い」の度数をカウントするには, categorical 関数を使ってセル配列をカテゴリカル配列に変換した後で, countcats 関数を使うことがひとつの方法です. コマンドウィンドウで,


C = {'嫌い', '好き'};
Math = categorical(T.math, C, 'Ordinal', true);
Stat = categorical(T.stat, C, 'Ordinal', true);

MCnts = countcats(Math)
SCnts = countcats(Stat)

と順にキーインしてください. ここでは,「好き」と「嫌い」に順序をつけて, 「好き」の方が「嫌い」よりも大きいとしました. それが categorical 関数での 'Ordinal', true という指定です. 順序は変数 C に保存してあります. これで,下図のように計数ができました.

countcats function

あとは bar 関数で棒グラフを描画するだけです. ここまでコマンドウィンドウで入力してきたコードを含め, プログラム全体を以下に示します.


T = readtable('shidouhou.csv', 'Encoding', 'Shift-JIS');

C = {'嫌い', '好き'};
Math = categorical(T.math, C, 'Ordinal', true);
Stat = categorical(T.stat, C, 'Ordinal', true);

MCnts = countcats(Math);
SCnts = countcats(Stat);

bar(categorical(C), [MCnts SCnts]);
set(gca, 'YLim', [0 20]);
ylabel('度数');
legend('数学', '統計学');

このプログラムを実行すると,以下の棒グラフが描画されます.

an example of bar chart

5.5.6 円グラフ:pie

円の面積は 1 であるとします.

円グラフであらわすデータ Y を,合計が 1 になるように与えると, 扇形の面積を直接に指定したことになります. たとえば,


Y = [1 2 3 4 5] ./ 15;
pie(Y);

とすると,円の12時の位置から反時計回りに,面積が 1/15, 2/15, 3/15, 4/15, 5/15 の扇形が描画されます.

円グラフであらわすデータ Y の合計が 1 を超える場合は, データ Y の構成要素は,合計 sum(Y) に占める割合に変換され, 扇形の面積が決められます. たとえば,


Y = [1 2 3 4 5];
pie(Y);

とすると,データを Y = [1 2 3 4 5] ./ 15; とした場合と同じ結果になります.

5.5.5 節で,データを保存した CSV ファイル( 指導法データ )を読み込んで棒グラフを描画しました. 同じデータを使用して円グラフを描画するプログラムを以下に示します.


T = readtable('shidouhou.csv', 'Encoding', 'Shift-JIS');

C = {'嫌い', '好き'};
Math = categorical(T.math, C, 'Ordinal', true);
Stat = categorical(T.stat, C, 'Ordinal', true);

subplot(2, 1, 1);
pie(Math);
title('数学');

subplot(2, 1, 2);
pie(Stat);
title('統計学');

このプログラムを実行すると,以下の円グラフが描画されます.

an example of pie chart

5.5.7 ヒストグラム:hist

ヒストグラムの描画に使用されていた hist 関数は, 現在の MATLAB では推奨されていません. かわりに,histogram 関数を使用することが推奨されています. とはいえ,まずは例題 ex5507 で hist 関数の使い方を見ておきましょう.

ヒストグラムに描画するデータは,ある範囲の実数値すべてをとりうる,連続型変数のデータです. 取りうる値の範囲をいくつかの階級に分割し, 各階級に属する測定値の数を柱の高さ(正確には,柱の面積)で表したグラフを描画します.

階級は,階級の数を整数で指定するか,階級の中心をベクトルで指定して決定します. 例題 ex5507 では階級の中心を X = -3:0.5:3; と指定しています.

データはベクトルまたは行列で与えます. データが行列の場合は, bar 関数と同様に,各列がひとつの系列(カテゴリ)に対応します. 例題 ex5507 では標準正規分布に従う乱数でデータ行列 Y を生成しています. データは階級に分類されるので,bar 関数のようにグラフの高さを与えるのではないということに注意してください.

例題 ex5507 での hist 関数を,現在の MATLAB で推奨されている histogram 関数に置き換えると, 下図のヒストグラムが描画されます.データとして与えた行列 Y は, 列ごとに区別はされず,全体がひとつのデータとなります. 例題 ex5507 で描かれているようなヒストグラムは, histogram 関数では描画されません.

histogram

細かいことですが重要な変更点として, hist 関数では階級の中心を第2の引数で指定しましたが, histogram 関数では階級の境界値を指定します. 上図での階級の境界が X = -3:0.5:3; で与えられていることを確認してください.

男女別など,異なったカテゴリのデータを分けたヒストグラムを描きたければ, 5.1.4 節で学習した hold 関数を利用して,ヒストグラムを重ねて描画します. 以下のプログラムを実行してください.


X = -5:0.2:7;
Y = randn(10000, 3);
histogram(Y(:,1), X); hold on
histogram(Y(:,2) + 1, X);
histogram(Y(:,3) + 2, X); hold off
set(gca, 'YLim', [0 1000]);
xlabel('X');
ylabel('Frequency');

下図のようなヒストグラムが得られます.

histogram

5.5.5 節および 5.5.6 節で使用した 指導法データ に含まれている,psych_test という変数の測定値の分布をヒストグラムで表示してみましょう. これは心理学のテストのスコアです(仮想データです). 以下のプログラムを実行してください


T = readtable('shidouhou.csv', 'Encoding', 'Shift-JIS');

Xedges = 2.5:17.5; % 階級の境界値
histogram(T.psych_test, Xedges);

set(gca, 'YLim', [0 5], 'YTick', 0:5);
xlabel('Test Score');
ylabel('度数');

下図のヒストグラムが得られます.

histogram

5.5.8 線図形を描く:line

例題 ex5508 では5つの点を結んだ7本の折れ線を描いていますので, 図が複雑になっていて, line 関数の使い方がわかりにくいと思います. 描く線分を単純にして,数は2本だけにしてみましょう. コマンドウィンドウで,


X = [0 1; 1 2]'
Y = [0 1; 3 4]'
line(X, Y)

と入力してください.X と Y はコマンドウィンドウに出力されます.

two lines

Figure ウィンドウには下図のように線分が描画されます.

two lines drawed in Figure winodw

下側の線分は 0 0 1 1 を結んでいます.これら2点の座標は X と Y の1列目に与えられています.

上側の線分は 1 3 2 4 を結んでいます.これら2点の座標は X と Y の2列目に与えられています.

中学校や高等学校での数学で出てくる図形の多くは, line 関数や plot など,図形を描画する関数を組み合わせて描くことができます. たとえば,以下のプログラムは, 2022年度大学入試共通テスト数学II・B第1問での, 問題の状況を描きます.(受験生はこれをフリーハンドで描いたことでしょう)


t = linspace(0,2*pi,100);
cx = 2; cy = 5; % 円の中心
r = 5;          % 半径
plot(r*sin(t)+cx, r*cos(t)+cy)
axis([-10,10,-5,15])
axis square

hold on;

line([-8 8]', [0 0]') % 傾き0の接線
line([-8 ((-8) + 3*3.5)]', [0 (0 + 4*3.5)]')
   % 傾き 4/3 の接線
line([2 2 -8]', [0 5 0]')
   % 三角形の描画 tan(theta) = 1/2

text(-8.5, -0.5, 'A(-8, 0)')
text(2.5, 5.5, 'Q(2, 5)')
text(1.5, -0.5, '(2, 0)')
text(-6, 0.5, '\theta')
text(-6.5, 1.5, '\theta')
text(2.5, 13, '$ y = k_{0}(x+8) $', 'Interpreter','latex')

hold off;

このプログラムを実行すると以下の図が描かれます.

2022 共通テスト 数学II・B 第1問

例題 ex5508 のプログラム1行目と2行目では,6行目の line 関数に引数として渡される行列 X および Y の要素として,

T = 0 2 5 π 4 5 π 6 5 π 8 5 π
CT = cos 0 cos 2 5 π cos 4 5 π cos 6 5 π cos 8 5 π
ST = sin 0 sin 2 5 π sin 4 5 π sin 6 5 π sin 8 5 π

という3つの列ベクトル(要素を縦に並べたベクトル)を作っています.

プログラムの3行目と4行目を


X = [CT];
Y = [ST];

として,どのような図形が描かれるかを観察してみましょう. これは5つの点 cos 0 sin 0 cos 2 5 π sin 2 5 π cos 4 5 π sin 4 5 π cos 6 5 π sin 6 5 π cos 8 5 π sin 8 5 π を結んでできる図形であり,以下のように描かれます.

ex5508

例題 ex5508 では,これら5つの点の座標値を0.9倍した点を結んだ図形,0.8倍した点を結んだ図形, ・・・,0.4倍した点を結んだ図形を描いています.もとの座標値が -1 から +1 の間の値をとっていますから, 最初の図形から見ると原点 0 0 に向かって縮小されていく図形が描かれることになります.

例題 ex5508 のプログラム最終行の


box on

は座標軸の外枠を描く指示です.この最終行を省略したプログラムを実行して,違いを確認してください.

5.5.9 塗りつぶした図形を描く:fill

例題 ex5509 の実行結果は p.175 の図です. 図の右下の ex5409 は誤植で,ex5509 が正しいです.

例題 ex5509 のプログラムは図形の塗りつぶしを繰り返すので, fill 関数の動作が少しわかりにくいと思います. 簡略化した以下のプログラムを実行してみてください.


T = ((2*pi/5)*(0:4))';
CT = cos(T);
ST = sin(T);

axis([-1.5, 1.5, -1.5, 1.5]);
axis square;
box on;

hold on;

    X = CT;
    Y = ST;
    fill(X, Y, 'b');

hold off

下のような図形が描かれます.

a simplified version of ex5509

これは5つの点 cos 0 sin 0 cos 2 5 π sin 2 5 π cos 4 5 π sin 4 5 π cos 6 5 π sin 6 5 π cos 8 5 π sin 8 5 π を結んでできる図形(正5角形です)を描き,その内部を青色で塗りつぶしたものです. テキストで説明されているように,line 関数の場合と異なり,終点 cos 8 5 π sin 8 5 π は始点 cos 0 sin 0 と結ばれて,多角形が描画されます.

例題 ex5509 のプログラムには,for ループでの図の描画に冗長な部分があります. このプログラムを実行した後,下図のように, fill 関数に引数として与えられている変数 X および Y の内容をコマンドウィンドウで確認してみましょう.

variables X and Y at the end of the for loop

繰り返しを制御している変数 I の値は,1回目のループでは 8 であり. そこからひとつずつ減少して.最後のループでは 3 になっています. したがって,プログラム6行目の式に I = 3 を代入すると,


X = [0.3*CT 0.4*CT];
Y = [0.3*ST 0.4*ST];

となります.これが上図に示されている X および Y です. いずれも5行2列の行列です.

プログラム7行目では,これら2つの行列 X および Y を fill 関数に渡しています. 塗りつぶしの色は C(1) ですから 'y' すなわち yellow です. 一般に,fill 関数で描画する多角形を決める引数 X および Y が行列のとき, 第1列から列ごとに多角形が描かれ,その内部が塗りつぶされます. したがって,この例題では


X = [0.3*CT];
Y = [0.3*ST];

によって決まる正5角形の内部が塗りつぶされた後,


X = [0.4*CT];
Y = [0.4*ST];

によって決まる正5角形の内部が塗りつぶされます. 後で描かれたこの正5角形は,最初に描かれた正5角形を内部に含んでいます. 最初に描かれた正5角形は,その内部も含め, 後で描かれた正5角形によって完全に塗りつぶされます. したがって,最初の正5角形の描画は不要で, 後の正5角形の描画とその内部の塗りつぶしだけでよいことになります. そうすると,この例題の for ループは冗長で,次のように書けばよいことになります.


for I = 9:-1:4
    X = [0.1*I*CT];
    Y = [0.1*I*ST];
    fill(X, Y, C(I-3));
end

テキストでの例題 ex5509 のプログラムを実行した結果と, このように冗長性を修正したプログラムを実行した結果を比較して, 描画される図形が同じであることを確かめてください. 描画された多角形の頂点にマウスのポインタをあわせると, 下図のように,その頂点の座標が表示されます.

a vetex (0.9, 0) of the polygon

a vertex (0.4, 0) of the polygon

5.5.10 計算しながら表示する:pause

例題 ex5510 のプログラムは,例題 ex5509 のプログラムに, pause 関数を使用する1行を加えただけのものです. 5.4.10 節(p.175)に示されている図は例題 ex5509 の出力ですが, 例題 es5510 の最終的な出力も同じです.

この図のすぐ下の行での「ex5409 を修正して」は誤植で, 「ex5509 を修正して」が正しいです.

引数なしで pause 関数を用いると.任意のキーを押すまでプログラムの実行が停止されます. 例題 ex5510 のプログラム8行目を


pause()

あるいは


pause

に変更して実行してみてください. 一時停止を解除してプログラムの実行を進めるには,何かキーを押します. 最後の for ループで黄色での多角形の塗りつぶしが終わると, プログラムは8行目で停止します. プログラムを最後まで実行して終了するには,もう一度何かキーを押す必要があります. そうすると,コマンドウィンドウでは, プログラム実行中は表示されていなかったコマンドプロンプト(>>)が表示されます.