Octave で waterfall 風グラフを作成:実践プログラミング例

2025-04-26

Octaveにおける「waterfall」は、3次元のデータを視覚的に表現するためのプロットの一種です。具体的には、複数の2次元のラインプロットを奥行き方向にずらして表示することで、全体として滝が流れ落ちるような見た目になることからこの名前が付けられました。

主な特徴と用途

  • 見やすさ
    重なり合う可能性のある複数の2次元プロットを奥行き方向に分離することで、個々のラインの変化を比較的容易に追跡できます。
  • 奥行きによる表現
    各ラインプロットは異なる奥行きに配置されるため、データの変化を立体的に見ることができます。
  • 時間変化の表現
    特に、ある量が時間とともにどのように変化していくかを視覚的に捉えるのに適しています。例えば、信号の周波数成分の時間的な変化などを表現できます。
  • 3次元データの可視化
    waterfall関数は、3つの変数を持つデータ(例えば、時間、周波数、振幅など)の関係性を把握するのに役立ちます。

基本的な使い方 (Octaveのコマンド)

% サンプルデータの作成
x = 1:10;
y = 1:5;
Z = zeros(length(y), length(x));
for i = 1:length(y)
  Z(i,:) = sin(0.5*x + i);
end

% waterfallプロットの作成
waterfall(x, y, Z);

% ラベルやタイトルなどの追加 (必要に応じて)
xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸");
title("Waterfallプロットの例");
  1. データの作成 (x, y, Z)

    • xyは、それぞれ横軸と奥行き方向の座標を表すベクトルです。
    • Zは、各(x, y)の組み合わせに対応する高さ(z軸の値)を表す行列です。この例では、正弦波の値を奥行き方向に少しずつずらして作成しています。
  2. waterfall(x, y, Z)

    • この関数がwaterfallプロットを作成する主要なコマンドです。
    • xyZは、それぞれデータの座標を指定します。
  3. ラベルとタイトル (xlabel, ylabel, zlabel, title)

    • これらのコマンドは、プロットに軸ラベルやタイトルを追加して、内容をより分かりやすくするために使用されます。
  • カラーマップを変更することで、色の表現を変えることもできます。
  • プロットの見え方は、データの形状や視点の角度によって大きく変わります。viewコマンドなどを使って視点を調整することも可能です。
  • waterfall関数は、MATLABにも同様の機能が存在します。


よくあるエラーとトラブルシューティング

    • エラー
      error: invalid call to waterfall のようなエラーメッセージが表示される。
    • 原因
      waterfall 関数に渡す引数の数が間違っている場合によく起こります。通常、waterfall(x, y, Z) のように、横軸のベクトル x、奥行き方向のベクトル y、高さの行列 Z の3つの引数を指定する必要があります。
    • トラブルシューティング
      • help waterfall コマンドを実行して、正しい引数の数と型を確認してください。
      • xyZ の変数が定義されており、適切なサイズとデータ型を持っているか確認してください。
  1. 引数のサイズの不一致

    • エラー
      error: meshgrid: arguments X and Y must be vectors (meshgridのエラーですが、内部で関連している場合があります) や、プロットが正しく表示されない。
    • 原因
      • x ベクトルの長さが Z 行列の列数と一致しない。
      • y ベクトルの長さが Z 行列の行数と一致しない。
    • トラブルシューティング
      • size(Z)length(x)length(y) を実行して、それぞれのサイズを確認してください。
      • Z の次元が length(y) x length(x) になっているか確認してください。
      • データの生成過程で、インデックスの範囲などが間違っていないか確認してください。
  2. Z が行列でない

    • エラー
      error: waterfall: Z must be a matrix のようなエラーメッセージが表示される。
    • 原因
      高さのデータ Z がベクトルやスカラなど、行列でない場合に発生します。
    • トラブルシューティング
      • whos Z コマンドを実行して、Z のクラスとサイズを確認してください。Z が行列 (matrix) である必要があります。
      • データの生成方法を見直し、Z が適切な形状の行列になるように修正してください。
  3. x または y がベクトルでない

    • エラー
      error: waterfall: X and Y must be vectors のようなエラーメッセージが表示される。
    • 原因
      横軸または奥行き方向の座標データ x または y がベクトルでない場合に発生します。
    • トラブルシューティング
      • whos x および whos y コマンドを実行して、それぞれのクラスとサイズを確認してください。これらはベクトル (vector) である必要があります。
      • データの生成方法を見直し、xy が適切な形状のベクトルになるように修正してください。
  4. データの範囲が適切でない

    • エラー
      エラーメッセージは表示されないが、プロットが見にくい、または意図した形状と異なる。
    • 原因
      データの値の範囲が広すぎる、または狭すぎる場合に、プロットのスケールが適切でなくなり、詳細が分かりにくくなることがあります。
    • トラブルシューティング
      • min(Z(:))max(Z(:)) などを使って、データの最小値と最大値を確認してください。
      • 必要に応じて、データのスケーリングや正規化を行うことを検討してください。
      • xlimylimzlim コマンドを使って、軸の表示範囲を明示的に設定してみてください。
  5. 視点の調整が不適切

    • エラー
      エラーメッセージは表示されないが、プロットの立体感が分かりにくい。
    • 原因
      デフォルトの視点では、データの形状が把握しにくい場合があります。
    • トラブルシューティング
      • view(az, el) コマンドを使って、方位角 (azimuth) と仰角 (elevation) を調整してみてください。色々な角度からプロットを見ることで、データの構造をより理解しやすくなります。
      • rotate3d on コマンドを有効にして、マウスでインタラクティブに視点を回転させることもできます。
  6. カラーマップの問題

    • エラー
      エラーメッセージは表示されないが、色の変化がデータの変化を適切に表現していない。
    • 原因
      デフォルトのカラーマップが、データの特性に適していない場合があります。
    • トラブルシューティング
      • colormap(map) コマンドを使って、別のカラーマップを試してみてください。例えば、colormap(jet)colormap(gray) などがあります。
      • 必要に応じて、colorbar コマンドを使ってカラーバーを表示し、色の意味を確認してください。

