粗大メモ置き場

個人用,たまーに来訪者を意識する雑記メモ

MATLAB figureの背景を分けて塗りつぶす (補題:3次Spline補間とPCHIPの比較)

完成図 と 目的

研究柄matlabで図を書くことが多いですが,稀にmatlabの背景領域に色を塗りたくなります。

要はこういうグラフが書きたいってわけ。
f:id:ossyaritoori:20161114205000p:plain

使う関数area()について

今回はarea()という関数を使います。

Referenceは以下のとおりです。
2 次元プロットの塗りつぶし領域 - MATLAB area - MathWorks 日本

今回は

area([X1 X2],[Y1 Y2],basevalue);

という形で使っていきます。
これは(X1 Y1)と(X2 Y2)と Y=baselineで囲む領域を塗るという意味です。

塗りつぶし用コードまとめ

他にも枠線を消したり,グリッドを前面に出したり,ゴニョゴニョした結果次のような感じになります。
以下の手順でplot可能ですが,これは見たい直線よりも先にplotする必要があります。
(2016年追記:gcaの'Children'の順番をいじることにより変更可能ですね)

ha=area([X1 X2],[Y1 Y2],baseline);         % 塗る範囲([X1 X2],[Y1 Y2])とbaselineの間
set(ha,'FaceColor',[1.0 1.0 0.9]);      % 塗りつぶし色指定:今回はクリーム色
set(ha,'LineStyle','none');             % 塗りつぶし部分に枠を描かない
set(gca,'layer','top');                 % gridを塗りつぶしの前面に出す
hAnnotation = get(ha,'Annotation');
hLegendEntry = get(hAnnotation','LegendInformation');
set(hLegendEntry,'IconDisplayStyle','off');     % legendに入れないようにする

従ってこの後に

hold on
plot(...)

grid on
grid off

とやることによって完成です。

しかしこのままだとベースラインが見えてしまったり,プロット範囲を手動で変更したりが結構面倒です。
そこでくりかえし使えるように以下のように関数化します。

関数化(注意点あり)

同期I氏によってもっと便利に使えるよう関数化を施されました。

  • 自動でプロット範囲を判別し,余計な所を塗らない点
  • Childrenのハンドラをいじることで表示の優先順を変えられるため,後付けでプロットできるようにした点

がアピールポイントになります。

丁寧にプログラム書く人は尊敬しますね。
僭越ながら少し手を入れさせてもらいました。
x軸の範囲だけ与えれば適当に色を塗ってくれる関数です。引数を追加することで細やかな配色も可能です。

2017/1/27 : 引数の順番を変えました。キモいけど必要な順にすることで余計な入力を省きます。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 2017/1/28 Y.R & T.I @ Univ.T
% Input : Xrange, color, Baseline, Yrange
%
% PX = [X1, X2];
% color : [red, green, blue], ex) 'm', 'c'
% PY = [Y1, Y2];
% Bace : Filled up above this value
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function Square_coloring(PX, color, PY, Bace )
hold on;

xlimit = get(gca, 'XLim');                                                  % デフォルトXレンジ設定
ylimit = get(gca, 'YLim');                                                  % デフォルトXレンジ設定
colordflt = [1.0 1.0 0.9];                                                  % デフォルト色:クリーム
if nargin<4, Bace = ylimit(1); end                                          % 以下,引数が足りない時に埋めます。
if nargin<3, PY = [ylimit(2), ylimit(2)]; end                               % 
if nargin<2, color = colordflt; end                                         % 
if nargin<1, PX = [xlimit(1), xlimit(2)]; end                               % 

Area_handle = area(PX , PY, Bace);                                          % 塗る範囲([X_1 X_2],[y1 y2])
hold off;                                                                   % 
set(Area_handle,'FaceColor', color);                                        % 塗りつぶし色
set(Area_handle,'LineStyle','none');                                        % 塗りつぶし部分に枠を描かない
set(Area_handle,'ShowBaseline','off');                                      % ベースラインの不可視化
set(gca,'layer','top');                                                     % gridを塗りつぶしの前面に出す
set(Area_handle.Annotation.LegendInformation, 'IconDisplayStyle','off');    % legendに入れないようにする
children_handle = get(gca, 'Children');                                     % Axisオブジェクトの子オブジェクトを取得
set(gca, 'Children', circshift(children_handle,[-1 0]));                    % 子オブジェクトの順番変更

