I am wishing to use Matlab to achieve the following goal:
I have a function that takes in two inputs and gives a real number.
function T = SS(x,y)
%%% some calculation %%%
T = returnval
I want the point (x,y) in the x-y plane to be coloured blue if the return value is equal to 1, green if the return value is equal to 0.5 etc.
I don't know how to approach this.
(the calculation is complicated so it is not obvious what's the relationship between x and y with respect to z. Thus can't write an equation to divide the region then colour accordingly.)
Thanks for helping.
If you can group all your T's into a vector, you can use scatter to make the plot. Then just setup your own colormap. Here's an example:
%// Sample data
[x,y]=meshgrid(0:.1:2);
x=x(:);y=y(:);
T=rand(size(x));
%// Define the colormap
MAP=[1 0 0; %// red
0 1 0; %// green
0 0 1]; %// blue
colormap(MAP) %// apply the colormap
scatter(x,y,[],T) %// make the plot
MAP is a matrix, and each row defines a colour. In this case, there are three rows, so elements with values between 0 and 1/3 will be red, elements with values between 1/3 and 2/3 will be green, and elements between 2/3 and 1 will be blue. In general, the range of T values (i.e. max(T)-min(T)) is evenly divided into each colour defined by MAP.
Related
I'm creating a pie graph.
pie([a,b,c,d]);
Is it possible to explicitly change the color of the individual slices?
For example; if I wanted the slices for a and b to always be green and c and d to always be blue, regardless of their size, how would I do that? It seems to me that a color map shades using the size of the slice not necessarily the order in which it was given to the pie function.
The colors of the pie are determined by the axis colormap. So define a matrix with as many rows as the number of pie wedges, and use that as colormap. The first color refers to the first value (a), etc.
For example:
pie([3 2 4 1])
colormap([1 0 0; %// red
0 1 0; %// green
0 0 1; %// blue
.5 .5 .5]) %// grey
I want to classify pixels of one tiff image according to pixel's RGB colour. The input is an image and three predefined colours for water(r0,g0,b0), forest(r1,g1,b1) and building(r2,g2,c2). The classification is based on the distance between image pixel and these three colors. If a pixel is closet to the water, the pixel is water and changed it the water RGB. The distance is calculated as (one sample) sqrt((x-r0)^2+(y-g0)^2+(z0-b0)^2)
The sample implementation is:
a=imread(..);
[row col dim] = size(a); % dim =3
for i=1:row
for j=1:col
dis1=sqrtCal(a(i,j,:)-water)
dis2=sqrtCal(a(i,j,:)-forest)
dis3=sqrtCal(a(i,j,:)-build)
a(i,j,:) = water;
if dis2< dis1
dis1 = dis2
a(i,j,:) = forest
end
dis3=sqrt(a(i,j,:)-build)
if dis3<dis1
a(i,j,:) = build
end
end
end
This implementation should work. The problem is that the two for loops is not a good choice.
So is there any good alternatives in the Matlab? The
D = pdist(X,distance)
Seems not appliable for my case.
I think this does what you want. The number of reference colors is arbitrary (3 in your example). Each reference color is defined as a row of the matrix ref_colors. Let MxN denote the number of pixels in the original image. Thus the original image is an MxNx3 array.
result_index is an MxN array which for each original pixel contains the index of the closest reference color.
result is a MxNx3 array in which each pixel has been assigned the RBG values of the closest reference color.
im = rand(10,12,3); %// example image
ref_colors = [ .1 .1 .8; ... %// water
.3 .9 .2; ... %// forest
.6 .6 .6 ]; %// build: example reference colors
dist = sum(bsxfun(#minus, im, permute(ref_colors, [3 4 2 1])).^2, 3);
%// 4D array containing the distance from each pixel to each reference color.
%// Dimensions are: 1st: pixel row, 2nd: pixel col, 3rd: not used,
%// 4th: index of reference color
[~, result_index] = min(dist, [], 4); %// compute arg min along 4th dimension
result = reshape(ref_colors(result_index,:), size(im,1), size(im,2), 3);
This one is another bsxfun based solution, but stays in 3D and could be more efficient -
%// Concatenate water, forest, build as a 2D array for easy processing
wfb = cat(2,water(:),forest(:),build(:))
%// Calculate square root of squared distances & indices corresponding to min vals
[~,idx] = min(sum(bsxfun(#minus,reshape(a,[],3),permute(wfb,[3 1 2])).^2,2),[],3)
%// Get the output with the minimum from the set of water, forest & build
a_out = reshape(wfb(:,idx).',size(a))
If you have the statistics toolbox installed, you can use this version based on knnsearch, that scales well for a large number of colors.
result_index = knnsearch(ref_colors, reshape(im,[],3));
result = reshape(ref_colors(result_index,:), size(im));
I have a matrix (200 x 4) where first 3 values are X, Y and Z data. I want use the fourth column to display each (X,Y,Z) triplet so that it maps to a color.
The fourth column contains values from 0.0 to 1.0 (200 values). I want to map these values with colormap manually and linearly. The smallest value should have blue color and the largest value may have red color.
I know that it is possible with scatter3. However, I want to do using stem3 where I can specify the color manually from colormap.
Is there a way to do this in MATLAB?
That's pretty simple to do. kkuilla posted a very insightful link. To get something started, if you want to have a colour map that varies from blue to red, you know that an image is decomposed into three colours: Red, green and blue.
Therefore, all you would have to do is vary the red and blue channels. Start with a pure blue colour, which is RGB = (0,0,255) where this is mapped to the initial weight of w = 0 and vary this to the end where RGB = (255,0,0) with w = 1. You can very easily do that by linspace. However, colours in a colour map for plotting in MATLAB are normalized so that they're between [0,1], not [0,255]. Also, because a colour map in MATLAB is a matrix of N x 3, where N is the total number of colours you want, all you have to do is:
num_colours = 10;
colourmap = [linspace(0,1,num_colours).' zeros(num_colours,1) linspace(1,0,num_colours).'];
weights = linspace(0,1,num_colours);
num_colours is the total number of colours you would like displayed. I set it to 10 to get you started. weights is something we will need for later, so don't worry about that righ tnow. Essentially, colormap would be the colour map you apply to your data.
However, what is going to be difficult now is that the data that you're plotting has no correlation to the weight of the data itself (or the fourth column of your data). This means that you can't simply use the (X,Y,Z) data to determine what the colour of each plot in your stem is going to look like. Usually for colour maps in MATLAB, the height of the stem is proportional to the colour that is displayed. For the largest Z value in your data, this would naturally be assigned to the colour at the end of your colour map, or red. The smallestZ value in your data would naturally get assigned at the beginning of your colour map, or blue.
If this was the case, you would only need to make one stem call and specify the colour map as the attribute for Color. Because there is no correlation between the height of the Z value and the weight that you're assigning for each data point, you have no choice but to loop through each of your points and determine the closest value between the weight for a point with every weight and ultimately every colour in your colour map, then apply this closest colour to each point in your stem respectively.
We determine the closest point by using the weights vector that was generated above. We can consider each colour as having a mapping from [0,1], and each weight corresponds to the colour in colourmap. Therefore, a weight of 0 is the first colour in the colour map, and that's in the first row. The next weight after this is the second colour, and that's in the second row and so on.... so we simply need to determine where each weight that's in the fourth column of your matrix is closest to for the above weights vector. This will determine which colour we need to select from the colour map to plot the point.
Given that your matrix of 200 x 4 is stored in data, you must specifically do this:
%// Spawn a new figure
figure;
%// Determine the number of points in the dataset
num_points = size(data,1);
%// For each point in the data set
for idx = 1 : num_points
%// Get 4th column element and determine closest colour
w = data(idx,4);
[~,ind] = min(abs(weights-w));
color = colourmap(ind,:);
%// Plot a stem at this point and change the colour of the stem
%// as well as the marker edge colour and face colour
stem3(data(idx,1), data(idx,2), data(idx,3), 'Color', color, ...
'MarkerEdgeColor', color, 'MarkerFaceColor', color);
%// Make sure multiple calls to stem don't clear the plot
hold on;
end
%// Display colour bar to show colours
colormap(colourmap(1:end-1,:));
colorbar('YTickLabel', colourmap);
The last two lines are a bit hackish, but we basically show a colour bar to the right of the plot that tells you how each weight maps to each colour.
Let's test this on some data. I'm going to generate a random 200 x 4 matrix of points and we will use the above code and plot it using stem3:
rng(123123); %// Set seed for reproducibility
data = rand(200,4);
num_colours = 10;
I set the total number of unique colours to 10. Once I have this above data, when I run through the code above, this is the plot I get:
You can use HSV as well. The Z values would correspond to your fourth column. Low Z values are blue and high Z values are red.
I used the site http://colorizer.org/ to work out that blue is H=0.65 and red is H=1. S and V stay the same.
From http://colorizer.org/, I got that a blue colour is H=236, S=100, V=100. Then the H value for blue is H = 235/360 = 0.65 and H=1, S=1, V=1 for red.
num_elem = 200;
c = linspace(0,1,num_elem)'; % // Replace this with the values from your fourth column
% // The equation gives blue (H=0.65) for c=0 and red (H=1) for c = 1
H = 0.65 + ((1-0.65).* c);
S = ones(size(c,1),1);
V = ones(size(c,1),1);
% // You have to convert it to RGB to be compatible with stem3
colourmap = hsv2rgb([H,S,V]);
% // Generate some sample data
theta = linspace(0,2*pi,num_elem)';
X = cos(theta);
Y = sin(theta);
Z = theta;
% // Plot the sample data with the colourmap
figure;
hold on;
for idx=1:num_elem
stem3(X(idx),Y(idx),Z(idx),':*','Color',colourmap(idx,:) ...
,'MarkerEdgeColor',colourmap(idx,:) ...
,'MarkerFaceColor',colourmap(idx,:) ...
,'LineWidth',4 ...
);
end
hold off;
set(gca,'FontSize',36');
I populate a grid data=zeros(n,n); with 0's and 1's (could also be thought of as an adjacency grid, if you'd like). I just want to plot the grid with colors according to whether the value at that point is 0 or 1. For example,
scatter(1:n,1:n,data);
It gives me the error:
Error using scatter (line 77)
C must be a single color, a vector the same length as X, or an M-by-3 matrix.
Any suggestions?
you are telling matlab to plot only n points ((1,1), (2,2), ..., (n,n)) where you want actually the cartesian product (1:nX1:n).
Try
[X,Y] = meshgrid(1:n,1:n);
scatter(X(:), Y(:), 10, data(:));
scatter allows you to plot points with different options (color, size, etc) for each point depending on a 'Z' value, but it creates a lot of graphic objects (one for each point).
In your case, you only have 2 subsets of data (among all your points). The points with value 1 and with value 0. So another option is to extract these 2 subsets then plot each subset with each a set of common properties.
%% // prepare test data
n = 10 ;
data=randi([0 1],n); %// create a 10x10 matrix filled with `0` and `1`
%% // extract the 2 subsets
[x0 , y0] = find( data == 0 ) ;
[x1 , y1] = find( data == 1 ) ;
%% // display
figure ; axes('Nextplot','add')
plotOptions = {'LineStyle','none','MarkerEdgeColor','k','MarkerSize',10} ; %// common options for both plots
plot(x0,y0,'o','MarkerFaceColor','r', plotOptions{:} ) %// circle marker, red fill
plot(x1,y1,'d','MarkerFaceColor','g', plotOptions{:} ) %// diamond marker, green fill
This way you have full control on each subset property (you can control the size, color, shape etc...). And you only have 2 graphic objects to handle (instead of n^2).
Say I have a data set with x values of longitude and Y values of 1 to 100. How can I plot the whole data set and represent all Y values over 90 with a different symbol?
Thanks for the help!
The easiest way would be to plot the sets separately, and specify a different symbol for each set i.e.
plot(x(Y<=90),Y(Y<=90),'bx',x(Y>90),Y(Y>90),'bo');
You could also do different colors. The scatter function has the ability to specify a different color for each point with the syntax scatter(x,y,s,c). For your example, you could do:
% make data
rng(0,'twister'); theta = linspace(0,2*pi,150);
x = sin(theta) + 0.75*rand(1,150); x = x*100;
y = cos(theta) + 0.75*rand(1,150); y = y*100;
mask = y>90;
% plot with custom colors for each point
c = zeros(numel(x),3); % matrix of RGB colorspecs
c(mask,:) = repmat([1 0 0],nnz(mask),1); % red
c(~mask,:) = repmat([0 0 1],nnz(~mask),1); % blue
scatter(x,y,10,c,'+');
Or instead of and RGB colorspec matrix, you can index into the current colormap. This allows you to get a nice smooth variation with some value:
scatter(x,y,10,y+x,'o') % x+y is mapped to indexes into default colormap, jet(64)
You can combine this color mapping with the approach of separating the data into two sets to also get different markers. Split the data, plot the first set with scatter as above, hold on, and plot the second set with a different marker. For example,
cv = x+y; % or just y, but this is an interesting example
scatter(x(mask),y(mask),10,cv(mask),'+');
hold on
scatter(x(~mask),y(~mask),10,cv(~mask),'o');
The result is different marker styles, where '+' is used where y>90 and '+' elsewhere, and different colors, where color is determined by mapping the values of cv=x+y onto the current colormap. The idea here is to look at 2 different modes of variations, but you could just use cv=y.