一般的なトラブルシューティングのヒント

  • コードを段階的に実行し、変数の値を確認する
    問題が発生していると思われる箇所の前後の変数の値を disp() コマンドなどで表示させて、意図した値になっているか確認します。
  • ドキュメントやオンラインリソースを参照する
    Octaveの公式ドキュメントやオンラインのフォーラム、コミュニティなどで、同様の問題に遭遇した人がいないか検索してみるのも有効です。
  • help コマンドを活用する
    関数の使い方や引数に関する情報は、help waterfall のように help コマンドで確認できます。
  • 簡単なデータで試す
    まずは小さな簡単なデータを作成して waterfall プロットが正しく動作するか確認し、問題がデータにあるのか、コードにあるのかを切り分けます。
  • エラーメッセージをよく読む
    Octaveのエラーメッセージは、問題の原因を示唆していることが多いです。


基本的な waterfall プロットの例

% 例1: 基本的な waterfall プロット

% データの作成
x = 1:20;
y = 1:10;
Z = zeros(length(y), length(x));
for i = 1:length(y)
  Z(i,:) = sin(0.3*x + i*0.5) * exp(-x/30);
end

% waterfall プロットの作成
figure; % 新しい Figure ウィンドウを開く
waterfall(x, y, Z);

% ラベルとタイトルの追加
xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸 (振幅)");
title("基本的な Waterfall プロット");

% グリッドの追加
grid on;

% 視点の調整 (見やすい角度に)
view(30, 30);

説明

  • view(30, 30) は、プロットの視点を方位角 30 度、仰角 30 度に設定しています。これにより、3次元的な構造が見やすくなります。
  • grid on は、プロットにグリッド線を追加して見やすくします。
  • xlabel, ylabel, zlabel, title は、それぞれ軸ラベルとタイトルを設定します。
  • waterfall(x, y, Z) 関数が実際のプロットを生成します。
  • この例では、x 軸と y 軸の範囲を定義し、それに対応する Z 値(高さ)を計算しています。Zy のインデックス i に応じて少しずつ変化する正弦波と指数関数の積で構成されています。

異なる形状のデータを使った例

% 例2: ガウス分布の waterfall プロット

% データの作成
x = -5:0.5:5;
y = -5:0.5:5;
[X, Y] = meshgrid(x, y); % x と y の組み合わせを作成
Z = exp(-(X.^2 + (Y - 2).^2) / 5) + exp(-((X + 2).^2 + Y.^2) / 5);

% waterfall プロットの作成
figure;
waterfall(x, y, Z);

% ラベルとタイトルの追加
xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸 (高さ)");
title("ガウス分布の Waterfall プロット");

% カラーマップの変更
colormap(hot); % 暖色系のカラーマップを使用
colorbar;      % カラーバーを表示

% 視点の調整
view(-45, 45);