set(gca,'Xlim',xlimit);							    % 表示の調整
set(gca,'Ylim',ylimit);							    %
end

使い方

最もよく使われるであろう使い方を以下に書きます。

figure;
plot(...)

Square_coloring([xmin xmax]);

注意点として,以下のコマンドでgridを

set(gca,'layer','top');

にしているのでEPS変換時にgridに線が潰されるという問題があります。


困った点・改善点 2017/2/12 :追記

したがって

set(gca,'layer','top');

を使わずに,alpha値を設定してareaを透過させることでこれを解決します。

なお,FaceAlphaのプロパティがAreaに追加されるのはMATLAB 2015bからなのでご注意。


なお,これも問題があって,
areaが図の軸の枠線に被ったりするんですよね…
適当なmargin=0.2%くらいをAreaから削ることによって解決していますが,非常にキモイ。
graphicのサイズから削る量を計算するのがベストですが読みにくい記述の入るのは確実。

f:id:ossyaritoori:20170212010926p:plain:w300


なおコードは以下の通り。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 2017/1/28 Y.R & T.I @ Univ.T
% Input : Xrange, color, Baseline, Yrange
%
% ## Need version after MATLAB 2015b ##
% 
% PX = [X1, X2];
% color : [red, green, blue], ex) 'm', 'c'
% PY = [Y1, Y2];
% Bace : Filled up above this value
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function Square_coloring(PX, color, PY, Bace )
hold on;

xlimit = get(gca, 'XLim');                                                  % デフォルトXレンジ設定
ylimit = get(gca, 'YLim');                                                  % デフォルトXレンジ設定
colordflt = [1.0 1.0 0.9];                                                  % デフォルト色:クリーム

margin = 0.002*(ylimit(2)-ylimit(1));                                       % 見栄えのためAreaの塗る範囲を少し削ります

if nargin<4, Bace = ylimit(1) + margin; end                                 % 以下,引数が足りない時に埋めます。
if nargin<3, PY = [ylimit(2) - margin, ylimit(2) - margin]; end             % 本来の領域よりmargin=0.2%分縦に削って埋めています。
if nargin<2, color = colordflt; end                                         % 
if nargin<1, PX = [xlimit(1), xlimit(2)]; end                               % 

Area_handle = area(PX , PY, Bace,'FaceAlpha',0.5);                          % 塗る範囲([X_1 X_2],[y1 y2])
                                                                            % alpha値 0.5にします
hold off;                                                                   % 
set(Area_handle,'FaceColor', color);                                        % 塗りつぶし色
set(Area_handle,'LineStyle','none');                                        % 塗りつぶし部分に枠を描かない
set(Area_handle,'ShowBaseline','off');                                      % ベースラインの不可視化
set(gca,'layer','bottom');                                                  % gridを塗りつぶしの前面に出す
set(Area_handle.Annotation.LegendInformation, 'IconDisplayStyle','off');    % legendに入れないようにする
children_handle = get(gca, 'Children');                                     % Axisオブジェクトの子オブジェクトを取得
set(gca, 'Children', circshift(children_handle,[-1 0]));                    % 子オブジェクトの順番変更

set(gca,'Xlim',xlimit);							    % 表示の調整
set(gca,'Ylim',ylimit);							    %
end

補題:spline補間とPCHIP補間

matlabの3次スプライン補間とPCHIP補間で遊んだものに使ったコードを乗せておきます。
splineに食わせる時は境界条件を忘れないようにしましょう。

close all
% spline and PCHIP
x = -3:3;
y = [-1 -1 -1 0 1 1 1];
t = -3:.01:3;
p = pchip(x,y,t);
s = spline(x,[0 y 0],t);

% plot
figure(1)


% plot line
plot(x,y,'o',t,p,'-',t,s,'-.')
legend('data','pchip','spline','Location','SouthEast')
xlabel('time[s]');
ylabel('$\frac{d}{dt}\xi_{ref}$','Interpreter','latex'); 
grid on

Square_coloring([0 3]);

補間のお勉強用に資料へのリンクをば。
B-Spline 近似 - 大人になってからの再学習