Coloring Bars from a histogram/bargraph - matlab

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.

Related

How to color multiple lines based on their value?

I produced a plot that contains 50 curves and each of them corresponds to a specific value of a parameter called "Jacobi constant", so I have 50 values of jacobi constant stored in array called jacobi_cst_L1:
3.000900891023230
3.000894276927840
3.000887643313580
3.000881028967010
3.000874419173230
3.000867791975870
3.000861196034850
3.000854592397690
3.000847948043080
3.000841330136040
3.000834723697250
3.000828099771820
3.000821489088600
3.000814922863360
3.000808265737810
3.000801695858850
3.000795067776960
3.000788475204760
3.000781845363950
3.000775192199620
3.000768609354090
3.000761928862980
3.000755335851910
3.000748750854930
3.000742084743060
3.000735532899990
3.000728906460450
3.000722309400740
3.000715644446600
3.000709016645110
3.000702431180730
3.000695791284050
3.000689196186970
3.000682547292110
3.000675958537960
3.000669315388860
3.000662738391370
3.000656116141060
3.000649560630930
3.000642857256680
3.000636330415510
3.000629657944820
3.000623060310100
3.000616425935580
3.000609870077710
3.000603171772120
3.000596554947660
3.000590018845460
3.000583342259840
3.000576748353570
I want to use a colormap to color my curves and then show in a lateral bar the legend that show the numerical values corresponding to each color of orbit.
By considering my example image, I would want to add the array of constants in the lateral bar and then to color each curve according the lateral bar.
% Family of 50 planar Lyapunov orbits around L1 in dimensionless unit
fig = figure;
for k1 = 1:(numel(files_L1_L2_Ly_prop)-2)
plot([Ly_orb_filt(1).prop(k1).orbits.x],[Ly_orb_filt(1).prop(k1).orbits.y],...
"Color",my_green*1.1); hold on %"Color",my_green*1.1
colorbar()
end
axis equal
% Plot L1 point
plot(Ly_orb_filt_sys_data(1).x,Ly_orb_filt_sys_data(1).y,'.',...
'color',[0,0,0],'MarkerFaceColor',my_green,'MarkerSize',10);
text(Ly_orb_filt_sys_data(1).x-0.00015,Ly_orb_filt_sys_data(1).y-0.0008,'L_{1}');
%Primary bodies plots
plot(AstroData.mu_SEM_sys -1,0,'.',...
'color',my_blue,'MarkerFaceColor',my_blue,'MarkerSize',20);
text(AstroData.mu_SEM_sys-1,0-0.001,'$Earth + Moon$','Interpreter',"latex");
grid on;
xlabel('$x$','interpreter','latex','fontsize',12);
ylabel('$y$','interpreter','latex','FontSize',12);
How can I color each line based on its Jacobi constant value?
You can use any colour map to produce a series of RGB-triplets for the plotting routines to read (Or create an m-by-3 matrix with elements between 0 and 1 yourself):
n = 10; % Plot 10 lines
x = 1:15;
colour_map = jet(n); % Get colours. parula, hsv, hot etc.
figure;
hold on
for ii = 1:n
% Plot each line individually
plot(x, x+ii, 'Color', colour_map(ii, :))
end
colorbar % Show the colour bar.
Which on R2007b produces:
Note that indexing into a colour map will produce linearly spaced colours, thus you'll need to either interpolate or calculate a lot to get the specific ones you need. Then you can (need to?) modify the resulting colour bar's labels by hand to reflect your input values. I'd simply use parula(50), treat its indices as linspace(jacobi(1), jacobi(end), 50) and then my_colour = interp1(linspace(jacobi(1), jacobi(end), 50), parula(50), jacobi).
So in your code, rather than using "Color",my_green*1.1 for each line, use "Color",my_colour(kl,:), where my_colour is whatever series of RGB triplets you have defined.

Color-coded representation of data in a 2-D plot (in MATLAB)

