Categorical Bar Plot keeps old categories

I make a bar plot with categorical x-values as follows:
  • define legend names (that will be the labels for each bar in the bar graph) depending on if the value is normal or lowered (specificity to the app I am writing)
  • make the legend names categorical
  • plot them together with the heights
  • add text labels
app.legendnames = strings(app.n,1);
for i = 1:app.n
if app.loweringHeights(i)
app.legendnames(i) = strcat("P",num2str(i),"-lowered");
else %remaining plank
app.legendnames(i) = strcat('P',num2str(i));
end
end
app.bx = reordercats(categorical(app.legendnames),app.legendnames);
app.by = heights;
cla(app.UIAxes);
b = bar(app.UIAxes, app.bx, app.by,0.5);
xtips = b(1).XEndPoints;
ytips = b(1).YEndPoints;
labels = compose("%6.0f",b(1).YData);
text(app.UIAxes, xtips,ytips,labels,'HorizontalAlignment','center','VerticalAlignment','bottom')
It looks like this
Now, when I call this plotting function again (without closing the app), each of these steps is called again. In this case, I adapt loweringHeights(2). In some way Matlab/App Designer keeps old labels that are now not anymore in use. These old labels are not part of the legendnames anymore. I know this because in other plots, the legendnames are plotted correctly. It is only in the bar graphs that I have this problem:
So I suspect the categorical thing is keeping old categories even when they are not anymore part of the new app.legendnames vector. I have no idea how to eliminate those old values. I was thinking about using removecats() but I don't see how I can tell what categories to eliminate. Any suggestions?

回答(1 个)

That is the expected behavior of the categorical datatype. The list of possible categories is maintained, even if they are not present in the captured data. When creating a bar plot, the possible category names are used for X.
To get the behavior you want, use removecats to remove categories that are empty before plotting.

8 个评论

Hi Cris, I tried this but it doesn't work.
app.bx = reordercats(categorical(app.legendnames, app.legendnames),app.legendnames);
app.bx = removecats(app.bx);
Stil the old category remains.
I also tried
clear app.bx app.by
and that also didn't work.
Could it have something to do with bx being an app property? It seems I don't have the issue when I run these commands in the editor. It does persist in the app. But I have no idea how to fix it as the values in the editor are correct, so I have no way of identifying wheren in the app processing there is a difference in behaviour of these categorical values.
It's looks like your code is doing something different, so while what I shared is true, it applies when creating a histogram (X is determined based on Y). It does not apply to bar. Since you have not shared how height is calculated, one approach could be to use indexing to plot just those bars whose Y value is not 0.
Try something like this.
b = bar(app.UIAxes, app.bx(app.by>0), app.by(app.by>0),0.5);
Height are indeed positive numbers. So your approach seemed logical. However, this also didn't work. It still gives the same error.
It is very remarkable still that executing the same code in editor does not pose issues. Is it possible this is an AppDesigner bug?
It's more likely your code is doing exactly what you are telling it to do. Consider sharing your app. You can attach it using the paperclip icon. Include any additional files we would need to run your code.
For confidentiality reasons I am unable to do so unfortunately. I know that would be the most easy way but I can't.
However my original post contains all the lines where "app.bx" is involved in. There's nothing more except that bx and by are public app properties. And I clear the axes before plotting, that's it.
cla(app.UIAxes);
I forgot my own advice in the orginal post. You need to combine logical indexing and removecats. Here's a simple example. Hopefully this helps.
% Create data
x=categorical("p"+[1:3]);
y=[3 0 1];
% What you are currently seeing
bar(x,y)
% removecats and indexing
figure
bar(removecats(x(y>0)),y(y>0))
Hi Chris, I tried this. It is indeed effective in the editor. Again, it is not effective in the app environment.
So I focussed on the difference, which is the axis handle in the app. What finally did the trick was
cla(app.UIAxes, 'reset');
so it seems some information about categorical bx was kept within the UIAxes environment.
I see. Yes, it appears a uiaxes is combining the categories from the previous bar plot and the current one. I can't say if that is intentional or not, but it is different behavior than what happens in a figure axes. I believe your workaround is the best solution currently (R2021b).

请先登录,再进行评论。

产品

Community Treasure Hunt

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

Start Hunting!

Translated by