MATLAB ユーザーコミュニティー

MATLAB & Simulink ユーザーコミュニティー向け日本語ブログ

MATLAB グラフィックス オブジェクトのいろは

皆さんこんにちは、トレーニングチームの遠藤です。

昨年末ゲーミング PC を買ったのですが、今までスペックギリギリで動いていたゲームがサクサク動くので、恥ずかしながら最近はゲーム三昧の自堕落な生活を送っています。最近のゲームはどれもグラフィックスがキレイなので、ゲームの世界に入り込んでいるような感覚になってしまいますよね……。

ということで、今回は「グラフィックス」繋がりで、MATLAB のグラフィックスの根幹を担っている「グラフィックス オブジェクト」についての技術記事になります!

目次

  1. 「グラフィックス オブジェクト」とは?
  2. グラフィックス オブジェクトの階層
  3. ハンドルとプロパティ
  4. グラフィックス オブジェクトの検索
  5. 応用例
  6. まとめ

1. 「グラフィックス オブジェクト」とは?

グラフィックス オブジェクトとは、MATLAB 上で可視化を行うために用意されているオブジェクト群のことです。例えば、皆さんもよく使っているであろう plot 関数によって描画されるグラフもこのグラフィックス オブジェクトに該当します。

t = 0:0.1:10;
y1 = sin(t);
y2 = cos(t);
plot(t, y1, t, y2)

他にも、画像を表示する image や文字を表示する text などもこのグラフィックス オブジェクトの一種です。MATLAB で可視化を行う際には必ず何かしらのグラフィックス オブジェクトを使うことになります。

さて、それでは今プロットしたグラフに対して以下のような操作を行おうとした場合、どうすればいいでしょうか?

  • グラフの線の太さや色を変える
  • 特定のグラフだけ消す
  • グラフに新しいデータを追加する

もちろん、プロットするコードを書き直してもう一度プロットする、といった解決方法もあるかもしれませんが、グラフィックス オブジェクトの扱い方がわかっていると、もっとスマートなやり方で可視化結果をカスタマイズできるようになります!

 

2. グラフィックス オブジェクトの階層構造

グラフィックス オブジェクトの細かい話に入る前に、簡単なクイズです。先ほど plot 関数を使ってサイン波とコサイン波のグラフをプロットしましたが、このとき MATLAB 上にはグラフィックスオブジェクトが何個存在しているでしょうか?

………

……

はい、それでは実際に確認してみましょう。findobj 関数を使うとグラフィックス オブジェクトのリストを取得できますので、表示してみます。

>> findobj

ans =

5×1 graphics 配列:

Root
Figure (1)
Axes
Line
Line

この通り、正解は 5 つになります。一見 2 本のグラフが描画されているだけですが、この時点で MATLAB 上には 5 つのグラフィックス オブジェクトが存在しているのです。何故 5 つもオブジェクトが作られているのでしょうか?

実は、グラフィックス オブジェクトは以下のような決められた階層構造を持っており、必ずこの構造の順番に従ってオブジェクトが作成されます(参照:グラフィックス オブジェクト)。

今回の場合、2 本のグラフは一番下の Char and Primitve Objects に該当します。そのため、その上に Root, Figure, Axes が作成され、合計 5 つのオブジェクトができた、というわけです。

それでは、これらのオブジェクトはそれぞれどのような役割を持ったオブジェクトなのでしょうか?順番に確認していきましょう。

Root オブジェクト

Root オブジェクトは、すべてのグラフィックス オブジェクトの大元となるオブジェクトで、MATLAB を起動した時点で自動的に1つだけ作成されています。groot 関数を使用すると、このオブジェクトにアクセスすることができます。

>> groot()

ans =

Graphics Root のプロパティ:

CurrentFigure: [1×1 Figure]
ScreenPixelsPerInch: 96
ScreenSize: [1 1 **** ****]
MonitorPositions: [2×4 double]
Units: 'pixels'

スクリーンやモニターに関する情報が入っていることがわかりますね。すべてのグラフィックス オブジェクトはこの Root オブジェクトの下に属することになります。

 

Figure (UI Figure) オブジェクト

グラフや画像などを描画する際に作られる Figure ウィンドウ(アプリの場合は UI Figure)です。単独で作成するには、figure (uifigure) 関数を使用します。

>> figure()

 

Axes (UI Axes) オブジェクト