説明

  • colorbar は、色の濃淡が Z の値にどのように対応しているかを示すカラーバーを表示します。
  • colormap(hot) は、プロットの色を暖色系のカラーマップに変更します。
  • Z は、2つのガウス分布の和として計算され、中央付近と少しずれた位置にピークを持つ形状になります。
  • この例では、meshgrid 関数を使って xy のすべての組み合わせからなるグリッド (X, Y) を作成しています。

時間変化を表現する例

% 例3: 時間変化する信号のスペクトログラム風 waterfall プロット

% パラメータ設定
fs = 100;       % サンプリング周波数
t = 0:1/fs:5;   % 時間ベクトル
frequencies = 10:5:50; % 周波数成分

% スペクトルデータの生成 (時間とともに周波数成分が変化する信号を模擬)
S = zeros(length(frequencies), length(t));
for i = 1:length(frequencies)
  f = frequencies(i);
  amplitude = exp(-(frequencies(i) - 30)^2 / 200); % 中心周波数に近いほど振幅が大きい
  S(i,:) = amplitude * sin(2*pi*f*t + i*0.2);
end

% waterfall プロットの作成
figure;
waterfall(t, frequencies, abs(S)); % 時間を x 軸、周波数を y 軸、振幅を z 軸に

% ラベルとタイトルの追加
xlabel("時間 [秒]");
ylabel("周波数 [Hz]");
zlabel("振幅");
title("時間変化する信号のスペクトログラム (Waterfall)");

% 視点の調整
view(-60, 30);

説明

  • これは厳密なスペクトログラムではありませんが、waterfall を使って時間変化するデータの様子を表現する一例です。
  • waterfall(t, frequencies, abs(S)) では、時間を x 軸、周波数を y 軸(奥行き方向)、振幅の絶対値を z 軸としてプロットしています。
  • S は、各時間における各周波数成分の振幅を表す行列です。ここでは、簡単なサイン波を重ね合わせて模擬的に作成しています。
  • t は時間ベクトル、frequencies は考慮する周波数のベクトルです。
  • この例は、時間とともに信号の周波数成分がどのように変化するかを視覚化するようなイメージです。

プロットのカスタマイズ例

% 例4: ラインの色とスタイルをカスタマイズした waterfall プロット

% データは例1と同じ
x = 1:20;
y = 1:10;
Z = zeros(length(y), length(x));
for i = 1:length(y)
  Z(i,:) = sin(0.3*x + i*0.5) * exp(-x/30);
end

% waterfall プロットの作成とプロパティの変更
figure;
h = waterfall(x, y, Z); % waterfall オブジェクトのハンドルを取得

% 各ラインの色を個別に設定 (例として最初のラインを赤に)
h(1).EdgeColor = 'r';

% 全てのラインのラインスタイルを変更
for i = 1:length(h)
  h(i).LineStyle = '--'; % 破線にする
end

% その他のカスタマイズ (例: 面の色)
% waterfall(x, y, Z, 'FaceColor', 'interp', 'EdgeColor', 'k');

% ラベルとタイトルなどは例1と同じ
xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸 (振幅)");
title("カスタマイズされた Waterfall プロット");
grid on;
view(30, 30);
  • コメントアウトされている部分のように、waterfall 関数に直接プロパティ値を渡すことで、面の色 (FaceColor) やエッジの色 (EdgeColor) などを設定することも可能です。'interp' は、面の色を頂点の色から補間して滑らかに表示するオプションです。
  • ループを使って、全てのラインのラインスタイルを破線 ('--') に変更しています。
  • h(1).EdgeColor = 'r'; のようにして、特定のラインの色を変更できます。
  • h は、個々のラインプロットのオブジェクトを含む配列です。
  • この例では、waterfall 関数の戻り値としてプロットオブジェクトのハンドル h を取得しています。


mesh 関数とループ処理の組み合わせ

mesh 関数は、3次元のメッシュサーフェスを描画する関数です。waterfall のように、複数のラインを奥行き方向にずらして表示する効果を、ループ処理と mesh 関数を組み合わせることで実現できます。

% 代替手法1: mesh 関数とループ処理

% データは waterfall の例と同様
x = 1:20;
y = 1:10;
Z = zeros(length(y), length(x));
for i = 1:length(y)
  Z(i,:) = sin(0.3*x + i*0.5) * exp(-x/30);
end

figure;
hold on; % 複数のプロットを重ねて描画

for i = 1:length(y)
  % y 軸の値を固定して、x-z 平面上のラインを mesh で描画
  Y_slice = ones(size(x)) * y(i);
  mesh(x, Y_slice, Z(i,:));
