MATLAB Color Map defined by segment values - matlab

I have a plot in MATLAB that I would like to transform into a colormap (plot shown below). There are several line segments in this plot, and I want each line segment to be colored based on a specific value that is associated with the segment.
For example:
Value of line 1 = 800, plot a specific color
Value of line 2 = 555, plot a specific color
...etc.
Does anyone know how to do this? I have included the part of the code in my program that is making the plots below. In the code I want the color of the line to be dependent on ElementMap(i,6). I don't have a particular preference on the colors as long as I can tell which line segments have a higher value.
Thanks
%% Plot
for i = 1:length(ElementMap)
if ElementMap(i,6) < 1000
x = [ElementMap(i,1);ElementMap(i,3)];
y = [ElementMap(i,2);ElementMap(i,4)];
plot(x,y,['-','b','o']);
hold on;
end
end

You could determine an indexed color for each unique value in the 6th column and then convert these indexed colors to RGB colors using a colormap of your choosing (here we use parula). Then when plotting each line, specify the Color property.
% Get indices to use for the colormap
[~, ~, ind] = unique(ElementMap(:,6));
% Create a colormap of the correct size
cmap = parula(max(ind));
% Create a color for each plot
colors = ind2rgb(ind, cmap);
% Now plot everything
for k = 1:size(ElementMap, 1)
x = [ElementMap(k,1);ElementMap(k,3)];
y = [ElementMap(k,2);ElementMap(k,4)];
plot(x,y, 'Marker', 'o', 'LineStyle', '-', 'Color', colors(k,:));
hold on
end
With this approach, the colors won't necessary scale linearly with your data, but each unique value in ElementMap(:,6) will be represented by a different color and smaller values will be differentiated from larger values.
If you don't care about every plot having a unique value, you could do something like the following which would get you a linear mapping between your colors and values.
values = ElementMap(:,6);
% Assign an index to each
ind = gray2ind(mat2gray(values))
% Create the colormap
cmap = parula(numel(unique(inds)));
% Create a color for each plot
colors = ind2rgb(ind, cmap);
% Now plot everything
for k = 1:size(ElementMap, 1)
x = [ElementMap(k,1);ElementMap(k,3)];
y = [ElementMap(k,2);ElementMap(k,4)];
plot(x,y, 'Marker', 'o', 'LineStyle', '-', 'Color', colors(k,:));
hold on
end
% Now create a colorbar
colorbar()
% Set the range of the colorbar
set(gca, 'CLim', [min(values), max(values)])

Related

matlab quiver3 plot color gradient in z direction? [duplicate]

I want the color of each arrow in a quiver3 plot from MATLAB to correspond to the magnitude of each arrow. Is there any way to do that?
I saw a few examples online that are able to do this for the 2D quiver, however none of them work for the 3D variant, quiver3.
I have the following plot and want to replace the blue arrows with a color corresponding to their magnitude.
In the old graphics system (R2014a and earlier) this is not possible using the built-in quiver object. You can easily get all of the plot objects that are used to compose the quiver plot
q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');
But the tails are all represented by one plot object, and the arrow heads are represented by another. As such, you can't alter the color of each head/tail individually.
set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')
However, with the introduction of HG2 (R2014b and later), you can actually get access to two (undocumented) LineStrip objects (matlab.graphics.primitive.world.LineStrip) (one represents the heads and one represents the tails). These are accessible via the hidden properties Tail and Head.
q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;
You can then alter the color properties of these objects to make each arrow a different color.
The Basic Idea
To do this, I first compute the magnitude of all quiver arrows (this works for both quiver and quiver3)
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
Then I use the current colormap to map each magnitude to an RGB value. The shortest arrow is assigned the lowest color on the colormap and the longest arrow is assigned the highest color on the colormap. histcounts works great for assigning each magnitude an index which can be passed to ind2rgb along with the colormap itself. We have to multiply by 255 because we need the color to be RGB as an 8-bit integer.
% Get the current colormap
currentColormap = colormap(gca);
% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
The LineStrip ColorData property (when specified as truecolor) also needs to have an alpha channel (which we will set to 255 meaning opaque).
cmap(:,:,4) = 255;
At this point we can then set the ColorBinding property to interpolated rather than object (to decouple it from the quiver object) and set the ColorData property of both q.Head and q.Tail to the colors we created above giving each arrow it's own color.
Full Solution
NOTE: This solution works for both quiver and quiver3 and the code does not have to be adapted at all.
%// Create a quiver3 as we normally would (could also be 2D quiver)
x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);
q = quiver3(X, Y, Z, U, V, W);
%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
%// Get the current colormap
currentColormap = colormap(gca);
%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);
%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:3,:,:), [], 4).'); %'
%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:2,:,:), [], 4).');
And applied to a 2D quiver object
If you don't necessarily want to scale the arrows to the entire range of the colormap you could use the following call to histcounts (instead of the line above) to map the magnitudes using the color limits of the axes.
clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));
If your using a post r2014b version you can use undocumented features to change the colour of each line and head:
figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w);
s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the start and end of the
% line.
for jj=1:2
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)
% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the all the points
% at the head of the arrow
for jj=1:3
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)
Note: I've not done anything clever with the magnitude and simply change the colour of each quiver based on the order in the original matrix - but you should be able to get the idea on how to use this "feature"
Note that if you are using Suevers solution and have NaNs in your data you should include this line before calling histcounts:
mags(isnan(mags)) = [];
Otherwise you will get an error about wrong input size because matlab does not create vertices for NaNs in your U/V/W data.