I have several 4 x 4 matrices with data that I would like to represent in a 2-D plot. The plot is supposed to show how the results of a simulation change with varying parameters.
On the y-axis I would like to have the possible values of parameter A (in this case, [10,20,30,40]) and on the x-axis I want to have the possible values of parameter B (in this case, [2,3,4,5]). C is a 4 x 4 matrix with the evaluation value for running the simulation with the corresponding parameter combination.
Example: The evaluation value for the parameter combination A = 10, B = 2 equals 12 dB. I would like to plot it at the cross section A and B (I hope you understand what I mean by this) and code the value by a fat colored dot (e.g. red means high values, blue means low values).
How can I do this? I would basically like to have something like mesh without lines.
I'm sorry for my imperfect English! I hope you understood what I would like to achieve, thank you in advance!
You can do this with the mesh command (and the built-in colormaps you can choose from can be found here, or you could even make your own):
[A, B] = meshgrid(10:10:40, 2:5); % Grids of parameter values
C = rand(4); % Random sample data
hMesh = mesh(A, B, C); % Plot a mesh
set(hMesh, 'Marker', '.', ... % Circular marker
'MarkerSize', 60, ... % Make marker bigger
'FaceColor', 'none', ... % Don't color the faces
'LineStyle', 'none'); % Don't render lines
colormap(jet); % Change the color map
view(0, 90); % Change the view to look from above
axis([5 45 1.5 5.5]); % Expand the axes limits a bit
colorbar; % Add colorbar
And here's the plot:

Using different intensities of a specific color for contour plots

This question is in reference to visualization of EM clustering(or K-means) of 2D gaussian data. Say, I have displayed 3 clusters obtained from EM in a scatter plot with 3 different colors(say r,g,b) for the data samples of 3 clusters. Now I want to plot elliptical contours on top of this. I don't want the color of each of the three countours vary over entire colorspectrum from r to b. For contours of cluster 1, I want varying intensities of red, for cluster 2, I want varying intensities of blue and same of cluster 3. I have set the number of concentric contours to be 5 and tried passing a Color array as follows, but it did not work.
ColorVec = ['r' ; 'g' ; 'b' ; 'm' ; 'c' ; 'y'; 'b'];
String2RBG = #(C)rem(floor((strfind('kbgcrmyw', C) - 1) * [0.25 0.5 1]), 2);
x = -3:0.1:4;
y = -3:0.1:4;
[X,Y] = meshgrid(x,y);
for k=1:numberOfClusters
Z = mvnpdf([X(:) Y(:)],estimatedMu(k,:),estimatedSigma{k});
Z = reshape(Z,length(y),length(x));
ColorVecConcentricCountours = [String2RBG(ColorVec(k));String2RBG(ColorVec(k))/1.2;String2RBG(ColorVec(k))/1.4;String2RBG(ColorVec(k))/1.6;String2RBG(ColorVec(k))/1.8];
contour(X,Y,Z,5,'color',ColorVecConcentricCountours);hold on;
end
Use of ColorVecConcentricCountours throws an error, but if I give ColorVec(k), it gives a single shade of r, g or b for all 5 contours which is not what I want.
Contour plots are groups of patch objects. Patch objects have an 'EdgeColor' property, which is what sets what we'd call the line color of the contours. You can set the edge colors of all contour objects in the figure with the contourcmap function, but since you want separate control over each of the groups of lines that won't work. What you can do, however, is to address the patch objects themselves and change the edge color of each one separately.
To start, I have written functions called green, cyan, and the rest of the RGB + CYM colors that allow me to use those as colormaps in addition to the built-in ones. The green function looks like this:
function G = green(m)
%GREEN Green Colormap
% GREEN(M) is an M-by-3 matrix colormap for increasing red intensity.
% GREEN, by itself, is the same length as the current figure's
% colormap. If no figure exists, MATLAB creates one.
%
% See also RED, JET, HSV, HOT, PINK, FLAG, COLORMAP, RGBPLOT.
if nargin < 1
m = size(get(gcf,'colormap'),1);
end
G = zeros(m,3);
G(:,2) = (0:(1/(m-1)):1);
You can take a look at the built-in functions to see how this one is similar. To run the code below you'll need a cyan function as well (or change that function call to whatever colormap function you'd like).
Armed with a couple of contour plots put into the same axes and their handles (H1 and H2 below) we can pull out the levels the contours are drawn at with the contour group's LevelList property, yielding a vector of each contour level. Each of the contour patch objects (children of the group) has the level that line was drawn at saved in the patch object's UserData property. We can use the group's LevelList property to make a matrix of colors we want to use, using the colormap function call, then the position of the contour line's level in the LevelList vector is the row of the colormap that we want to use to color that line. Change the EdgeColor of the patch object to that color for each line and we're good to go. Two groups are drawn here to show how to get two contour groups with different colors.
figure()
[C1, H1] = contour(linspace(-50, 0, 50), linspace(-50, 0, 50), peaks(50), 50);
hold on
[C2, H2] = contour(linspace(0, 50, 50), linspace(0, 50, 50), peaks(50), 20);
hold off
axis([-50 50 -50 50]);
levels1 = get(H1, 'LevelList');
cmap1 = green(numel(levels1));
child1 = get(H1, 'Children');
for m = 1:numel(child1)
cmapHere = cmap1(levels1 == get(child1(m), 'UserData'), :);
set(child1(m), 'EdgeColor', cmapHere);
end
levels2 = get(H2, 'LevelList');
cmap2 = cyan(numel(levels2));
child2 = get(H2, 'Children');
for m = 1:numel(child2)
cmapHere = cmap2(levels2 == get(child2(m), 'UserData'), :);
set(child2(m), 'EdgeColor', cmapHere);
end

