Plotting MATLAB values in two different colors - matlab

Anyway, I wish to plot two column vectors, filled with random numbers with no negative values in them, on a 2D plot(x and y).
The 'x-vector' I can leave as it is, but with the 'y vector', I wish to plot that any y values that is equal to zero as a different color(Say red) to the other positive non-zero values(Say blue).
Please try to keep solution relatively simple, if possible, as I myself am relatively new to MATLAB as well as to this site.

I'm not sure what you mean by 2D plot but I assuming you mean just a normal curve. Try this:
x = rand(10, 1);
y = rand(10, 1);
y([5 8]) = 0; %Force a couple of values to be 0 for visualisation
t = 1:10;
plot(t, x);
hold on
plot(t, y, 'g');
ind = y == 0; %Make a logical index that masks all the value where y is not 0
plot(t(ind), y(ind), 'r*');

Related

Non-rectangular meshgrids in MATLAB

I want to create a non-rectangular meshgrid in matlab.
Basically I have a polygon shaped feasible set I need to make a grid of in order to interpolate 3D data points in this set. The function for interpolation is given and requires finite (x, y, z) inputs. Where x is nx1, y is 1xm and z is nxm. Right now I have the mesh set up with linspace and set all NaN (infeasible) values to 0 before using my function, which is wrong of course (third figure).
Is there a simple solution for this?
I added a picture illustrating what I'm currently doing: First plot is the feasible set, second plot are solved sample data points in this set and third plot is the interpolation (currently still with rectangular meshgrid and NaN = 0). What I need is a meshgrid looking like the first figure (red polygon) instead of a rectangular one. In the third plot you can see that the rectangular meshgrid in combination with setting NaN to 0 (=infeasible values, not included in the red polygon set) results in a wrong interpolation along the edges, because it includes infeasible regions.
Here is my code using a rectangular meshgrid:
figure (2) %sample data
plot3(X0(1,:), X0(2,:), U, 'x')
%X0(1,:) and X0(2,:) are vectors corresponding to the Z-Values (blue sample data)
%X0 and U are in the feasible set (red polygon)
xv = linspace(xLb(1), xUb(1), 100);
yv = linspace(xLb(2), xUb(2), 100); %xLb and xUb are upper and lower bounds for the rectangle mesh
[x1,x2] = meshgrid(xv, yv);
Z = griddata(X0(1,:), X0(2,:), U, x1, x2);
%This grid obviously includes values that are not in the feasible set (red polygon) by its rectangular nature
Z(isnan(Z))=0; %set infeasible values to 0, wrong of course
testMPC = someInterpolationFunction([0:length(Z)-1]',[0:length(Z)-1],Z);
testMPC.showInterpolation(20,20)
%this shows figure 3 in the attached picture
Try something like this:
nRows = 100;
nCols = 200;
x1 = #(x) max(0, x-50);
x2 = #(x) min(nCols, nCols - 50 + x);
RR = zeros(nRows, nCols);
CC = zeros(nRows, nCols);
for iRow = 1:nRows
c1 = x1(iRow);
c2 = x2(iRow);
colVec = linspace(c1, c2, nCols);
RR(iRow, :) = iRow;
CC(iRow, :) = colVec;
end
mesh(RR, CC, zeros(size(RR)))
You'd need to redefine the functions for x1 and x2 or course as well as the scaling, but this should give you an idea of how to get started.

Volumetric 3D data plotting from 2D map in MATLAB?

I have a heat map
and want to convert this 2D matrix to a 3D volume/shape/surface data points for further processing. Not simply display it in 3D using surf.
What would be a good way to do this?
With a lot of help from this community I could come closer:
I shrunk the size to 45x45 px for simplicity.
I = (imread("TESTGREYPLASTIC.bmp"))./2+125;
Iinv = 255-(imread("TESTGREYPLASTIC.bmp"))./2-80;%
for i = 1:45
for j = 1:45
A(i, j, I(i,j) ) = 1;
A(i, j, Iinv(i,j) ) = 1;
end
end
volshow(A)
Its not ideal but the matrix is what I wanted now. Maybe the loop can be improved to run faster when dealing with 1200x1200 points.
How do I create a real closed surface now?
Following your conversation with #BoilermakerRV, I guess you are looking for one of the following two results:
A list of 3d points, where x and y are index of pixels in the image, and z is value of corresponding pixels. The result will be an m*n by 3 matrix.
An m by n by 256 volume of zeros and ones, that for (i,j)-th pixel in the image, all voxels of the (i, j)-the pile of the volume are 0, except the one at I(i, j).
Take a look at the following example that generates both results:
close all; clc; clear variables;
I = rgb2gray(imread('data2.png'));
imshow(I), title('Data as image')
% generating mesh grid
[m, n] = size(I);
[X, Y] = meshgrid(1:n, 1:m);
% converting image to list of 3-d points
P = [Y(:), X(:), I(:)];
figure
scatter3(P(:, 1), P(:, 2), P(:, 3), 3, P(:, 3), '.')
colormap jet
title('Same data as a list of points in R^3')
% converting image to 256 layers of voxels
ind = sub2ind([m n 256], Y(:), X(:), I(:));
V = zeros(m, n, 256);
V(ind) = 1.0;
figure
h = slice(V, [250], [250], [71]) ;
[h.EdgeColor] = deal('none');
colormap winter
camlight
title('And finally, as a matrix of 0/1 voxels')
The contour plot that is shown can't be generated with "2D" data. It requires three inputs as follows:
[XGrid,YGrid] = meshgrid(-4:.1:4,-4:.1:4);
C = peaks(XGrid,YGrid);
contourf(XGrid,YGrid,C,'LevelStep',0.1,'LineStyle','none')
colormap('gray')
axis equal
Where XGrid, YGrid and C are all NxN matrices defining the X values, Y values and Z values for every point, respectively.
If you want this to be "3D", simply use surf:
surf(XGrid,YGrid,C)

Plotting a cell array

I need to plot a cell array with the following format in Matlab:
{[vector1], [vector2], ...}
Into a 2D graph with the index of the vector as the y and the vector as the x
([vector1], 1), ([vector2], 2), ...
Here's a simple option:
% some arbitrary data:
CellData = {rand(10,1)*50,rand(10,1)*50,rand(10,1)*50};
% Define x and y:
x = cell2mat(CellData);
y = ones(size(x,1),1)*(1:size(x,2));
% plot:
plot(x,y,'o')
ylim([0 size(x,2)+1])
so you plot each vector of x on a separate y value:
It will work as long as your cell array is just a list of vectors.
EDIT: For non equal vectors
You'll have to use a for loop with hold:
% some arbitrary data:
CellData = {rand(5,1)*50,rand(6,1)*50,rand(7,1)*50,rand(8,1)*50,rand(9,1)*50};
figure;
hold on
for ii = 1:length(CellData)
x = CellData{ii};
y = ones(size(x,1),1)*ii;
plot(x,y,'o')
end
ylim([0 ii+1])
hold off
Hope this answers your question ;)
Here's my (brute force) interpretation of your request. There are likely more elegant solutions.
This code generates a dot plot that puts the values from the vectors at each index on the y axis—bottom to top. It can accommodate vectors of different lengths. You could make it a dot plot of vector distributions, but you might need to add some jitter to the x value, if multiple occurrences of identical or nearly identical values are possible.
% random data--three vectors from range 1:10 of different lengths
for i = 1:3
dataVals{i} = randi(10,randi(10,1),1);
end
dotSize = 14;
% plot the first vector with dots and increase the dot size
% I happen to like filled circles for this, and this is how I do it.
h = plot(dataVals{1}, ones(length(dataVals{1}), 1),'.r');
set(h,'markers', dotSize);
ax = gca;
axis([0 11 0 4]); % set axis limits
% set the Y axis labels to whole numbers
ax.YTickLabel = {'','','1','','2','','3','','',}';
hold on;
% plot the rest of the vectors
for i=2:length(dataVals)
h = plot(dataVals{i}, ones(length(dataVals{i}),1)*i,'.r');
set(h, 'markers', dotSize);
end
hold off
Without any data this is the best I can come up with for what you want:
yourCell = {[0,0,0],[1,1,1],[2,2,2]}; % 1x3 cell
figure;
plot(cell2mat(yourCell));
ylabel('Vector Values');
xlabel('Index of Vector');
It makes a plot like this:
Hope this helps.

