How to change bars colour in MATLAB - matlab

I am new to programming so I am learning introductory to MATLAB I was wondering how you could change colours of bar in MATLAB.
this is my script. Can someone please help!!
x =[1:8]
for y = [20 30 40 50 60 70 80]
bar(x,y)
if y < 40
col = 'b';
else if y > 40
col= 'g';
end
end
end
i also tried bar(x,y, r) but it doesnt work

Whilst this is overkill for your specific question, in general, to change the colour of bars depending on their height, you can apply a colormap to the bars. This is mainly from the bar documentation.
x = 1:8;
y = 10*x;
h=bar(y); %// create a sample bar graph
For the colormap MAP, you do this:
colormap(MAP)
ch = get(h,'Children');
fvd = get(ch,'Faces');
fvcd = get(ch,'FaceVertexCData');
[zs, izs] = sort(y);
for i = 1:length(x)
row = izs(i);
fvcd(fvd(row,:)) = i;
end
set(ch,'FaceVertexCData',fvcd)
hold off
And, for example, using the builtin colormap hsv, you get
But in this case we want a very specific colormap,
b=40 %// the cut-off for changing the colour
MAP=zeros(length(x),3); %// intialise colormap matrix
MAP(y<b,:)=repmat([0 0 1],sum(y<b),1); %// [0 0 1] is blue, when y<40
MAP(y>=b,:)=repmat([0 1 0],sum(y>=b),1); %// [0 1 0] is green, for y>=40
colormap(MAP)
which gives

To use two different colors depending on y: compute a logical index depending on y values and call bar twice with appropriate arguments:
x = [1:8];
y = [20 30 40 50 60 70 80];
ind = y < 40; %// logical index
bar(x(ind), y(ind), 'facecolor', 'b', 'edgecolor', 'k') %// blue bars, black edge
hold on %// keep plot
bar(x(~ind), y(~ind), 'facecolor', 'g', 'edgecolor', 'k') %// green bars, black edge
set(gca,'xtick',x)

bar can take third argument, which is color value, e.g. bar(x,y, 'r').

Related

Consulting waterfall chart matlab

