How to plot discrete array with colors

34 views (last 30 days)
Laura
Laura on 20 Jun 2023
Edited: dpb on 21 Jun 2023
I have 'nodes' which each have a status. The status of these nodes are contained in an array 'status_array' and have the values "waiting" or "busy". I would like to plot an array with colors indicating what state each node is in, for example, green = 'waiting' and red = 'busy'. This way I can visualize how the node transistion from their states. I want it to look something like this:
I tried using imagesc or bar but it doesn't look quite right.
Thanks in advance for any suggestions!

Answers (3)

Star Strider
Star Strider on 20 Jun 2023
One approach —
status = randi([0 1], 1, 9) % 'Waiting' = 0, 'Busy' = 1
status = 1×9
0 0 0 1 0 1 0 0 1
status = flip(status);
cv = ["g" "r"]; % Coluur Vector
xv = repmat([0 1], size(status,2), size(status,1));
yv = xv + (0:size(status,2)-1).';
figure
% patch([xv fliplr(xv)], [yv fliplr(yv)], cv(status+1))
hold on
for k = 1:numel(status)
patch([xv(k,:) fliplr(xv(k,:))], [[1 1]*yv(k,1) [1 1]*(yv(k,2))], cv(status(k)+1))
end
hold off
xlim([0 0.1])
% axis('equal')
daspect([0.1 1 1])
xticks([])
yt = yticks;
yticks(0.5:max(yt))
yticklabels(yt(2:end))
I could not get this to work correctly without the loop.
.
  1 Comment
dpb
dpb on 20 Jun 2023
Edited: dpb on 20 Jun 2023
I didn't go back to the beginning to try to remove the loop there, but it's not terribly difficult to then update the graphic to match a new status vector without looping...
Following copies the above with one exception during creation -- save a vector of patch handles, hP, to use to address the objects later.
status = randi([0 1], 1, 9) % 'Waiting' = 0, 'Busy' = 1
status = 1×9
0 0 0 0 0 0 1 0 0
status = flip(status);
cv = ["g" "r"]; % Coluur Vector
xv = repmat([0 1], size(status,2), size(status,1));
yv = xv + (0:size(status,2)-1).';
figure
hold on
hP=gobjects(size(status)); % patch handles array
for k = 1:numel(status)
hP(k)=patch([xv(k,:) fliplr(xv(k,:))], [[1 1]*yv(k,1) [1 1]*(yv(k,2))], cv(status(k)+1));
end
hold off
xlim([0 0.1])
daspect([0.1 1 1])
xticks([])
yt = yticks;
yticks(0.5:max(yt))
yticklabels(yt(2:end))
Above ends the original iwth the one mod noted...now update given a new status...but, the .FaceColor property is actually an RGB triplet; the patch() function will accept the shortnames for the base colors but have to use rgb to set directly...
% define the rgb triplets to go with the original colors
R=[1 0 0]; G=[0 1 0]; CV=[G;R]; % lookup vector to match "g","r"
status = randi([0 1], 1, 9); % a new status vector
status=flip(status); % match order to object handle order
cv(status+1) % what what it is for comparison in string form
ans = 1×9 string array
"r" "r" "r" "r" "g" "r" "r" "g" "r"
set(hP,{'FaceColor'},num2cell(CV(status+1,:),2)) % update the colors to match
Remember to look at the colors in comparison to the color names from bottom up, not top down!!! :)

Sign in to comment.


Askic V
Askic V on 20 Jun 2023
I would also like to offer my solution. It is not so elegant comparing to @Star Strider, but it can show you how bar can be used to achieve something similar:
clear;clc;close all;
red = [1 0 0];
green = [0 1 0];
% Example data
data = [1; 0; 1; 0; 0; 1; 1; 0; 1];
% Adjust the width of the bars
barWidth = 0.8; % Specify the desired width of the bars
barWidthRatio = barWidth / numel(data); % Calculate the ratio of the desired width to the number of bars
h = bar(1, ones(size(data, 1), 1), 'stacked');
for i = 1:numel(data)
h(i).BarWidth = barWidthRatio;
if data(i) == 1
h(i).FaceColor = green;
else
h(i).FaceColor = red;
end
text(0.95, i, num2str(i), 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom');
end
axis ij; % invert axis
ylabel('Value');
ylim([0 size(data, 1)+1]);
yticks(1:size(data, 1)); % Set the y-axis tick locations
yticklabels([]); % Hide the y-axis tick labels

dpb
dpb on 20 Jun 2023
Edited: dpb on 21 Jun 2023
I looked at the vectorized version issue a little -- it doesn't work easily for the purpose because even if you create multiple polygons, it's then a one-object patch with only a single .FaceColor property. To set the colors by face then have to set the initial color vector as a nx1x3 rgb array which is more of a pain to generate than the lookup of the color vector or 2D array.
While doable and does create the same overall effect, I think it's handier to leave it as the separate patch objects above -- although I guess once one writes the code once, even if it was harder initially, then it doesn't really matter to use...
The following works...
status=randi(2,[1,9])-1;
status=flip(status);
status
status = 1×9
1 0 1 0 1 1 0 1 0
x=[0 1 1 0].'; y=[0 0 1 1].';
x=repmat(x,size(status));
y=repmat(y,size(status))+[0:numel(status)-1];
G=[0 1 0];G=reshape(G,1,1,[]);
R=[1 0 0];R=reshape(R,1,1,[]);
C=[G; R];
c=C(status+1,1,:);
hP=patch(x,y,c);
box on
xlim([0 0.1])
daspect([0.1 1 1])
prior to the cleanup of tick labels, etc., ...

Community Treasure Hunt

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

Start Hunting!