Bar3 plot with seperate x,y,height and width values

Solution posted below function to plot bar 3 with separate x, y values and separate width and height values
bar3(x,y,z,xWidth,yWidth)
We are currently working on a project that allow one to visualize the area under a 3d function, f(x,y). The purpose of this is to demonstrate how the bars cut a 3d surface. Indirectly to visualize the desired integral.
We wish to have the bars match up with the intervals of the surface grid.
Below is a rough demonstration of the idea.
bar3 only has input for the x-values bar3(x,z), where as surf has a input for both the x and y surf(x,y,z)
Unfortunately this is what we are getting. - this is because bar3 cant be in terms of x and y
CODE:
clc;
cla;
d=eval(get(handles.edtOuterUpperB,'string'));
c=eval(get(handles.edtOuterLowerB,'string'));
b=eval(get(handles.edtInnerUpperB,'string'));
a=eval(get(handles.edtInnerLowerB,'string'));
n=eval(get(handles.edtInnerInterval,'string'));
m=eval(get(handles.edtOuterInterval,'string'));
h=(b-a)/n;
k=(d-c)/m;
[x,y] = meshgrid(a:h:b, c:k:d);
f=eval(get(handles.edtFunc,'string'));
surf(x,y,f);
hold on
bar3(f,1);
If you look closely, you will see that the XData and YData are different from the mesh to the 3D bar plot. This is because your mesh uses "real" x and y values while the bar plot uses indexes for the x and y values.
To fix this, you will want to change one or the other. For your case, the easiest one to change is going to be the surface. You can actually just omit the x and y inputs and the indexed x and y values will be used instead by default when generating the surface.
surf(f);
From the documentation for surf:
surf(Z) creates a three-dimensional shaded surface from the z components in matrix Z, using x = 1:n and y = 1:m, where [m,n] = size(Z). The height, Z, is a single-valued function defined over a geometrically rectangular grid. Z specifies the color data, as well as surface height, so color is proportional to surface height.
Update
If you want to keep the non-indexed values on the x and y axes, you will want to convert the bar3 plot instead. Unfortunately, MATLAB provides a way to specify the x axis bot not the y axis. You can take one of two approaches.
Change the XData
You can get the XData property of the resulting bar objects and change them to the data you want.
x = a:h:b;
y = c:k:d;
%// Anonymous function to scale things for us
scaler = #(vals)x(1) + ((vals-1) * (x(end) - x(1)) / (numel(x) - 1));
%// Create the bar plot
bars = bar3(y, f);
%// Change the XData
xdata = get(bars, 'XData');
xdata = cellfun(scaler, xdata, 'uni', 0);
set(bars, {'XData'}, xdata);
set(gca, 'xtick', x)
%// Now plot the surface
surf(x,y,f);
And just to demonstrate what this does:
x = linspace(0.5, 1.5, 5);
y = linspace(2.5, 4.5, 4);
f = rand(4,5);
scaler = #(vals)x(1) + ((vals-1) * (x(end) - x(1)) / (numel(x) - 1));
bars = bar3(y, f);
set(bars, {'XData'}, cellfun(scaler, get(bars, 'XData'), 'uni', 0))
set(gca, 'xtick', x)
axis tight
Change the XTickLabels
Instead of changing the actual data, you could simply change the values that are displayed to be what you want them to be rather than the indexed values.
x = a:h:b;
y = c:k:d;
labels = arrayfun(#(x)sprintf('%.2f', x), x, 'uni', 0);
bar3(y, f);
set(gca, 'xtick', 1:numel(x), 'xticklabels', labels);
hold on
%// Make sure to use the INDEX values for the x variable
surf(1:numel(x), y, f);
We found a user contributed function scatterbar3, which does what we want, in a different way than what bar3 uses:
http://www.mathworks.com/matlabcentral/fileexchange/1420-scatterbar3
There was however a slight hiccup that we had to correct:
hold on
scatterbar3(x,y,f,h);
scatterbar3 does not have separate inputs for the width and height of the bars, thus large gaps occur when the intervals do not equal one another. Demonstrated below.
We thus edited the scatterbar3 function in order to take both the width and height of the bars as inputs:
Edited scatterbar3 function:
function scatterbar3(X,Y,Z,widthx,widthy)
[r,c]=size(Z);
for j=1:r,
for k=1:c,
if ~isnan(Z(j,k))
drawbar(X(j,k),Y(j,k),Z(j,k),widthx/2,widthy/2)
end
end
end
zlim=[min(Z(:)) max(Z(:))];
if zlim(1)>0,zlim(1)=0;end
if zlim(2)<0,zlim(2)=0;end
axis([min(X(:))-widthx max(X(:))+widthx min(Y(:))-widthy max(Y(:))+widthy zlim])
caxis([min(Z(:)) max(Z(:))])
function drawbar(x,y,z,widthx,widthy)
h(1)=patch([-widthx -widthx widthx widthx]+x,[-widthy widthy widthy -widthy]+y,[0 0 0 0],'b');
h(2)=patch(widthx.*[-1 -1 1 1]+x,widthy.*[-1 -1 -1 -1]+y,z.*[0 1 1 0],'b');
h(3)=patch(widthx.*[-1 -1 -1 -1]+x,widthy.*[-1 -1 1 1]+y,z.*[0 1 1 0],'b');
h(4)=patch([-widthx -widthx widthx widthx]+x,[-widthy widthy widthy -widthy]+y,[z z z z],'b');
h(5)=patch(widthx.*[-1 -1 1 1]+x,widthy.*[1 1 1 1]+y,z.*[0 1 1 0],'b');
h(6)=patch(widthx.*[1 1 1 1]+x,widthy.*[-1 -1 1 1]+y,z.*[0 1 1 0],'b');
set(h,'facecolor','flat','FaceVertexCData',z)
Finally the working solution in action:
hold on
scatterbar3(x,y,f,h,k);

Non-uniform axis of imagesc() in Matlab

Question: is it possible to illustrate an image on non-uniform axis?
Details:
I need to illustrate a multidimensional timeseries as an image. But the time grid of this timeseries is very non-uniform. Here is an example:
m = 10;
n = 3;
t = sort(rand(m, 1)); % non-uniform time
values = randn(m, n); % some random values
The figure, plot(t, values); handles it well.
But imagesc() converts t into uniform time between t(1) and t(end) according to documentation:
imagesc(x,y,C) displays C as an image and specifies the bounds of the
x- and y-axis with vectors x and y.
Therefore, the command:
figure, imagesc(t, 1 : n, values'); colorbar;
illustrates the image on uniform time grid.
Edit: It's possible to re-sample the timeseries with higher uniform resolution. But my timeseries is already very large.
There is pcolor function in MATLAB. This function does exactly what you're asking.
m = 10;
n = 3;
t = sort(rand(m, 1)); % non-uniform time
values = randn(m, n); % some random values
figure
plot(t, values);
figure
pcolor(t, 1 : n, values');
colorbar;
try uimagesc from the file exchange.
Solution
Try using surface for non-uniform spacing.
First, create a 3D xyz surface of the same size as your input data:
m = 10;
n = 3;
t = sort(rand(m, 1)); % non-uniform time
values = randn(m, n); % some random values
x = repmat(t,1,n);
y = repmat(1:n,m,1);
z = zeros(size(y));
Then, colormap your values. There is a nice tool posted to the mathworks file exchange, real2rgb, that can do this for you:
cdata = real2rgb(values); % Where size(cdata) = [m n 3]
Lastly, plot the surface. You can even get fancy and set the transparency.
surface(x,y,z,cdata,'EdgeColor','none','FaceColor','texturemap',...
'CDataMapping','direct');
alpha(0.3)