I was trying to create "consulting" waterfall chart in matlab, and I am having a really difficult time in creating it. I was expecting actually that there would be a built in way of doing that.
Given this data:
x = [5, 2, -5, 8, 2, 12];
total = [1, 0, 0 ,0 ,0, 1];
I want to make a waterfall chart.
Basically, the vector x has the values for the chart and the vector total indicates whether the corresponding column is a total column or not.
So the first column, is a 5 and is a total column. The second column is a two and it is not (so it adds up). The third column is minus five so it subtracts, and so on and so forth until the last column which is a total again. Below how the figure would look like.
1) How to get this figure?
2) How to color increases, decreases and totals with different colors?
3) How to include the connecting lines?
Method 1
Here's one possible solution using MATLAB's bar function.
Assumptions:
The total columns are always the first and last columns.
The basic idea is to use the 'Baseline' property of a Bar object, which allows a particular bar to start from a specific value. For example, bar([1,3,5], 'BaseValue', 2) produces 3 bars that start from the value 2: the first going down by 1 unit, the second going up by 1 unit, and the last going up by 3 units.
From testing on R2019b, unfortunately it appears that all Bar objects on an Axes must share the same BaseValue. Thus, for each Bar object to have its own Baseline value, each of them must be on a separate Axes object. We can workaround this by overlaying a bunch of Axes (one for each Bar) on top of each other, making all but one of them transparent. This way all bars will be visible.
Anyways, here's the function. The inputs are
ax (optional): a handle to an existing Axes object. You may want to do this if you have other things plotted already, or if you want to manually set various properties of an Axes.
y: a vector of all the incremental values. Note: the final value is NOT required, i.e. to reproduce the plot in the question, use y=[5, 2, -5, 8, 2];
The function outputs the handles to each Bar object created. You may want this to further change the EdgeColor of the Bars.
function h = wfall(ax, y)
if nargin == 1
y = ax;
ax = gca;
end
if ~strcmp(ax.NextPlot, 'add')
fprintf('hold on not set for current axes. Overriding.\n');
hold(ax, 'on');
end
y = y(:); % column vector
n = length(y);
cumy = cumsum(y);
set(ax, 'XLim', [0, n+1]+0.5, 'YLim', [min(min(cumy), 0), max(max(cumy), 0)]);
% colors:
% decrease - red - code as -1
% total - black - code as 0
% increase - blue - code as 1
set(ax, 'CLim', [-1, 1], 'ColorMap', [1 0 0; 0 0 0; 0 0 1]);
% copy a bunch of axes
for i = 1:n
ax(i+1) = copyobj(ax(1), ax(1).Parent);
end
% Make all subsequent axes invisible
% Make sure all axes will always be the same size by linking properties
set(ax(2:end), 'Color', 'none', 'XColor', 'none', 'YColor', 'none');
linkprop(ax, {'XLim', 'YLim', 'Position', 'DataAspectRatio'});
% define from/to of each bar (except 1st and last)
from = cumy(1:n-1);
to = cumy(2:n);
% color of each bar (except 1st and last)
c = double(y>0) - double(y<0);
c(1) = [];
% first total bar
h = bar(ax(1), 1, from(1), 'CData', 0, 'BaseValue', 0);
% 2nd to 2nd last bars
for i = 1:n-1
h(end+1) = bar(ax(i+1), i+1, to(i), 'CData', c(i), 'BaseValue', from(i), 'ShowBaseLine', 'off');
end
% last total bar
h(end+1) = bar(ax(1), n+1, cumy(n), 'CData', 0);
% setting FaceColor flat makes the Bars use the CData property
set(h, 'FaceColor', 'flat')
Run the code as follows to produce the following plot.
close all;
ax = gca;
h = wfall(ax, y(1:end-1));
Method 2
Here's another solution if you prefer not to stack Axes objects on top of each other.
In this case, we make an additional assumption:
The cumulative value is never negative (this would apply, for example, the cash in my pocket)
Simply, each bar we draw can be considered as one colored bar (either blue/red) that is partially covered by a shorter white bar.
function h = wfall2(ax, y)
if nargin == 1
y = ax;
ax = gca;
end
if ~strcmp(ax.NextPlot, 'add')
fprintf('hold on not set for current axes. Overriding.\n');
hold(ax, 'on');
end
y = y(:); % column vector
n = length(y);
cumy = cumsum(y);
from = cumy(1:n-1);
to = cumy(2:n);
% color values:
% 1 - blue (increase)
% 0 - white
% -1 - red (decrease)
c = double(y>0) - double(y<0);
c(1) = [];
upper = max(cumy(1:n-1), cumy(2:n));
lower = min(cumy(1:n-1), cumy(2:n));
h(1) = bar(ax, 2:n, upper, 'FaceColor', 'flat', 'CData', c);
h(2) = bar(ax, 2:n, lower, 'FaceColor', 'w');
h(3) = bar(ax, 1, cumy(1), 'FaceColor', 'k');
h(4) = bar(ax, n+1, cumy(n), 'FaceColor', 'k');
set(h, 'EdgeColor', 'none')
set(ax, 'CLim', [-1, 1], 'ColorMap', [1 0 0; 0 0 0; 0 0 1]);
Run the function as follows:
close all;
ax = gca;
h = wfall2(ax, y(1:end-1));
The resulting plot:
The result, however, is a bit ugly by my personal standards, since the white bar will partially cover the x-axis. You can fix this, however, by setting the lower YLim to a negative value, i.e. set(ax, 'YLim', [-0.5 inf])

Make squared in legend instead of lines Matlab

