How I obtain bars with function bar3 and different widths for each bar?
Asked Answered
Z

2

11

I have the code:

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

And this is what the figure looks like:

enter image description here

I want to obtain different widths for each bar dependent on the height of the bar.

What I want looks like a picture in http://www.sdtools.com/help/ii_mac.html.

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

Zymogenic answered 17/6, 2014 at 17:2 Comment(6)
+1 for reproducible (runnable) exampkleAssagai
This seems to be fine. You're scaling each bar according to the values. What are your doubts with this code?Tranquillize
@Tranquillize It seems that he doesnt want the Heigth of the bars changeable, but the x,y width insteadHooey
@AnderBiguri - That was not obvious in the OP's post. Thank you for clarifyingTranquillize
My aim is also to vary the size of each bar according to the Z value, which is between 0 and 1. As shown in this example: sdtools.com/help/ii_mac.htmlZymogenic
When I say "size" I mean the X and Y dimensions of the square, the area of the bar in a top viewZymogenic
A
7

This was a little hard to figure out, but it's easy once you get the pattern. The 'XData' and 'YData' properties of each h(i) are matrices that define the x- and y- width of each bar. Each group of 6 rows of those matrices defines a bar. So the trick is to modify 'XData' and 'YData' according to 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

Note that the above code scales linear size (width) according to values. To scale area just use the square root of 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

In either of the above, if you want all bars with equal height just replace the second line by

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

Or if you prefer a 2D view, use

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

enter image description here

Assagai answered 17/6, 2014 at 21:42 Comment(5)
Nice. I'm favouriting this. Well done both of you: Luis Mendo and natan.Tranquillize
Thank you all! I am very grateful, and very surprised at your speed and interest. Best regards and thank you very much againZymogenic
Hey Matlab CEO's! The pros are in SO, come and take them.Hooey
@user3749418 The question was a nice challenge :-)Assagai
@All. This should be submitted to Undocumented Matlab. This is awesome code.Tranquillize
W
4

Just for fun, this is a 2D solution of the problem:

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

Wain answered 17/6, 2014 at 21:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.