end

hold off;

xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸 (振幅)");
title("mesh 関数を使った Waterfall 風プロット");
grid on;
view(30, 30);

説明

  • hold onhold off を使うことで、複数の mesh プロットを同じ Figure 上に重ねて表示します。
  • mesh(x, Y_slice, Z(i,:)) を呼び出すことで、特定の y の値における xZ の関係をラインとして描画します。mesh は通常メッシュ状の面を描画しますが、Y_slice が一定値なので、結果的にラインが描画されます。
  • 各ループ内で、y の値を固定したベクトル Y_slice を作成します。
  • この例では、y の各値に対してループ処理を行います。

利点

  • 必要に応じて、ラインだけでなく面として表現することも比較的容易です。
  • mesh 関数の柔軟性を活かせるため、ラインの色やスタイルなどをより細かく制御できる可能性があります。

欠点

  • パフォーマンスは、データのサイズやループの回数によって waterfall 関数と異なる可能性があります。
  • waterfall 関数に比べて、コードが少し冗長になる場合があります。

plot3 関数とループ処理の組み合わせ

plot3 関数は、3次元空間に線や点を描画する関数です。waterfall の各ラインを個別に plot3 で描画し、奥行き方向に少しずつずらすことで、同様の表現が可能です。

% 代替手法2: plot3 関数とループ処理

% データは waterfall の例と同様
x = 1:20;
y = 1:10;
Z = zeros(length(y), length(x));
for i = 1:length(y)
  Z(i,:) = sin(0.3*x + i*0.5) * exp(-x/30);
end

figure;
hold on;

for i = 1:length(y)
  % 各ラインを plot3 で描画し、y 軸方向にオフセット
  plot3(x, ones(size(x)) * y(i), Z(i,:));
end

hold off;

xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸 (振幅)");
title("plot3 関数を使った Waterfall 風プロット");
grid on;
view(30, 30);

説明

  • ones(size(x)) * y(i) は、x と同じサイズのベクトルで、すべての要素が現在の y の値になっているものです。これにより、各ラインが異なる y の位置に描画されます。
  • 各ループ内で、plot3(x, ones(size(x)) * y(i), Z(i,:)) を呼び出します。

利点

  • ラインのスタイル(色、線種、マーカーなど)を plot3 のオプションで細かく制御できます。
  • シンプルで直感的なコードで実現できます。

欠点

  • 面の表現は直接的にはできません。
  • mesh を使う方法と同様に、waterfall 関数に比べてコードが少し長くなる場合があります。

surf 関数と適切なデータの準備

surf 関数は、3次元のサーフェス(面)を描画する関数です。waterfall のようなラインの集合としてではなく、面としてデータを準備し、適切なカラーマップや表示設定を行うことで、似たような視覚効果を得ることができます。

% 代替手法3: surf 関数を使った Waterfall 風プロット

% データは waterfall の例と同様
x = 1:20;
y = 1:10;
Z = zeros(length(y), length(x));
for i = 1:length(y)
  Z(i,:) = sin(0.3*x + i*0.5) * exp(-x/30);
end

figure;
surf(x, y, Z);

% ラインを目立たせるための設定 (エッジの色を黒にするなど)
shading interp; % 面の色を滑らかに補間
set(gca, 'ZGrid', 'on'); % Z軸のグリッドを表示
set(gca, 'Box', 'on');   % 軸のボックスを表示

% 必要に応じてカラーマップを調整
colormap(jet);
colorbar;

xlabel("X軸");
ylabel("Y軸");
zlabel("Z軸 (振幅)");
title("surf 関数を使った Waterfall 風プロット");
view(30, 30);

説明

  • エッジの色を明示的に設定することで、waterfall のようなラインの印象を強めることも可能です(例:surf(x, y, Z, 'EdgeColor', 'k');)。
  • set(gca, 'ZGrid', 'on')set(gca, 'Box', 'on') は、グリッド線や軸のボックスを表示することで、構造を強調するのに役立ちます。
  • shading interp は、面の色を滑らかに補間し、個々のメッシュラインをあまり目立たなくする効果があります。
  • surf(x, y, Z) は、xyZ で定義されるサーフェスを描画します。

利点

  • カラーマップを柔軟に制御できるため、データの特性に応じた視覚化が可能です。
  • surf 関数は、より複雑な3次元形状を表現するのに適しています。
  • waterfall のような明確なラインの集合としての表現にするためには、追加の設定が必要になる場合があります。