I have the following code, which plots a 'map' using imagesc, and provides a legend, see output attached.
I am trying to replace the lines in the legend with solid squares. My attamps to far leave the lines and ad hollow squares (including a random square in the top left corner of the figure)
figure(6)
imagesc(lut)
title('Ditribution of Land use Types')
ylabel('Longitude')
xlabel('Latitude')
caxis([0, 7])
myColorMap = jet(6);
imagesc(lut, 'AlphaData', ~isnan(lut))
colormap(myColorMap);
L = line(ones(6), ones(6));
set(L, {'Color'}, num2cell(myColorMap, 2))
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
set(L(:),'Marker','s')
grid on
ax = gca
ax.GridAlpha = .2
ax.XTick = [5 10 15 20 25 30 35 40];
ax.YTick = [5 10 15 20 25 30];
ax.XTickLabel = {'118^{o}E','123^{o}E','128^{o}E', '133^{o}E', '138^{o}E', '143^{o}E','148^{o}E', '153^{o}E'};
ax.YTickLabel = {'13^{o}S','18^{o}S','23^{o}S','28^{o}S','33^{o}S','38^{o}S'};
ax.TickLength =[0.0 0.0]
Use nan to create invisible data (thanks #matlatbgui), and set L with all needed properties for no line and filled square markers:
% some arbitrary data:
N = 30;
lut = diag(1:N)*ones(N)+(diag(1:N)*ones(N)).';
% coloring settings:
caxis([0, 7])
myColorMap = jet(6);
% plotting:
imagesc(lut, 'AlphaData', ~isnan(lut))
colormap(myColorMap);
% Setting the legend:
L = line(nan(6), nan(6),'LineStyle','none'); % 'nan' creates 'invisible' data
set(L, {'MarkerEdgeColor'}, num2cell(myColorMap, 2),...
{'MarkerFaceColor'},num2cell(myColorMap, 2),... % setting the markers to filled squares
'Marker','s');
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
and you don't need your line:
set(L(:),'Marker','s')
The square on the upper-left corner is obviously due to set(L(:),'Marker','s') which draws a square at the start and end points of the lines, at [1, 1]. Instead of changing the 'Marker', if you increase the 'LineWidth', you get much better results with:
L = line(ones(6), ones(6));
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
set(L(:), 'LineWidth', 10)
With this output:
So if you are not restricted to make squares, I believe wide rectangles are better flags for color.

Adding a legend when using imagesc, including white for NaN

I have a 35x43 matrix of data with vales ranging from 1-6 and lots of NaNs.
I want to NaNs to be white, and the numbers to each be a different colour. I need a legend with the 6 different colour and labels on it.
I can achieve most of this with the following code, however the colours in the legend do not match the colours in the figure. See code below
figure(6)
subplot(1,2,1)
imagesc(lut)
title('Highest Weighted Predictor variable for each Pixel')
ylabel('Longitude')
xlabel('Latitude')
caxis([0, 7])
myColorMap = jet(7);
myColorMap(1,:) = 1;
colormap(myColorMap);
M = jet(7); % Notice the 3, here and below
hold on
L = line(ones(7),ones(7));
set(L,{'color'},mat2cell(M,ones(1,7),3))
[legh,objh,outh,outm] = legend('First','Second','Location','Southeast');
set(objh,'linewidth',200);
legend('Forest','Shrubland','Savanna','Grassland','Agricultural','Barron');
grid on
ax = gca
ax.GridAlpha = .2
ax.XTick = [5 10 15 20 25 30 35 40];
ax.YTick = [5 10 15 20 25 30];
ax.XTickLabel = {'118^{o}E','123^{o}E','128^{o}E', '133^{o}E', '138^{o}E', '143^{o}E','148^{o}E', '153^{o}E'};
ax.YTickLabel = {'13^{o}S','18^{o}S','23^{o}S','28^{o}S','33^{o}S','38^{o}S'};
ax.TickLength =[0.0 0.0]
To display the NaN values as white I would use something like this. Then for your colormap, just use jet(6). Then the colors will match up just fine.
lut = [1:6 NaN];
myColorMap = jet(6);
imagesc(lut, 'AlphaData', ~isnan(lut))
colormap(myColorMap);
L = line(ones(6), ones(6));
set(L, {'Color'}, num2cell(myColorMap, 2))
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
I would suggest an alternative solution using a colorbar with individual ticks:
%// example data
lut = randi(6,35,43);
lut(1:23:end) = NaN;
%// parts of your your code
figure(6)
% subplot(1,2,1)
imagesc(lut)
title('Highest Weighted Predictor variable for each Pixel')
ylabel('Longitude')
xlabel('Latitude')
caxis([0, 7])
myColorMap = jet(7);
myColorMap(1,:) = 1;
colormap(myColorMap);
M = jet(7); % Notice the 3, here and below
hold on
%// colorbar
c = colorbar
c.Ticks = (1:6)+0.5
c.TickLabels = {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'}

MATLAB: How do I shade plot area with increasing and decreasing shades of a color

I want to plot an area of a graph (x = 1:24, y = -1:1) with one color (black), which I then want to decrease/increase in shading in terms of the time of day. So, that I have a plot which is 'dark' in the background at night and 'light' during the day with x being hours of day and y being a data value. My sunrise would be at 6.8 and my sunset would be at 22. I would then overlay scatter plots with data on top.
I have tried messing around with patch and area but with no luck. Here is some code I got from elsewhere on the internet but I'm not sure how to proceed:
% Define x, f(x), and M(x)
x = linspace(6.8, 22)';
f = sin(x)+cos(x);
M = x.^2;
% Define the vertices: the points at (x, f(x)) and (x, 0)
N = length(x);
verts = [x(:), f(:), x(:) zeros(N,1)];
% Define the faces to connect each adjacent f(x) and the corresponding points at y = 0.
q = (1:N-1)';
faces = [q, q+1, q+N+1, q+N];
p = patch('Faces', faces, 'Vertices', verts, 'FaceVertexCData', [M(:); M(:)], 'FaceColor', 'interp', 'EdgeColor', 'none')
So I want the end result to be similar to the image attached below (note faint shading - I would like the gradient stronger), but with x = 1:24 and y = -1:1.
Since you ignored my request to include the results of your MATLAB code in your question, I had to look into my crystal ball to determine that your "messing around" resulted in the following error message:
Error using patch
While setting the 'Vertices' property of Patch:
Value must be a 1x2 or 1x3 vector of numeric type
Error in X (line 13)
p = patch('Faces', faces, 'Vertices', verts, 'FaceVertexCData', [M(:); M(:)], 'FaceColor', 'interp', 'EdgeColor', 'none')
This can be resolved by concatenating the vertices vertically instead of horizontally in line 8:
verts = [x(:), f(:); x(:), zeros(N,1)];
This yields the following plot:
This is of course not what you want.
Actual Solution
You can build up your background from 5 rectangles:
x = [0;
6; % 'First daylight'
6.8; % Full brightness
22; % Beginning of 'sunset'
22.8; % Complete darkness
24];
vertices = [repmat(x,2,1), [ones(size(x)); -1.*ones(size(x))]];
faces = [1:5; 2:6; 8:12; 7:11].';
color = repmat([0 0 0; % 'Night' color
0 0 0;
1 1 1; % 'Day' color
1 1 1;
0 0 0;
0 0 0],2,1);
patch('Faces',faces, ...
'Vertices',vertices, ...
'FaceVertexCData',color, ...
'FaceColor','interp', ...
'EdgeColor','red');
xlim([0 24]);
You make the vertices of the 'night' rectangles black and the vertices of the 'day' rectangle white by assigning the appropriate RGB values to the FaceVertexCData property.
The color of 'sunrise'/'sunset' rectangles is then interpolated between black and white by setting the FaceColor property to 'interp'.
The EdgeColor has only been set to 'red' to illustrate how the background is constructed. Set the property to 'interp' to make the lines disappear.

How to create an interpolated colormap or color palette from two colors? [duplicate]

This question already has answers here:
How to create a custom colormap programmatically?
(2 answers)
Closed 7 years ago.
I'd like to create a color palette between two colors. For instance between Blue and Red with 20 or 50 instances.
How can this be achieved in Matlab R2014b?
You can use any kind of interpolation (e.g. interp1) to create your own custom colormap between two colors or multiple colors. A colormap is basically a 3-column matrix with RGB-values. In your case its pretty simple, as you just need red with [1 0 0] and blue [0 0 1] and linearly interpolated in between. linspace is therefore the best choice.
n = 50; %// number of colors
R = linspace(1,0,n); %// Red from 1 to 0
B = linspace(0,1,n); %// Blue from 0 to 1
G = zeros(size(R)); %// Green all zero
colormap( [R(:), G(:), B(:)] ); %// create colormap
%// some example figure
figure(1)
surf(peaks)
colorbar
Note that you could also use the the colormap GUI by typing colormapeditor.
Alternative you can also use 2D-interpolation:
n = 50; %// number of colors
cmap(1,:) = [1 0 0]; %// color first row - red
cmap(2,:) = [0 1 0]; %// color 25th row - green
cmap(3,:) = [0 0 1]; %// color 50th row - blue
[X,Y] = meshgrid([1:3],[1:50]); %// mesh of indices
cmap = interp2(X([1,25,50],:),Y([1,25,50],:),cmap,X,Y); %// interpolate colormap
colormap(cmap) %// set color map
%// some example figure
figure(1)
surf(peaks)
colorbar
And just another example using spline-interpolation to get wider areas of blue and red:
n = 50; %// number of colors
v = [0,0,0.1,0.5,0.9,1,1];
x = [-5*n,0, 0.45*n, 0.5*n, 0.55*n, n, 5*n];
xq = linspace(1,n,n);
vq = interp1(x,v,xq,'spline');
vq = vq - min(vq);
vq = vq./max(vq);
B = vq; %// Blue from 0 to 1 with spline shape
R = fliplr(B); %// Red as Blue but mirrored
G = zeros(size(R)); %// Green all zero
colormap( [R(:), G(:), B(:)] ); %// create colormap
%// some example figure
figure(1)
surf(peaks)
colorbar
Or use any mathematical function you want:
n = 50; %// number of colors
t = linspace(0,4*pi,50);
B = sin(t)*0.5 + 0.5; %// Blue from 0 to 1 as sine
R = cos(t)*0.5 + 0.5; %// Red from 0 to 1 as cosine
G = zeros(size(R)); %// Green all zero
colormap( [R(:), G(:), B(:)] ); %// create colormap
%// some example figure
figure(1)
surf(peaks)
colorbar