Figure (UI Figure) ウィンドウ上に描画される座標軸です。単独で作成するには、axes (uiaxes) 関数を使用します。

>> axes()

 

Chart & Primitive オブジェクト

plot 関数や image 関数などで描画される、グラフや文字列、図形、画像などを指します。

t = 0:0.1:10;
y = sin(t);
plot(t, y)

 

このように、グラフィックス オブジェクトには決められた構造があり、それぞれのオブジェクトが固有の役割を持っているのです。

 

3. ハンドルとプロパティ

それでは、グラフィックス オブジェクトの構成についてなんとなくわかってきたところで、次は作成した各オブジェクトにアクセスする方法について確認していきましょう。

基本的に、グラフィックス オブジェクトの情報にアクセスするためには、そのオブジェクトの “ハンドル” が必要です。ハンドルとは、オブジェクトを参照するための変数のことで、グラフィックス オブジェクトの場合は figure , axes, plot などのオブジェクトを作成する関数の出力として返ってくる変数です。ハンドル自体は知らない方でも、以下のようなコードを見たことある方は結構多いんじゃないでしょうか?

>> p = plot(t,y)

p =

Line のプロパティ:

Color: [0 0.4470 0.7410]
LineStyle: '-'
LineWidth: 0.5000
Marker: 'none'
MarkerSize: 6
MarkerFaceColor: 'none'
XData: [0 … ] (1×101 double)
YData: [0 … ] (1×101 double)

このハンドル変数を使うと、各オブジェクトの情報(プロパティ)を取得・変更することができます。例えば、先ほどプロットしたグラフのラインの幅を変えたければ、上記の LineWidth プロパティを変更します。プロパティにアクセスするには、ドット表記を使います。

>> p.LineWidth = 2; % ラインの幅を 2 に変更

または get/set 関数を使ってプロパティを取得・変更することもできます。

>> set(p, "LineWidth", 2);

delete 関数にハンドル渡すことで、そのオブジェクトを削除することもできます。

>> delete(p); % ラインオブジェクトを削除

このように、あらかじめオブジェクト作成時にハンドル変数を作っておけば、それ以降のコードで簡単に各オブジェクトの情報を取得・変更できるのです。

 

ただし、ハンドル変数を使う上での注意点として、ハンドル変数はあくまでもオブジェクトを参照しているだけの変数で、オブジェクトそのものではありません。そのため、例えば以下のようにハンドル変数をコピー・クリアしてもオブジェクト自体は複製・削除されません。ショートカットをコピー・削除しても元のファイルはコピー・削除されないのと同じですね。

>> p2 = p; % 参照をコピーしてもオブジェクトはコピーされない
>> clear p % 参照をクリアしてもオブジェクトは削除されない

 

(補足)プロパティの調べ方

前述の通り、ハンドル変数とプロパティ名さえわかればグラフィックス オブジェクトの情報にアクセスできますが、もしプロパティ名がわからない場合はどうすればいいでしょうか?

各オブジェクトのプロパティの一覧は、”○○のプロパティ” というドキュメントで確認できます。例えば、Figure のプロパティは Figure のプロパティに載っています。このドキュメントはオブジェクトを作成する各関数のドキュメントの最下部のリンクからも開けるので、ぜひ覚えておきましょう!

 

4. グラフィックス オブジェクトの検索

前節のとおり、グラフィックス オブジェクトを作成する際にハンドル変数を定義しておけば、それを使って自由に情報にアクセスできました。それでは、もしハンドル変数を定義せずに作成したオブジェクトや自動で作られたオブジェクトにアクセスしたい場合はどうすればよいでしょうか?

このような場合、以下のようなグラフィックス オブジェクトを検索する機能を使うことで、特定のオブジェクトのハンドルを取得することができます。

・現在のオブジェクトの検索(gcf, gca, gco 関数)

gc から始まる関数を使うことで、最後にアクティブになった(クリックやキーボード操作で選択された)特定のオブジェクトを取得することができます。

  • gcf: Figure
  • gca: Axes
  • gco: グラフィックス オブジェクト

特に、Figure や Axes は自動で作られることが多いので、gcf, gcaを使ってアクセスする頻度が高いです。

>> set(gcf, "Position", [0 0 100 100]); % Figure の位置を変更

 

・特定のプロパティ値を持つオブジェクトの検索(findobj 関数)

