Color-Coded Bar Graph

8 views (last 30 days)
Gillian Murray
Gillian Murray on 6 Jul 2021
Edited: dpb on 9 Jul 2021
I have a table with 3 columns, Time, Steps, Action and am trying to make a bar graph. I want time on the x-axis and steps on the y-axis and I want to color code based on action. I am using the following code, but my graph is coming out just one color, blue which maybe because the first data point is cycle. I'm not sure what I'm doing wrong. Thanks in advance for your help!
figure(1)
hold on
for i = 1:length(StepsS2.Time)
b = bar(StepsS2.Time, StepsS2.Steps);
if StepsS2.Action(i) == 'Jump'
set(b, 'FaceColor', 'r');
elseif StepsS2.Action(i) == 'Run'
set(b, 'FaceColor', 'y');
elseif StepsS2.Action(i) == 'Squat'
set(b, 'FaceColor', 'c');
elseif StepsS2.Action(i) == 'Cycle'
set(b, 'FaceColor', 'b');
else
set(b, 'FaceColor', 'g');
end
end
hold off
  1 Comment
dpb
dpb on 6 Jul 2021
Your code above is drawing the same bar graph over and over on top of the previous rendition for each pass through the loop.
With only a vector for the y variable, bar() creates only a single bar object and all bars are the same color. It is blue in the end because the last datapoint must be 'Cycle', not the first.
You need to rearrange the data in the table to have a variable for each bar wanted; fill the missing values for the times with NaN so those values will be ignored.
Then call bar() just once and set the colors using the array of bar handles.
I demonstrated for a smaller case just recently at https://www.mathworks.com/matlabcentral/answers/871108-legend-in-bar-plot?s_tid=srchtitle although there used a 'Stacked' plot to be able to get the three bars since bar() treats a vector y as one bar object regardless of the input orientation. You've got an array so won't run into that limitation.
Attach a .mat file if want somebody to play directly with your data...

Sign in to comment.

Accepted Answer

Benjamin Kraus
Benjamin Kraus on 6 Jul 2021
Edited: Benjamin Kraus on 6 Jul 2021
I suspect the issue you are having is because you are attempting to compare against a character vector incorrectly.
What format is your StepsS2.Action in? Is it a character matrix, cell-array of character vectors, string array, or categorical?
You can tell by doing this:
class(StepsS2.Action)
disp(StepsS2.Action)
If you include the output from those commands in a reply, someone can give you a more personalized answer.
There are a couple possibilities:
For example, if StepsS2.Action is a cell-array of character vectors:
% If StepsS2.Action is a cell-array of character vectors:
StepsS2.Action = {'Jump', 'Run', 'Squat', 'Cycle', 'Other'};
% Indexing with () and comparison using '==' will throw an error.
StepsS2.Action(1) == 'Jump'
% Error: Operator '==' is not supported for operands of type 'cell'.
% Indexing with {} and comparison using '==' will generate a logical
% vector, but only if the sizes match.
StepsS2.Action{1} == 'Jump' % Output = [1 1 1 1]
StepsS2.Action{1} == 'Run'
% Error: Arrays have incompatible sizes for this operation.
% What you want is to compare using 'strcmp' or 'isequal'
strcmp(StepsS2.Action(1), 'Jump') % Output = true
strcmp(StepsS2.Action{1}, 'Jump') % Output = true
If instead StepsS2.Action is a string vector, what you are trying to do will work.
Note: you can convert from a cell-array of character vectors to string using the string command.
% If StepsS2.Action is a cell-array of character vectors:
StepsS2.Action = ["Jump", "Run", "Squat", "Cycle", "Other"];
% Indexing with () and comparison using '==' will work as expected.
StepsS2.Action(1) == 'Jump' % Output = true
% Indexing with {} and comparison using '==' will generate a logical
% vector, but only if the sizes match.
StepsS2.Action{1} == 'Jump' % Output = [1 1 1 1]
StepsS2.Action{1} == 'Run'
% Error: Arrays have incompatible sizes for this operation.
% You can also use either 'strcmp' or 'isequal'
strcmp(StepsS2.Action(1), 'Jump') % Output = true
strcmp(StepsS2.Action{1}, 'Jump') % Output = true
Another completely different option is to set the FaceColor property to 'flat' and then use the CData property on the bar object. This example also shows how to use a switch statement to do what you are trying to do. For example:
Time = hours(1:15)';
Steps = randi(100,15,1);
Actions = ["Jump";"Run";"Squat";"Cycle";"Other"];
Action = Actions(randi(5,15,1));
StepsS2 = table(Time, Steps, Action);
b = bar(StepsS2.Time, StepsS2.Steps);
b.FaceColor = 'flat';
for i = 1:length(StepsS2.Time)
switch StepsS2.Action(i)
case "Jump"
b.CData(i,:) = [1 0 0];
case "Run"
b.CData(i,:) = [1 1 0];
case "Squat"
b.CData(i,:) = [0 1 1];
case "Cycle"
b.CData(i,:) = [0 0 1];
otherwise
b.CData(i,:) = [0 1 0];
end
end
  8 Comments
dpb
dpb on 9 Jul 2021
For context, here's just one of those prior ca 2017; there are responses as early as 2014 on Answers; if go to Google Groups and search under the "cssm" newsgroup archives, it'll go back as far as their archives go, probably...
The one in 2014 already pointed out having a bar label should be a built-in writeable property of the bar, not require such machinations although I'd submitted enhancement requests and b-^h^h complained about bar() and suggested such going back long, long before that to some of earliest days w/ MATLAB. Then, picked up MATLAB again fairly heavily with the transition to self-employed instead of through consulting firm around 2000 and began the crusade again then until finally just gave it up as lost cause...

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by