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 个评论

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...

请先登录,再进行评论。

 采纳的回答

Benjamin Kraus
Benjamin Kraus 2021-7-6
编辑:Benjamin Kraus 2021-7-6
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 个评论

Thank you so much! That was super helpful, my graph looks great now!
I have an additional question, if you don't mind, how would I add a legend to this if I'm using the switch and case format? I've tried a variety of solutions, but can't figure out where to put it in the code.
A limitation of using the single bar object and setting the CData property (as in my switch example) is that the legend will have only a single entry to represent the entire bar. There's no good way around that, other than to switch back to using multiple bar objects.
Regardless of which approach you use, you can call the legend command at the end (after the for loop).
Or, as another answer Walter posted in the Q? I linked to above, create a set of dummy plot objects to provide the handles for legend() to label.
I think personally it's cleaner to just go ahead and create the multiple bars plot from the git-go.
I certainly wish bar() interface weren't so inflexible and munging on one so problematic -- the recast/rewrite a few releases ago helped, but it's still klunky.
In particular, that it treats both a row and column vector as a column vector and so creates only the one bar object is both not consistent with the definition otherwise of what bar() does by column treating each as a group, but is the limitation that keeps this particular form from being only two lines of code.
@dpb I almost suggested "create dummy objects", but in this specific case, as you observed, it makes more sense to just split the data across multiple objects.
We've had a number of small tweaks to the bar command, including one in MATLAB R2019b to modify how it handles vector and matrix inputs. I suspect that is the "rewrite" you are talking about. Unfortunately, we are somewhat limited by what we can change without breaking a lot of existing code.
I agree about the frustration with respect to column vs. row vectors. Unfortunately, it is just far too common for users to do something like bar(1:10) (row vector) and expect to get a single object, so we couldn't modify that behavior.
dpb
dpb 2021-7-8
编辑:dpb 2021-7-9
My enhancement suggestion some 20 (nearly 30?) years ago now was to add a 'separate' Style when TMW complained they couldn't (or at least wouldn't) fix the underlying behavior for vectors.
I've railed against bar from almost the first, having been user since the Win 3 release as it just needed "throwed out and started over" from the very beginning.
It doesn't seem to bother TMW to introduce all other kinds of (almost) duplicate functionality; if don't want to modify the original much more, then it's a good candidate for such a complete replacement; new and different, including hatching patterns and all the other goodies everybody always wants to add on top as user-settable properties instead of 20 lines of code to generate the amenities.
And, no, it wasn't those differences specifically I was referring to; it was instead that finally! the 'x|yendpoints' properties were made visible so the most obvious of those enhancements, labeling the bar values could be done without handle-diving to uncover the locations. Initially, at least the positions of the bars was available and one could derive the center positions from them (no idea how many times I've posted that code over the years going back to the old newsgroup even before Answers); then in one iteration, even those were made hidden properties so unless one knew they were there from prior experience, one was stuck entirely (or unless knew of Yair's undocumented tool and had the acumen to use it). What a waste of time has gone into the thousands of users who have struggled over that over the years to simply create a presentable chart instead of working on and solving the underlying research problem at hand.
Interesting, thanks for all of your help!
dpb
dpb 2021-7-9
编辑:dpb 2021-7-9
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...

请先登录,再进行评论。

更多回答(0 个)

类别

帮助中心File Exchange 中查找有关 Text Data Preparation 的更多信息

产品

版本

R2020a

Community Treasure Hunt

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

Start Hunting!

Translated by