findobj 関数を使うと、特定のプロパティ値を持つグラフィックス オブジェクトを検索することができます。

>> p = findobj("LineWidth",2)

p =

Line のプロパティ:

Color: [0 0.4470 0.7410]
LineStyle: '-'
LineWidth: 2
Marker: 'none'
MarkerSize: 6
MarkerFaceColor: 'none'
XData: [0 … ] (1×101 double)
YData: [0 … ] (1×101 double)

特に、各オブジェクトの Type プロパティにはそのオブジェクトの種類が格納されているので、これを使えば特定の種類のオブジェクトだけを取得することが可能です。

>> p = findobj("Type","Line") % Line オブジェクトだけ取得

また、各オブジェクトには共通して UserData というプロパティが用意されており、好きな値を入れておくことができます。そのため、ここにタグのようなものを仕込んでおけば、後々特定のタグをつけたオブジェクトだけを検索して消す、といったことも簡単にできます。

objs = findobj("UserData", "Group1");
delete(objs)

 

5. 応用例

最後に、これらの機能を使うとどんなことができるのか、いくつか代表例を紹介します。

①可視化アプリ

データの可視化アプリでは、グラフの表示・非表示を切り替えたり、色を変えたり、新たな可視化を行ったり、ユーザーの操作に応じてグラフィクス オブジェクトの操作が必要になります。このような場合、ハンドル変数が非常に重要になります。

 

②アニメーション

アニメーションを作成する場合、一定時間毎にグラフィックス オブジェクトのプロパティを取得・変更する必要があります。

例えば、色が変わりながら徐々にデータが増えていくプロットを作るコードは以下のようになります。

axis([0 10 -1 1])                  % 座標軸の範囲を事前に設定
h = animatedline;                  % AnimatedLine オブジェクトを作成
ts = 0.1;                          % 0.1秒周期で更新
time = 10;                         % 10秒間
t = 0:ts:time;                     % 横軸データ
y = sin(t);                        % 縦軸データ
red = 1/2*sin(t)+1/2;              % 赤を 0~1 で変化
green = 1-red;                     % 緑を赤と逆に変化
for i = 1:length(t)
    addpoints(h,t(i),y(i));        % データを追加
    h.Color = [red(i) green(i) 0]; % 色を変更
    pause(ts);                     % ts秒待機
end

animatedline 関数で AnimatedLine オブジェクトを作り、ループの中で addpoints 関数でデータを追加、Color プロパティの変更を行っています。

色を変化させながらウネウネ動くプロット(ゲーミングプロット)ができました!

 

③大量の Figure ウィンドウの管理

大量の Figure ウィンドウを管理しなければならない場合も、グラフィックス オブジェクトの知識が役立ちます。

rt = groot;                      % Root オブジェクトにアクセス
sc = rt.ScreenSize;              % スクリーンサイズを取得
scw = sc(3);                     % スクリーンの幅を取得
sch = sc(4);                     % スクリーンの高さを取得
w = scw/5;                       % Figure の幅はスクリーンの5分の1
h = sch/2;                       % Figure の高さはスクリーンの2分の1
t = 0:0.1:10;                    % 横軸データ(共通)
for i = 1:10
    f = figure;                  % 新しい Figure を作成
    x = w*mod((i-1),5);          % Figure の横の位置を計算
    y = h*floor((i-1)/5);        % Figure の縦の位置を計算
    f.OuterPosition = [x y w h]; % Figure の位置を設定
    y = sin(i*t);                % 縦軸データ
    plot(t,y)                    % プロット
end

 

※この例のように Figure を分ける必要がない場合は、1 つの Figure 上に tiledlayout 関数で複数グラフをプロットする方が管理もしやすくてオススメです。

 

6. まとめ

ということで、今回は MATLAB の可視化を裏で支えているグラフィックス オブジェクトについての技術記事でした。この記事では一部のオブジェクトだけの紹介でしたが、MATLAB には様々なグラフィックス オブジェクトが存在します。普段よく使うオブジェクトのプロパティ一覧を見るだけでも新しい発見があるかもしれませんので、ぜひ色々調べてみてください!

うまく活用すれば、ゲームだって作れちゃうかも……?

 

(おまけ)

作れちゃった例

|
  • print

コメント

コメントを残すには、ここ をクリックして MathWorks アカウントにサインインするか新しい MathWorks アカウントを作成します。

Loading...
Go to top of page