How to use progressive coloring with plot3? - matlab

I want to use plot3 with varying colors as the array index progresses.
I have 3 variables: x, y, z.
All of these variables contain values in the timeline progress.
For example:
x = [1, 2, 3, 4, 5];
y = [1, 2, 3, 4, 5];
z = [1, 2, 3, 4, 5];
plot3(x, y, z, 'o')
I'd like to see a change of color from (x(1), y(1), z(1)) to the last value in the plot (x(5), y(5), z(5)). How can I change this color dynamically?

The way to go here, in my opinion, is to use scatter3, where you can specify the colour value explicitly:
scatter3(x,y,z,3,1:numel(x))
where 3 would be the size argument and 1:numel(x) gives increasing colours. Afterward you can choose your colour map as usual.
Using plot3 you could do the same, but it requires a loop:
cMap = jet(numel(x)); % Generates colours on the desired map
figure
hold on % Force figure to stay open, rather than overwriting
for ii = 1:numel(x)
% Plot each point separately
plot3(x(ii), y(ii), z(ii), 'o', 'color',cMap(ii,:))
end
I'd only use the plot3 option in case you want successively coloured lines between elements, which scatter3 can't do:
cMap = jet(numel(x)); % Generates colours on the desired map
figure
hold on % Force figure to stay open, rather than overwriting
for ii = 1:numel(x)-1
% Plot each line element separately
plot3(x(ii:ii+1), y(ii:ii+1), z(ii:ii+1), 'o-', 'color',cMap(ii,:))
end
% Redraw the last point to give it a separate colour as well
plot3(x(ii+1), y(ii+1), z(ii+1), 'o', 'color',cMap(ii+1,:))
NB: tested and exported images on R2007b, cross-checked the syntax with R2021b docs

Related

Coloring Bars from a histogram/bargraph

I'm currently working on a project. For this project I've binned data according to where along a track something happens and now I would like to nicely present this data in a histogram. For this data however, multiple environments have been presented. I would like to color code each environment with its own color. The way I've done it now (very roughly) is:
x = 0:1:10;
y = bins;
color = ['b', 'g', 'g', 'g', 'y', 'y', 'g', 'g', 'g', 'b'];
b = hist(x, y, 'facecolor', 'flat');
b.CData = color
In this data bins contains all the bins a freeze has happened (1-10). These numbers are not in chronological order and not all numbers are present. However, when i use the code i get the following error:
Unable to perform assignment because dot indexing is not supported for variables of this type.
How can I color my various bars?
This is very nearly a duplicate of this question:
How to draw a colorful 1D histogram in matlab
However, you want to specify the colours according to the colorspec letter which changes things slightly.
The general concept is the same; you don't have that level of control with either hist (which is deprecated anyway) or histogram, so you have to plot it in two steps using histcounts and bar, because you do have that level of control on bar plots:
x = randn(100,1)*10; % random example data
% Specify the colours as RGB triplets
b = [0, 141, 201]/255;
g = [0, 179, 9]/255;
y = [247, 227, 40]/255;
% Build the numeric colours array
color = [b; g; g; g; y; y; g; g; g; b];
% Plot using histcounts and bar
[h,edges] = histcounts(x,10); % calculate the histogram data. 10 = size(color,1)
b = bar( (edges(1:end-1)+edges(2:end))/2, h ); % plot the bar chart
b.BarWidth = 1; % make the bars full width to look the same as 'histogram'
b.CData = color; % color is a 10x3 array (columns are RGB, one row per bar)
b.FaceColor = 'flat'; % Make 'bar' use the CData colours
Tip: you can find RGB colour values easily using any number of colour pickers online, but Googling "color picker" will give you one at the top of Search, from which you can copy the RGB values. Note that MATLAB expects values between 0 and 1, not 0 and 255.
In R2007b b = hist() indeed outputs a 1x11 double array, being the counts in each bin. This means that you cannot use the regular syntax to output a figure handle that way. Citing the documentation:
n = hist(Y) bins the elements in vector Y into 10 equally spaced containers and returns the number of elements in each container as a row vector. (...)
Solution 1:
Call hist(__); b = get(gcf);, i.e. force a figure handle. Check its properties on where the CData-equivalent property is. (On R2007b you need to do b = get(gcf);, followed by set(b, 'Color', color))
Solution 2:
Use the nowadays recommended histogram(). You can check its property list, you need to set
b.FaceColor = color;
b.EdgeColor = color;
However, as is already noted in this question hist(), and also histogram(), do not natively support the handling of multiple colours. That means that either of the above tricks need to be applied on a per-colour basis. In other words: first plot everything you want to have the colour blue with histogram( __, 'FaceColor', 'b', 'EdgeColor', 'b'), then the same for the green graph etc.

