Как получить бары с функцией bar3 и разной шириной для каждого бара?

У меня есть код:

values = [1.0 0.6 0.1;  0.0 1.0 0.3;  0.9 0.4 1.0];
h = bar3(values);
shading interp
for i = 1:length(h)
    % Get the ZData matrix of the current group
    zdata = get(h(i),'Zdata');
    set(h(i),'Cdata',zdata)
end
set(h,'EdgeColor','k')
view(-61, 68);
colormap cool
colorbar

И вот как выглядит цифра:

enter image description here

Я хочу получить разную ширину для каждого бара в зависимости от высоты бара.

Я хочу выглядеть как картинка в http://www.sdtools.com/help/ii_mac.html.

blah http://www.sdtools.com/help/mac.gif

Ответ 1

Это было немного трудно понять, но это легко, как только вы получите шаблон. Свойства 'XData' и 'YData' для каждого h(i) являются матрицами, которые определяют ширину x и y каждой панели. Каждая группа из 6 строк этих матриц определяет бар. Итак, трюк заключается в изменении 'XData' и 'YData' в соответствии с values.

values = [1.0 0.6 0.1;  0.0 1.0 0.3;  0.9 0.4 1.0];
h = bar3(values);
m = max(values(:))*2; %// normalizing constant for bar width
shading interp
for i = 1:length(h)
    % Get the ZData matrix of the current group
    xdata = get(h(i),'Xdata');
    ydata = get(h(i),'Ydata');
    zdata = get(h(i),'Zdata');
    set(h(i),'Cdata',zdata)
    for k = 1:6:size(xdata,1)
        xdatak = xdata(k+(0:5),:);
        xdatak = round(xdatak)+sign(xdatak-round(xdatak))*values(ceil(k/6),i)/m;
        xdata(k+(0:5),:) = xdatak;
        ydatak = ydata(k+(0:5),:);
        ydatak = round(ydatak)+sign(ydatak-round(ydatak))*values(ceil(k/6),i)/m;
        ydata(k+(0:5),:) = ydatak;
    end
    set(h(i),'XData',xdata);
    set(h(i),'YData',ydata);
end
set(h,'EdgeColor','k')
view(-61, 68);
colormap cool
colorbar

enter image description here

Обратите внимание, что приведенный выше код масштабирует линейный размер (ширина) в соответствии с values. Для масштабирования используйте квадратный корень values:

values = [1.0 0.6 0.1;  0.0 1.0 0.3;  0.9 0.4 1.0];
h = bar3(values);
svalues= sqrt(values);
m = max(svalues(:))*2; %// normalizing constant for bar width
shading interp
for i = 1:length(h)
    % Get the ZData matrix of the current group
    xdata = get(h(i),'Xdata');
    ydata = get(h(i),'Ydata');
    zdata = get(h(i),'Zdata');
    set(h(i),'Cdata',zdata)
    for k = 1:6:size(xdata,1)
        xdatak = xdata(k+(0:5),:);
        xdatak = round(xdatak)+sign(xdatak-round(xdatak))*svalues(ceil(k/6),i)/m;
        xdata(k+(0:5),:) = xdatak;
        ydatak = ydata(k+(0:5),:);
        ydatak = round(ydatak)+sign(ydatak-round(ydatak))*svalues(ceil(k/6),i)/m;
        ydata(k+(0:5),:) = ydatak;
    end
    set(h(i),'XData',xdata);
    set(h(i),'YData',ydata);
end
set(h,'EdgeColor','k')
view(-61, 68);
colormap cool
colorbar

В любом из вышеперечисленных, если вы хотите, чтобы все столбцы с равной высотой просто заменили вторую строку на

h = bar3(ones(size(values)));

Или, если вы предпочитаете 2D-просмотр, используйте

view(-90,90) %// view from above
axis equal %// set the same scale in x and y

enter image description here

Ответ 2

Просто для удовольствия это двумерное решение проблемы:

values=values./max(values(:)); % normalize to 1
cmap=cool(numel(unique(values(:)))); % set color map range
hold on
for n=1:numel(values)
    [x y]=ind2sub(size(values),n);
    revec(n,:)=[x-0.5*values(n) y-0.5*values(n) values(n) values(n)];
    try
        rectangle('Position',revec(n,:),'FaceColor',cmap( round(values(n)*size(cmap,1)),:))
    end
end

enter image description here