2

I have a collection of data that I am trying to graph as a histogram. Additionally, I would like to color the individual bars as a function of the x axis location. CData, described here seems to do what I want but I can't get it to work.

Here is my code:

h = bar(new_edge,N,'hist','FaceColor','flat');
hold on

for n = 1:length(N)
    if (x - x/1.09) - (x-1) > 0
        probability(n) = 1 - ((x-x/1.09) - (x-1))/((x - 1/1.09)+(x/0.91 - x)); 
    else
        probability(n) = 1;
    end

    color_num = 30;
    cm = jet(color_num);
    min = 0.5450;
    max = 1;

    color_map_index = floor(1 + (probability(n) - min)/(max-min)*(color_num-1));
    rbg = cm(color_map_index,:);

    h.CData(n,:) = rbg;

end

Similar to the MATLAB example, I first create my bar graph. Next, I want to loop through and prescribe the color for each bar based on a calculation. I do this by creating a colormap with # of bins and a min/max, getting a color index, then finally retrieving the rbg value. I get the following error when I try to apply the color:

Subscript indices must either be real positive integers or logicals.

h.CData(n,:) = rbg;

If I dive into the h object, MATLAB tells me that CData has a size of (4x65). What's going on here? Both new_edge and N are 1x65 vectors.

Joe
  • 457
  • 5
  • 18
MattM
  • 317
  • 4
  • 12

3 Answers3

2

Are you certain that the error you're getting ("Subscript indices must either be real positive integers or logicals") is coming from the following line?:

h.CData(n,:) = rbg;

Since we know n is a positive integer greater than or equal to one, the indexing here shouldn't have a problem. It's more likely that your error is coming from the line above it (i.e. the value for color_map_index is less than 1). I would double-check how you are computing color_map_index.

You could also try using function notation (i.e. get and set) instead of dot notation to update the property:

cData = get(h, 'CData');
cData(n, :) = rbg;
set(h, 'CData', cData);

Incidentally, you should also not be giving your variables the same name as existing functions, like you are doing here:

...
min = 0.5450;
max = 1;
...

This shadows the built-in min and max functions, which can also lead to the same error message under other conditions. Definitely rename those.

If you are still having trouble after trying those fixes, you could try setting the color using indexed color mapping instead, as illustrated in one of my other answers (near the bottom). As a simple example, the following plots 20 bars of 30 different possible values, then colors them based on their height:

color_num = 30;
N = randi(color_num, 1, 20);
hBar = bar(N, 'hist');
colormap(parula(color_num));
set(hBar, 'CData', N, 'CDataMapping', 'direct');

And the plot:

enter image description here

gnovice
  • 125,304
  • 15
  • 256
  • 359
0

This could be a problem with your Matlab version. When I test CData with bar on 2017b, this works:

openExample('graphics/ControlIndividualBarColorsExample')

When I try it on 2017a, it doesn't run. Does the example work?

Till
  • 26
  • 5
  • 1
    I think you're on to it. The example does not work either, so this must be a version thing. Thanks! – MattM Nov 07 '17 at 22:35
0

Given that this is a version control problem, there's really not a clean solution. In case anyone else comes along with a similar question and has the same version, here's a workaround that worked for me in 2017a.

Rather than creating a bar chart, you can simply draw rectangles. It's messy, but it does produce the desired result.

[N,edges] = histcounts(AB(AB<2));

probability = zeros(1,length(N));
new_edge = zeros(1,length(N));

for m = 1:length(N)
    new_edge(m) = (edges(m) + edges(m+1))/2;
end

figure
hold on

for n = 1:length(N)
    x = new_edge(n);
    if ((x - x/1.09) - (x-1)) > 0
        probability(n) = 1 - ((x-x/1.09) - (x-1))./((x - x/1.09)+(x/0.91 - x)); 
    else
        probability(n) = 1;
    end

    color_num = 100;
    cm = jet(color_num);
    min = 0;
    max = 1;

    color_map_index(n) = floor(1 + (probability(n) - min)/(max-min)*(color_num-1));
    rbg = cm(color_map_index(n),:);

    rectangle('Position',[edges(n),0,(edges(n+1)-edges(n)),N(n)],'Edgecolor','k','FaceColor',rbg)

end

set(gcf,'color','w');
blah = colorbar;
MattM
  • 317
  • 4
  • 12