Create a tailored colorbar in matlab

I have to create a map to show how far o how close some values are from a range and give them colors in consequence. Meanwhile, values that are within that range should have another different color.
For example: only the results that are within [-2 2] can be considered valid. For the other values, colors must show how far are from these limits (-3 lighter than -5, darker)
I've tried with colorbar but I'm not able to set up a self-defined color scale.
Any idea??
Thanks in advance!
You need to define a colormap for the range of values you have.
The colormap is N*3 matrix, defining the RGB values of each color.
See the example below, for a range -10:10 and valid values v1,v2:
v1=-3;
v2=+3;
a = -10:10;
graylevels=[...
linspace(0,1,abs(-10-v1)+1) , ...
ones(1, v2-v1-1) , ...
linspace(1,0,abs(10-v2)+1)];
c=repmat(graylevels , [3 1])';
figure;
imagesc(a);
colormap(c);
Here is some code that I just put together to demonstrate a simple means of creating your own lookup table and assigning values from it to the image that you're working with. I'm assuming that your results are in a 2D array and I just used randomly assigned values, but the concept is the same.
I mention the potentila use of HSV as a coloring scheme. Just note that, that requires you to have a m by n by 3 matrix. The top layer is the H - hue, 2nd being the S - saturation and the 3rd being the V or value (light/dark). Simply set the H and S to whatever values you want for the color and vary the V in a similar manner as shown below and you can get the varied light and dark color you want.
% This is just assuming a -10:10 range and randomly generating the values.
randmat = randi(20, 100);
randmat = randmat - 10;
% This should just be a black and white image. Black is negative and white is positive.
figure, imshow(randmat)
% Create your lookup table. This will illustrate having a non-uniform
% acceptable range, for funsies.
vMin = -3;
vMax = 2;
% I'm adding 10 here to account for the negative values since matlab
% doesn't like the negative indicies...
map = zeros(1,20); % initialized
map(vMin+10:vMax+10) = 1; % This will give the light color you want.
%linspace just simply returns a linearly spaced vector between the values
%you give it. The third term is just telling it how many values to return.
map(1:vMin+10) = linspace(0,1,length(map(1:vMin+10)));
map(vMax+10:end) = linspace(1,0,length(map(vMax+10:end)));
% The idea here is to incriment through each position in your results and
% assign the appropriate colorvalue from the map for visualization. You
% can certainly save it to a new matrix if you want to preserve the
% results!
for X = 1:size(randmat,1)
for Y = 1:size(randmat,2)
randmat(X,Y) = map(randmat(X,Y)+10);
end
end
figure, imshow(randmat)

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.