Matlab plotting specific points on x-axis

I want to plot a function with markers where f(x)=0.
I have a function findmanyzeros that returns an array of x-values where f(x)=0 within a range.
For example:
findmanyzeros(#(x)sin(x)-exp(-x), 0, 10, 50, 1e-10);
ans = [0.5885 3.0964 6.2850 9.4247]
I am trying to plot the graph of f(x) and the zeros of f(x) that lie on the x-axis, but when I run the code below the resulting figure does not display the zeros.
How can I properly display the zeros of f(x) along the x-axis?
Also, how can I do it such that I'm not hardcoding the amount of values ([ 0 0 0 0])?
% Find zeros of f(x)
f = #(x)sin(x)-exp(-x);
zeros = findmanyzeros(f, 0, 10, 50, 1e-10);
% Plot f(x)
fplot(f, [0 10], 'linewidth', 2, 'color', 'b');
hold on
% Plot the x-axis
yline(0, 'linewidth', 2, 'color', 'r');
hold on
% Plot the zeros of f(x)
plot(zeros, [0 0 0 0], 'color', 'g', 'MarkerSize',20);
hold off
grid on
ylim([-1.5 1])
EDIT: I want my figure to look like this:
First of all, it is strongly recommended avoiding naming variables with names of existing functions, so calling your values vector "zeros" isn't a good idea, and you'll be better off with calling it "my_func_zeros" or something similar. zeros is a built-in matlab function used to create zeros-filled vectors/matrices.
As for your questions:
I believe you've just forgot to specify what type of marker you want, so by default it's an infinitely small point which won't appear. Further more, when using one of MATLAB's basic colors\markers, there is no need to specify the option name (will be more clear in the code line I'll attach).
You can use the function zeros and length to create a vector with a dependent size.
Therefor, your code should look somewhat like this:
my_func_zeros = findmanyzeros(f, 0, 10, 50, 1e-10);
...
plot(my_func_zeros, zeros(1,length(my_func_zeros)), '*g', 'MarkerSize',20);
where:
zeros(1,length(my_func_zeros))
creates a vector containing zeros with the size of your my_func_zeros vector, and:
'*g'
specifies the marker type (*) and the color (g).
By the way, there is no need to add hold on after every plot - after you wrote it once anything you plot will be plotted on the same figure until the next hold off or figure command.
Good luck!

Matlab: same colormap for hist, plot and mesh

I have datasets for 5 different frequencies in a matrix and I want to illustrate them using plot, hist and mesh. However, each plot type is using different colormaps (see picture), so I need a legend for every plot.
Is there a way to set the same colormap for all plot types, or specify one for each of them? Another thing thats strange: I can set the colormap for hist using the figure tools for example, but not for the normal plot. For the mesh I have to use a hold on loop, so I guess setting the color here is different from defining a colormap?
Edit:
Here is a minimal example. Its still not working, see comments in the code below.
clear all;
close all;
clc;
% make up some data with the original format
freqLen = 5;
data = zeros(10, 3, 3, freqLen);
data(:, :, :, 1) = rand(10, 3, 3);
data(:, :, :, 2) = rand(10, 3, 3)+1;
data(:, :, :, 3) = rand(10, 3, 3)+2;
data(:, :, :, 4) = rand(10, 3, 3)+3;
data(:, :, :, 5) = rand(10, 3, 3)+4;
% reshape data so we get a vector for each frequency
dataF = reshape(data, [10*3*3, freqLen]);
% prepare colors for plot, try to get 5 colors over the range of colormap
% but I get wrong colors using both methods below!
%cols = colormap(jet);
%cols = cols(1:round(length(cols)/length(freqGHz)):end, :);
cols = jet(freqLen);
% plot samples in 3D
figure('Position', [0 0 1000 1000]);
subplot(211);
hold on;
for iF = 1:freqLen
dataThisF = dataF(:, iF);
data3D = reshape(dataThisF, [10*3, 3]);
mesh(data3D);
% try to give each "holded" mesh a different color. Not working!
% after the loop, all meshes have the last color
set(get(gca, 'child'), 'FaceColor', 'w', 'EdgeColor', cols(iF, :));
end
view(60, 20);
% plot samples
subplot(223);
hold on;
for iF = 1:freqLen
% the loop is not avoidable
% because matlab maps the colors wrong when plotting as a matrix
% at least its not using the colormap colors
plot(dataF(:, iF), 'Color', cols(iF, :));
end
% plot histogram
subplot(224);
% actually the only one which is working as intended, horray!
hist(dataF, 50);
How can I give a holded mesh a single color, different from the others? How can I map the correct jet colormap when plotting a matrix using simple line plot, or at least get 5 colors from the jet colormap (jet(5) give 5 different colors, but not from start to end)?
What you are talking about is mainly the ColorOrder property (and not the colormap of the figure).
The link for the colororder given just above will explain you how to force Matlab to use a given set of colors for all the plots. It works perfectly fine for plot. You wouldn't need a loop, just define the DefaultColororder property of the figure before the plots then plot all your series in one single call, Matlab will assign the color of each plot according to the order you defined earlier.
For mesh and hist it is not that simple unfortunately, so you will have to run a loop to specify the color or each graphic object. To modify a graphic object property (like the color) after it has been created, you have to use the set method, or even the direct dot notation if you're using a Matlab version >= 2014b. For both methods you needs to have the handle of the graphic object, so usually the easiest when you know you'll need that is to retrieve the graphic object handle at the time of creation*.
*instead of dirty hack like get(gca, 'child'). This is quite prone to errors and as a matter of fact was wrong in your case. Your code wouldn't color properly because you were not getting the right graphic handle this way.
The code below plots all your graphs, retrieve the handle of each graphic object, then assign the colors in the final loop.
%// Get a few colors
cols = jet(freqLen);
% plot samples in 3D
figure('Position', [0 0 1000 1000]);
set( gcf , 'DefaultAxesColorOrder',cols) %// set the line color order for this figure
subplot(2,1,1,'NextPlot','add'); %// 'NextPlot','add' == "hold on" ;
for iF = 1:freqLen
dataThisF = dataF(:, iF);
data3D = reshape(dataThisF, [10*3, 3]);
h.mesh(iF) = mesh(data3D) ; %// plot MESH and retrieve handles
%// You can set the color here direct, or in the last final "coloring" loop
%// set( h.mesh(iF) , 'FaceColor', 'w', 'EdgeColor', cols(iF, :));
end
view(60, 20);
%// plot samples
subplot(223);
h.plots = plot(dataF); %// plot LINES and retrieve handles
%// plot histogram
subplot(224);
[counts,centers] = hist(dataF, 50 ) ; %// get the counts values for each series
h.hist = bar(centers,counts) ; %// plot HISTOGRAM and retrieve handles
%// now color every series with the same color
for iF = 1:freqLen
thisColor = cols(iF, :) ;
set( h.mesh(iF) , 'EdgeColor' , thisColor , 'FaceColor', 'w' );
set( h.hist(iF) , 'EdgeColor' , thisColor , 'FaceColor' , thisColor )
%// this is actually redundant, the colors of the plots were already right from the
%// beginning thanks to the "DefaultColorOrder" property we specified earlier
set( h.plots(iF) , 'Color' , thisColor )
end
Will land you the following figure:
UPDATE: The original question asked
Is there a way to set the same colormap for all plot types, or specify one for each of them?
this answer, answers that question with colormap taken to mean colormap in MATLAB literally.
You can set the colormap for a figure using colormap. You could use one of the many built in colormaps or specify your own.
An example using mesh and the builtin hsv colormap could be
figure;
mesh(data);
colormap(hsv);
This would apply a colormap based on
to your figure. You can also create your own colormap like
map = [1, 0, 0,
1, 1, 1,
0, 1, 0,
0, 0, 0];
colormap(map);
which would create a colormap with the colours Red, White, Blue and Black.
The MATLAB documentation contains extensive information on the use of colormap.

How to do definitely associate colors to values in a heatmap in Matlab?

I have a matrix M of integers (1, 2 or 3). I'd like to represent it with a heatmap and associate a fixed color to 1, 2 and 3. I use this piece of code :
map = [1, 1, 0; % color for 1 (yellow)
1, 0.5, 0 ; % color for 2 (orange)
0, 1, 0.5]; % color for 3 (green)
HeatMap(M,'Colormap',map,'Symmetric','false');
When M contains at least one 1, one 2 and one 3, there isn't any problem. But when M contains only 3s for example, the heatmap isn't as I want (all green).
How can I solve this problem?
It doesn't look like you can do this easily.
In Matlab 2013b or older (I haven't tried in 2014b) when you call HeatMap it internally goes through a process of creating axes and settin the colors and so on. Eventually it gets to a point inside plot.m where the following function is called:
function scaleHeatMap(hHMAxes, obj)
%SCALEHEATMAP Update the CLIM in image axes
if obj.Symmetric
maxval = min(max(abs(obj.Data(:))), obj.DisplayRange);
minval = -maxval;
else
maxval = min(max(obj.Data(:)), obj.DisplayRange);
minval = min(obj.Data(:));
end
set(hHMAxes, 'Clim', [minval,maxval]);
end
This function does actually define the limits of the colormap using the axes of the heatmap (hHMAxes), but that object is not returned by the HeatMap() call, unfortunately.
The only ways I can think of getting out of this problem are:
Modify the plot.m function. This is generally a quite bad idea.
Create a myHeatMap function, that does everything the original one does but with a changed functionality on the Clim property on the axes.
Do not use HeatMap at all and create an equally looking plot using e.g. surf or imshow.
Do an if statement before the call of HeatMap, and check if there is a single value in the colormap (numel(unique(M(:)))==1), and if that happens, change your map to a single valued colormap, with the color of your choice.
The easiest one is by far 4.
The easiest would be not to use HeatMap which is a quite inconvenient function based on Java.
Rather use imagesc or pcolor where you can easily fix the color axis with caxis:
map = [1, 1, 0; % color for 1 (yellow)
1, 0.5, 0 ; % color for 2 (orange)
0, 1, 0.5]; % color for 3 (green)
%// left plot
subplot(131)
M = randi(3,3,3);
imagesc(M)
colormap(map)
caxis( [1 3] )
%// right plot
subplot(132)
M = 3*ones(3);
imagesc(M)
colormap(map)
caxis( [1 3] )
%// legend
subplot(133)
set(gca,'visible','off')
c = colorbar
caxis( [1 3] )
c.Ticks = [1.25,2,2.75]
c.TickLabels = 1:3

Setting colors for plot function in Matlab

I would like to be able to choose the colors for a multiline plot but I can not get it. This is my code
colors = {'b','r','g'};
T = [0 1 2]';
column = [2 3];
count = magic(3);
SelecY = count(:,column),
plot(T,SelecY,'Color',colors{column});
For some reason I couldn't get it to work without using a handle, but:
h = plot(T,SelecY);
set(h, {'Color'}, colors(column)');
Works for me.
You can only specify one color at a time that way, and it must be specified as a 3-element RGB vector. Your three routes are:
Loop through and specify the colors by string, like you have them:
hold on
for i=1:size(SelecY, 2)
plot(T, SelecY(:,i), colors{i});
end
Using the RGB color specification, you can pass the colors in via the 'Color' property, like you were trying to do above:
cols = jet(8);
hold on
for i=1:size(SelecY, 2)
plot(T, SelecY(:,i), 'Color', cols(i,:));
end
Also using the RGB way, you can specify the ColorOrder up front, and then let matlab cycle through:
set(gca, 'ColorOrder', jet(3))
hold all
for i=1:size(SelecY, 2)
plot(T, SelecY(:,i));
end
For setting colors after the fact, see the other answer.