Passing colormap to scatter3

This is basic but I'm struggling to give scatter3 a colormap. I'm doing this:
scatter3(gesture_x(:,1),gesture_x(:,2),gesture_x(:,3),1,colors(labels_x))
Where colors = ['c','y','m'...] and labels_x = [1 3 3 2 ..]
If anyone could point out what I'm doing wrong that would be great.
You cannot use the single-character color specifications to specify an array of colors to be used for each point. MATLAB will actually interpret ['c', 'y', 'm'] as 'cym' and that isn't a valid color so it is going to error out.
If you look at the documentation, you need to specify the color in one of three ways:
RGB values for each data point (an N x 3 array where the columns are red, green, and blue components),
A single color ('r' or 'red' or [1 0 0]) to be applied to all points,
A number which will be mapped to the colormap of the axes using the clims.
Marker color, specified as a color string, an RGB row vector, a three-column matrix of RGB values, or a vector. For an RGB row vector, use a three-element row vector whose elements specify the intensities of the red, green, and blue components of the color. The intensities must be in the range [0 1]. If you have three points in the scatter plot and want the colors to be indices into the colormap, specify C as a three-element column vector.
% Random RGB value for each point
colors = rand(size(gesture_x, 1), 3);
% One color for everything
colors = 'r';
colors = 'red';
colors = [1 0 0];
% Random values mapped to the axes colormap
colors = rand(size(gesture_x,1), 1);
This answer complements the excellent existing answer with a full example and uses information gained from the answer at this post.
I find the easiest way to apply color using scatter3 is through the colormap.
From the documentation (emphasis mine):
scatter3(X,Y,Z,S,C) draws each circle with the color specified by C.
If C is a RGB triplet or character vector or string containing a color
name, then all circles are plotted with the specified color.
If C is a three column matrix with the number of rows in C equal to
the length of X, Y, and Z, then each row of C specifies an RGB color
value for the corresponding circle.
If C is a vector with length equal to the length of X, Y, and Z, then
the values in C are linearly mapped to the colors in the current
colormap.
Full example provided below with customization (except for marker size control).
% MATLAB R2017a
% Data
NumPoints = 25;
X = 100*rand(NumPoints,1);
Y = 100*rand(NumPoints,1);
Z = 100*rand(NumPoints,1);
V = (X + Y);
% Create custom colormap (2 color example)
col1 = [0 1 0]; %G
col2 = [1 0 0]; %R
cmap = interp1([col1; col2], linspace(1, 2, 101)); % Create the colormap
% Plot
colormap(cmap), hold on, box on
h = scatter3(X,Y,Z,[],V,'filled')
view(-25,25) % (azimuth,elevation)
% Colorbar Controls
cb = colorbar;
caxis([0 200]) % sets min and max value for color mapping (separate from tick control)
cb.Limits = [0 200];
cb.Ticks = [0:25:200]; % custom set colorbar ticks
cb.Label.String = ' V';
cb.Label.Rotation = 0; % Default is 90
% Cosmetics
h.MarkerEdgeColor = 'k'; % Set marker edge color to black
xlabel('X')
ylabel('Y')
zlabel('Z')

