Help us understand the problem. What is going on with this article?

「棒グラフがソートされながらぬるぬる動くやつ」=bar chart raceをMATLABで作成してみた.

成果物:こんなgifアニメが作れます.

outFile.gif

こういう,「棒グラフで値がソートされながらぬるぬる動くやつ」,見たことないでしょうか?Bar chart raceとも呼ぶようです.順位変化がわかりやすいので作りたいなーとTwitterでつぶやいていたところ,反応をいただきました.以下の記事です.

ぬめぬめ動く棒グラフ Bar Chart Race を描いてみよう: 準備編

こちらを参考として(実はほぼ同じなのですが),時系列データを与えるとアニメーションgifファイルを作成するプログラムをMATLABで作成し,FileExchangeで公開しました.引用の作法など守っていただければばんばん使ってもらいたいです.
(QiitaもFileExchangeもこれが初投稿です)

barChartRace.m

基本のアイデア

基本アイデアは上記参考記事と同じなのですが,以下です.

  • h=barh(x,y) で棒グラフを描く.xが縦座標,yが横座標であること注意.
  • x, yをそれぞれ次の要素と補完(一次補完)して棒の位置と大きさを設定しなおし,再描画
    • ここで縦方向の幅の調整が必要.

ソースコード

main_barChartRace.m

データの生成と設定を行い,本体(barChartRace.m)を呼び出します.Optのメンバは全て設定しないと多分エラーになるので(本体内でエラー処理をサボっていますすいません),このコードで代入する値を変えて対処してください.縦方向の文字列,出力ファイル名を設定します.

データyは縦方向がデータ種ごと,横方向に時系列が並ぶようにしてください.1列目が0,全て正の値であることを想定しています.

main_barChartRace.m
clear
clc
close all

%% sample data
y=rand(10,6);y(:,1)=zeros(size(y(:,1)));
y=filter(1,[1 -1], y')';

% options
Opt.xTickLabelStrs=cell(size(y,1),1);
Opt.outFileName='outFile.gif';
Opt.xLabelStr='x';
Opt.yLabelStr='y';
Opt.titleStr='Title';
Opt.faceColor=[0,0,1];%'blue';


for n1=1:size(y,1)
    Opt.xTickLabelStrs(n1)={char('A'+(n1)-1)};
end

設定が終われば,以下の関数を呼ぶだけで指定した名前でgifファイルができ上がります.

barChartRace(y,Opt)

barChartRace.m

本体のMATLAB関数です.まずは縦方向のラベルと出力ファイル名を設定します.

barChartRace.m
xTickLabelStrs=Opt.xTickLabelStrs;  % tick labels (vertical)

if isequal(Opt.outFileName(end-3:end),'.gif')
    outFileName=Opt.outFileName; % output gif name
else
    outFileName=[Opt.outFileName '.gif']; % output gif name
end

データをソートして,縦方向の位置を算出します.

y=inData;
x=zeros(size(inData));
x(:,1)=(1:size(inData,1))';

for n1=2:size(inData,2)
    [val,ind]=sort(inData(:,n1),'ascend');
    for n2=1:size(ind,1)
        x(ind(n2),n1)=n2;
    end
end

新しいfigureを作成し,描画します.時刻間を適当な実秒数とフレーム数に割り当てて,1フレームずつ描画して出力ファイルに追加します.各フレームでの位置は隣接する時刻間の値を線形補完しています.

figure
hold on

grid on;
set(gca,'FontName','Arial','FontSize',10)
h=barh(x(:,1),inData(:,1),'stacked','FaceAlpha',0.5, 'EdgeColor','white');
h.FaceColor=Opt.faceColor;

xlim([0 max(max(h(1).YData)*1.2,1)])
ylim([0,size(inData,1)+1])
set(gca,'YTick',x(:,1),'YTickLabel',xTickLabelStrs(x(:,1)))
title(Opt.titleStr)
xlabel(Opt.xLabelStr)
ylabel(Opt.yLabelStr)

framesPerDataTick=24;
for k=2:size(y,2)

    for n1=0:framesPerDataTick
        tmp=((framesPerDataTick-n1)*x(:,k-1)+ (n1)*x(:,k))/framesPerDataTick;
        [val,ind]=sort(tmp);
        bWidth=min(diff(val));

        if bWidth>0.01
            h(1).XData= ((framesPerDataTick-n1)*x(:,k-1)+ (n1)*x(:,k))/framesPerDataTick;
            set(gca,'YTick',val,'YTickLabel',xTickLabelStrs(ind));

            h(1).YData=((framesPerDataTick-n1)*y(:,k-1)+ (n1)*y(:,k))/framesPerDataTick;
            set(h(1),'BarWidth',0.9/bWidth);
            % automatic scaling of horizontal axis
            xlim([0 max(max(h(1).YData)*1.2,1)])

            refresh(1)

        end
        [A,map] = rgb2ind(frame2im( getframe(gcf)),256);

        if k==2 && n1==0
            imwrite(A,map,outFileName,'gif','DelayTime',0.5);
        else
            imwrite(A,map,outFileName,'gif','writemode', 'append','delaytime',1/framesPerDataTick);
        end

    end
    for n1=1:4  %stop between time instant
        imwrite(A,map,outFileName,'gif','writemode', 'append','delaytime',1/framesPerDataTick);
    end
end
%padding final frame to display longer.
    imwrite(A,map,outFileName,'gif','writemode', 'append','delaytime',0.5);
end

1箇所ちょっとしたコツがあります.

        if bWidth>0.01

この部分ですが,縦方向の棒の幅を計算するとき,幅が小さすぎると描画がおかしくなってしまったので,ある程度幅があるときのみ描画しなおすこととしています.

アニメーションgifの作成方法についてはMATLAB公式をほぼそのまま利用しています.

imwrite

konakalab
名城大学理工学部情報工学科で教員をしています.過去の研究の経緯でほぼMATLABしか使えないユーザです.最近のテーマはスポーツ統計が多めです.
http://www-ie.meijo-u.ac.jp/~konaka/index.html
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした