1

I am plotting a bar+scatter plot where the scatter points are colored according to a separate variable. The problem I am having is that the colorbar is using the wrong values at the moment. If I just plot the scatter plot and add a colorbar, then the range of the colorbar is correct.

I am using Matlab 2016a.

Please find a working example of the code below:

figure
subplot(2,1,1)
a = 1;
b = 2;
r = (b-a).*rand(1,7) + a;
y = r;
rr = (b-a).*rand(1,7) + a;
z = rr;
x = [1:7];
zz = rand(1,7)
yyaxis left
hold on
for i = 1:7
    h=bar(i,y(i), 'FaceColor',[1 1 1], 'LineWidth',3);
    yb(i) = cat(1, h.YData);
    xb(i) = bsxfun(@plus, h(1).XData, [h.XOffset]');
    if zz(i) < 0.0300000
        set(h,'EdgeColor','k');
    elseif zz(i) < 0.050000000
        set(h,'EdgeColor','b');
    elseif zz(i) < 0.070000000
        set(h,'EdgeColor','g');
    else
        set(h,'EdgeColor','r');
    end
end
ylabel('hm', 'FontSize', 12, 'FontWeight', 'bold')
for i1=1:7
    t = text(xb(i1)-0.2,yb(i1),num2str(yb(i1),'%0.3f'),...
        'HorizontalAlignment','center',...
        'VerticalAlignment','bottom')
    s = t.FontSize;
    t.FontSize = 12;
    t.FontWeight = 'bold';
end
yyaxis right
pointsize = 40;
hh = scatter(x,z,pointsize, zz,'filled')
cc = colormap([hsv(20)])
c = colorbar
c.Label.String = 'Pos';
set(gca,'Ydir','reverse')
ylabel('OK', 'FontSize', 12, 'FontWeight', 'bold')
lgd = legend([h, hh], 'hm', 'OK')
subplot(2,1,2)
x = [1:8]
a = 1;
b = 2;
r = (b-a).*rand(1,8) + a;
y = r;
rr = (b-a).*rand(1,8) + a;
z = rr;
zz = rand(1,8);
yyaxis left
hold on
for i = 1:8
    h=bar(i,y(i), 'FaceColor',[1 1 1], 'LineWidth',3);
    yb(i) = cat(1, h.YData);
    xb(i) = bsxfun(@plus, h(1).XData, [h.XOffset]');
    if zz(i) < 0.0300000
        set(h,'EdgeColor','k');
    elseif zz(i) < 0.050000000
        set(h,'EdgeColor','b');
    elseif zz(i) < 0.070000000
        set(h,'EdgeColor','g');
    else
        set(h,'EdgeColor','r');
    end
end
for i1=1:8
    t = text(xb(i1)-0.2,yb(i1),num2str(yb(i1),'%0.3f'),...
        'HorizontalAlignment','center',...
        'VerticalAlignment','bottom')
    s = t.FontSize;
    t.FontSize = 12;
    t.FontWeight = 'bold';
end
ylabel('hm', 'FontSize', 12, 'FontWeight', 'bold')
yyaxis right
pointsize = 40;
hh = scatter(x,z,pointsize, zz,'filled')
set(gca,'Ydir','reverse')
ylabel('OK', 'FontSize', 12, 'FontWeight', 'bold')
c = colorbar
c.Label.String = 'Pos';
lgd = legend([h, hh], 'hm', 'OK')
%title(lgd,'My Legend Title')
hold off

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Edit A working example of one solution to the question.

figure
a = 1;
b = 2;
r = (b-a).*rand(1,7) + a;
y = r;
rr = (b-a).*rand(1,7) + a;
z = rr;
x = [1:7];
zz = rand(1,7)
  colormap(jet)
  yyaxis left
  hold on
  for i = 1:length(y)
      h=bar(i,y(i), 'FaceColor',[1 1 1], 'LineWidth',3);
      yb(i) = cat(1, h.YData);
      xb(i) = bsxfun(@plus, h(1).XData, [h.XOffset]');
      if zz(i) < 0.0300000
          set(h,'EdgeColor','k');
      elseif zz(i) < 0.050000000
          set(h,'EdgeColor','k');
      elseif zz(i) < 0.070000000
          set(h,'EdgeColor','k');
      else
          set(h,'EdgeColor','k');
      end
  end
    cco = min(zz)
    cct = max(zz)
    caxis([cco cct])
    coloo = colorbar
    coloo.Label.String = 'Cbar';
    %h = bar(y, 0.2, 'FaceColor',[1 1 1], 'EdgeColor',[0 0 0],'LineWidth',2);
    %yb = cat(1, h.YData);
    %xb = bsxfun(@plus, h(1).XData, [h.XOffset]');
    for i1=1:7 % numel(yb)
        t = text(xb(i1)-0.3,yb(i1),num2str(yb(i1),'%0.3f'),...
                   'HorizontalAlignment','center',...
                   'VerticalAlignment','bottom')
                    s = t.FontSize;
                    t.FontSize = 12;
                    t.FontWeight = 'bold';
    end
    ylabel('OK', 'FontSize', 12, 'FontWeight', 'bold')
    yyaxis right
    pointsize = 80;
    hh = scatter(x,z,pointsize, zz,'filled')
    set(gca,'Ydir','reverse')
    ylabel('MM', 'FontSize', 12, 'FontWeight', 'bold')
    c = colorbar
    c.Label.String = 'Cbar';
    lgd = legend([h, hh], 'OK', 'MM')
    %title(lgd,'My Legend Title')
    hold off
Minary
  • 17
  • 4
  • 1
    This code is not functional. `xticklabel_rotate` is not a built-in MATLAB function. Please provide a **minimal** functioning example. – sco1 Nov 08 '16 at 12:51
  • Thanks, sorry for that. I will edit it so that a minimal functional example is provided. – Minary Nov 08 '16 at 13:08
  • What MATLAB version is this? `yyaxis` does not exist on 2014b, it was introduced in 2016a. I think its worth mentioning ;) – Ander Biguri Nov 08 '16 at 16:13
  • Cheers, Ander! It is indeed 2016a. I will edit the question. – Minary Nov 14 '16 at 14:02

1 Answers1

0

The problem is with zz. You define it as a vector, so scatter uses the figures colormap to choose the colors reltive to the values in zz. Instead, define it as a color matrix, i.e. an n-by-3 matrix where each row define one color in RGB values between 0 to 1.

In your example, try this: zz = rand(7,3) for the first subplot, and zz = rand(8,3) for the second.

Here is your code, where I set zz with a matrix of colors, and use it for both scatters:

figure
subplot(2,1,1)
a = 1;
b = 2;
r = (b-a).*rand(1,7) + a;
y = r;
rr = (b-a).*rand(1,7) + a;
z = rr;
x = 1:7;
%%%% this part is new: 
zz = [0    0.447 0.741;
    0.85  0.325 0.098;
    0.929 0.694 0.125;
    0.494 0.184 0.556;
    0.466 0.674 0.188;
    0.301 0.745 0.933;
    0.635 0.078 0.184;
    0.432 0.915 0.121];
%%%%%%%%%%%%%%%%%%%%%%%%
yyaxis left
hold on
for i = 1:7
    h=bar(i,y(i), 'FaceColor',[1 1 1], 'LineWidth',3);
    yb(i) = cat(1, h.YData);
    xb(i) = bsxfun(@plus, h(1).XData, [h.XOffset]');
    if zz(i) < 0.0300000
        set(h,'EdgeColor','k');
    elseif zz(i) < 0.050000000
        set(h,'EdgeColor','b');
    elseif zz(i) < 0.070000000
        set(h,'EdgeColor','g');
    else
        set(h,'EdgeColor','r');
    end
end
ylabel('hm', 'FontSize', 12, 'FontWeight', 'bold')
for i1=1:7
    t = text(xb(i1)-0.2,yb(i1),num2str(yb(i1),'%0.3f'),...
        'HorizontalAlignment','center',...
        'VerticalAlignment','bottom');
    s = t.FontSize;
    t.FontSize = 12;
    t.FontWeight = 'bold';
end
yyaxis right
pointsize = 40;
hh = scatter(x,z,pointsize, zz(1:numel(x),:),'filled');
cc = colormap(hsv(20));
c = colorbar;
c.Label.String = 'Pos';
set(gca,'Ydir','reverse')
ylabel('OK', 'FontSize', 12, 'FontWeight', 'bold')
legend([h, hh], 'hm', 'OK');

subplot(2,1,2)
x = 1:8;
a = 1;
b = 2;
r = (b-a).*rand(1,8) + a;
y = r;
rr = (b-a).*rand(1,8) + a;
z = rr;
yyaxis left
hold on
for i = 1:8
    h=bar(i,y(i), 'FaceColor',[1 1 1], 'LineWidth',3);
    yb(i) = cat(1, h.YData);
    xb(i) = bsxfun(@plus, h(1).XData, [h.XOffset]');
    if zz(i) < 0.0300000
        set(h,'EdgeColor','k');
    elseif zz(i) < 0.050000000
        set(h,'EdgeColor','b');
    elseif zz(i) < 0.070000000
        set(h,'EdgeColor','g');
    else
        set(h,'EdgeColor','r');
    end
end
for i1=1:8
    t = text(xb(i1)-0.2,yb(i1),num2str(yb(i1),'%0.3f'),...
        'HorizontalAlignment','center',...
        'VerticalAlignment','bottom');
    s = t.FontSize;
    t.FontSize = 12;
    t.FontWeight = 'bold';
end
ylabel('hm', 'FontSize', 12, 'FontWeight', 'bold')
yyaxis right
pointsize = 40;
hh = scatter(x,z,pointsize, zz(1:numel(x),:),'filled');
set(gca,'Ydir','reverse')
ylabel('OK', 'FontSize', 12, 'FontWeight', 'bold')
c = colorbar;
c.Label.String = 'Pos';
lgd = legend([h, hh], 'hm', 'OK');
%title(lgd,'My Legend Title')
hold off

And also notice the zz(1:numel(x),:) within the scatter command, so it will suite the size of the data.

This it the result:

scatter+colorbar

EDIT: After your response I see that you want the scatter in colors from the colormap but still there are many improvements you can add to your code, so I publish here a second version which works almost exactly like your second edit, but shorter and simpler. Get to know this tricks, they'll save you time ;)

a = 1;
b = 2;
r = (b-a).*rand(1,7) + a;
y = r;
rr = (b-a).*rand(1,7) + a;
z = rr;
x = 1:7;
zz = rand(1,7);
colormap(jet)
caxis([min(zz) max(zz)])
bary = diag(y);
bary(bary==0) = nan;
col_thresh = [0.03 0.05 0.07 1];
bar_color = {'r'; 'g'; 'b'; 'k'};
bar_group = sum(bsxfun(@lt,zz.',col_thresh),2);
yyaxis left
hold on
h = bar(bary,'stacked','FaceColor',[1 1 1], 'LineWidth',3);
set(h,{'EdgeColor'},bar_color(bar_group))
text(x-0.3,y,num2str(y.','%0.3f'),...
        'HorizontalAlignment','center',...
        'VerticalAlignment','bottom','FontSize',12,...
        'FontWeight','bold');
ylabel('OK', 'FontSize', 12, 'FontWeight', 'bold')
yyaxis right
pointsize = 80;
hh = scatter(x,z,pointsize,zz,'filled');
hh.Parent.YDir = 'reverse';
ylabel('MM', 'FontSize', 12, 'FontWeight', 'bold')
c = colorbar;
c.Label.String = 'Cbar';
legend([h(1), hh], 'OK', 'MM');
hold off

new_colorbar

EBH
  • 10,350
  • 3
  • 34
  • 59
  • @Minary, please let me know if this answers your question – EBH Nov 10 '16 at 18:33
  • Thank you @EBH! I really appreciate you taking the time! It is not entirely what I had in mind. I specifically want the colorbar to be directly related to the zz variable in the scatter plot - the variable which governs the color of the scatter plot. Your solution is very neat, though! I did manage to solve my question, I will include it as an edit to my question. – Minary Nov 14 '16 at 13:59
  • @Minary, your 2nd edit is quite different, so I'm not sure what was the problem, but I have added an etid to make your code simpler. Take a look ;) – EBH Nov 14 '16 at 19:38
  • Thank you, @EBH! Your code looks really neat! I am a newbie, and always open for suggestions regarding writing code that is shorter and more efficient. Well, the edit only shows the code for one of the fiures, but it does work even if I add a subplot. The problem I had was that the colorbar was not linked to to the scatter plot. I wanted XY scatter plot, where the color was dependent on the value of a third variable Z. This by itself worked, but when I added the colorbar the range was off - it did not ave the same range as Z. This was the issue. Sorry if I did not explain myself very well. – Minary Nov 17 '16 at 09:01