Plotting normals (quivers) with individual color [duplicate]

I want the color of each arrow in a quiver3 plot from MATLAB to correspond to the magnitude of each arrow. Is there any way to do that?
I saw a few examples online that are able to do this for the 2D quiver, however none of them work for the 3D variant, quiver3.
I have the following plot and want to replace the blue arrows with a color corresponding to their magnitude.
In the old graphics system (R2014a and earlier) this is not possible using the built-in quiver object. You can easily get all of the plot objects that are used to compose the quiver plot
q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');
But the tails are all represented by one plot object, and the arrow heads are represented by another. As such, you can't alter the color of each head/tail individually.
set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')
However, with the introduction of HG2 (R2014b and later), you can actually get access to two (undocumented) LineStrip objects (matlab.graphics.primitive.world.LineStrip) (one represents the heads and one represents the tails). These are accessible via the hidden properties Tail and Head.
q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;
You can then alter the color properties of these objects to make each arrow a different color.
The Basic Idea
To do this, I first compute the magnitude of all quiver arrows (this works for both quiver and quiver3)
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
Then I use the current colormap to map each magnitude to an RGB value. The shortest arrow is assigned the lowest color on the colormap and the longest arrow is assigned the highest color on the colormap. histcounts works great for assigning each magnitude an index which can be passed to ind2rgb along with the colormap itself. We have to multiply by 255 because we need the color to be RGB as an 8-bit integer.
% Get the current colormap
currentColormap = colormap(gca);
% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
The LineStrip ColorData property (when specified as truecolor) also needs to have an alpha channel (which we will set to 255 meaning opaque).
cmap(:,:,4) = 255;
At this point we can then set the ColorBinding property to interpolated rather than object (to decouple it from the quiver object) and set the ColorData property of both q.Head and q.Tail to the colors we created above giving each arrow it's own color.
Full Solution
NOTE: This solution works for both quiver and quiver3 and the code does not have to be adapted at all.
%// Create a quiver3 as we normally would (could also be 2D quiver)
x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);
q = quiver3(X, Y, Z, U, V, W);
%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
%// Get the current colormap
currentColormap = colormap(gca);
%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);
%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:3,:,:), [], 4).'); %'
%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:2,:,:), [], 4).');
And applied to a 2D quiver object
If you don't necessarily want to scale the arrows to the entire range of the colormap you could use the following call to histcounts (instead of the line above) to map the magnitudes using the color limits of the axes.
clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));
If your using a post r2014b version you can use undocumented features to change the colour of each line and head:
figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w);
s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the start and end of the
% line.
for jj=1:2
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)
% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the all the points
% at the head of the arrow
for jj=1:3
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)
Note: I've not done anything clever with the magnitude and simply change the colour of each quiver based on the order in the original matrix - but you should be able to get the idea on how to use this "feature"
Note that if you are using Suevers solution and have NaNs in your data you should include this line before calling histcounts:
mags(isnan(mags)) = [];
Otherwise you will get an error about wrong input size because matlab does not create vertices for NaNs in your U/V/W data.

Add non-existent entry to legend

I want to add an entry manually to a MATLAB legend. This legend can be pre-existent and contain other graphed elements' entries, but not necessarily.
I make a scatter plot, but instead of using e.g. scatter(x,y), I plot it using
for n = 1:numel(x)
text(x(n),y(n),num2str(n), ...
'HorizontalAlignment','center','color',[1 0 0])
end
This results in a scatter plot of numbers one through the number of elements in x (and y, because they are of the same size). I want to add a legend entry for these numbers.
I tried to add or edit the legend with
[h,icons,plots,s] = legend(___)
as described on the legend documentation page. I can't figure out how I can add a legend entry, without having to plot something (such as an actual scatter plot or regular plot). I want the usual line or marker symbol in the legend to be a number or character such as 'n', indicating the numbers in the graph. Is this possible and how would one achieve this?
EDIT by Erik
My answer goes below zelanix's answer, because mine is based on it.
Original answer
A fairly workable solution may be as follows:
x = rand(10, 1);
y = rand(10, 1);
figure;
text(x,y,num2str(transpose(1:numel(x))),'HorizontalAlignment','center')
% Create dummy legend entries, with white symbols.
hold on;
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
hold off;
% Create legend with placeholder entries.
[h_leg, icons] = legend('foo', 'bar');
% Create new (invisible) axes on top of the legend so that we can draw
% text on top.
ax2 = axes('position', get(h_leg, 'position'));
set(ax2, 'Color', 'none', 'Box', 'off')
set(ax2, 'xtick', [], 'ytick', []);
% Draw the numbers on the legend, positioned as per the original markers.
text(get(icons(4), 'XData'), get(icons(4), 'YData'), '1', 'HorizontalAlignment', 'center')
text(get(icons(6), 'XData'), get(icons(6), 'YData'), '2', 'HorizontalAlignment', 'center')
axes(ax1);
Output:
The trick to this is that the new axes are created in exactly the same place as the legend, and the coordinates of the elements of the icons are in normalised coordinates which can now be used inside the new axes directly. Of course you are now free to use whatever font size / colour / whatever you need.
The disadvantage is that this should only be called after your legend has been populated and positioned. Moving the legend, or adding entries will not update the custom markers.
Erik's answer
Based on zelanix's answer above. It is a work-in-progress answer, I am trying to make a quite flexible function of this. Currently, it's just a script that you'd need to adapt to your situation.
% plot some lines and some text numbers
f = figure;
plot([0 1],[0 1],[0 1],[1 0])
x = rand(25,1);
y = rand(25,1);
for n = 1:numel(x)
text(x(n),y(n),num2str(n), ...
'HorizontalAlignment','center','color',[1 0 0])
end
hold on
% scatter(x,y) % used to test the number positions
scatter(x,y,'Visible','off') % moves the legend location to best position
% create the dummy legend using some dummy plots
plot(0,0,'o','Visible','off')
[l,i] = legend('some line','some other line','some numbers','location','best');
l.Visible = 'off';
% create empty axes to mimick legend
oa = gca; % the original current axes handle
a = axes;
axis manual
a.Box = 'on';
a.XTick = [];
a.YTick = [];
% copy the legend's properties and contents to the new axes
a.Units = l.Units; % just in case
a.Position = l.Position;
i = copyobj(i,a);
% replace the marker with a red 'n'
s = findobj(i,'string','some numbers');
% m = findobj(i(i~=s),'-property','YData','marker','o');
m = findobj(i(i~=s),'-property','YData');
sy = s.Position(2);
if numel(m)>1
dy = abs(m(1).YData - sy);
for k = 2:numel(m)
h = m(k);
dy2 = abs(h.YData - sy);
if dy2<dy
kbest = k;
dy = dy2;
end
end
m = m(kbest);
end
m.Visible = 'off';
mx = m.XData;
text(mx,sy,'n','HorizontalAlignment','center','color',[1 0 0])
% reset current axes to main axes
f.CurrentAxes = oa;
The result:

Change color of each point in scatter plot sequentially

I am new to Matlab, I was trying to you scatter plot to plot 4 points in an axes.
for example
x = [0;0;1;-1];
y = [1;-1;0;0];
scatter(x,y);
what I wanted to do was to change the color of one coordinate in the above plot continuously in clock wise direction
Like the above pic.
If not is there another way I can do so?
Thanks in advance.
You can add a 4th argument to scatter in order to set the color (the 3rd argument sets the size, you can leave it empty):
col = lines(4); % create 4 colors using the 'lines' colormap
scatter(x,y,[],col);
You can use some other colormaps (type doc colormap in Matlab for more details), or just enter some vector of numbers to use the current colormap.
Edit I've just realized you wanted to change the color of only one point; you can do it with (for example) col = [2 1 1 1].
You need to plot each point separately, get a handle to each, and then change their 'color' property sequentially in a loop:
%// Data
x = [-1;0;1;0]; %// define in desired (counterclockwise) order
y = [0;1;0;-1];
color1 = 'g';
color2 = 'r';
%// Initial plot
N = numel(x);
h = NaN(1,N);
hold on
for n = 1:N
h(n) = plot(x(n), y(n), 'o', 'color', color1);
end
axis([-1.2 1.2 -1.2 1.2]) %// set as desired
%// Change color of one point at a time, and restore the rest
k = 0;
while true
k = k+1;
pause(.5)
n = mod(k-1,N)+1;
set(h(n), 'color', color2);
set(h([1:n-1 n+1:end]), 'color', color1);
end