Quiver from a single matrix - matlab

I have a matrix (In Matlab) which I need to plot with a quiver plot but I don't know how to turn it into a "quiver plot-able form". Are there any commands to change it? I saw some example on MathWorks Homepage using the peaks function but I couldn't get it to work.
The matrix I have is pretty huge with lots of NaN's so I created an smaller version of it.
Temperature = [ 1 2 2 2 3 4 6 7 ;
1 2 3 4 4 5 6 7 ;
2 3 4 NaN NaN 6 8 9 ;
3 4 5 NaN NaN 7 8 9 ;
4 4 6 6 7 8 10 11;
4 5 7 7 8 9 11 12];
contour(Temperature)
%quiver(Temperature)

In the comments you find the example code from the documentation which I used. Besides knowing that the dimensions are ordered [Y,X,Z] to get a matching meshgrid it's mostly copy&paste
% figure
figure
% [X,Y] = meshgrid(-2:.2:2);
Temperature = [ 1 2 2 2 3 4 6 7 ;
1 2 3 4 4 5 6 7 ;
2 3 4 NaN NaN 6 8 9 ;
3 4 5 NaN NaN 7 8 9 ;
4 4 6 6 7 8 10 11;
4 5 7 7 8 9 11 12];
[X,Y] = meshgrid(1:size(Temperature,2),1:size(Temperature,1));
% Z = X.*exp(-X.^2 - Y.^2);
Z=Temperature;
% [DX,DY] = gradient(Z,.2,.2);
[DX,DY] = gradient(Z,1,1);
% contour(X,Y,Z)
contour(X,Y,Z)
% hold on
hold on
% quiver(X,Y,DX,DY)
quiverscaling=3;
quiver(X,Y,DX,DY,quiverscaling)
% colormap hsv
colormap hsv
% hold off
hold off

Related

Reshape MATLAB matrix with repeated indicies

I apologize if this is a repeated question.
Suppose I have a matrix A
0 1 2 3 4 5 6 7
8 9 1 2 3 4 5 6
and a vector b [1,2,3,4,1,2,3,4]. Thus, matrix A contains multiple ordered measurements based on vector b.
How can I reshape the matrix to have dimension [2 2 4], such that A(:,:,1) = [0,4;8,3]?
I understand I need to reshape. I tried using permute, however it does not handle repeated indices.
Thanks!
You are close, you just need to sort the columns before reshaping them
A=[0 1 2 3 4 5 6 7; 8 9 1 2 3 4 5 6]
%A =
% 0 1 2 3 4 5 6 7
% 8 9 1 2 3 4 5 6
b=[1,2,3,4,1,2,3,4]
%b =
% 1 2 3 4 1 2 3 4
[~,idx]=sort(b)
%idx =
% 1 5 2 6 3 7 4 8
A=A(:,idx)
%A =
% 0 4 1 5 2 6 3 7
% 8 3 9 4 1 5 2 6
A=reshape(A,[2,2,4])
%A(:,:,1) =
% 0 4
% 8 3
%A(:,:,2) =
% 1 5
% 9 4
%A(:,:,3) =
% 2 6
% 1 5
%A(:,:,4) =
% 3 7
% 2 6
Be careful, this will only work if you can assure that each number in b is repeated same number of times.
Assuming your b is always some repeated 1:n pattern like it is in your question, you can use:
p=4 % number of indices
permute(reshape(A,size(A,1),p,[]),[1,3,2])

Extend the borders of a matrix and replicate the border elements in MATLAB

I am given the following matrix B:
B =
1 4 7
2 5 8
3 6 9
I would like to pad this matrix so that there is a 1 element border that surrounds it with the border elements replicated. Essentially, I would like this result:
B =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9
How can I do this in MATLAB?
If you have the Image Processing Toolbox, use padarray, specifically the replicate flag. If you don't have it, there's an implementation that someone made here on Github: https://github.com/gpeyre/matlab-toolboxes/blob/master/toolbox_nlmeans/toolbox/ordfilt2/padarray.m . You can download it and use the function for your own use.
padarray creates a larger matrix with the source matrix centred within this larger matrix. You have several options on what you can do with the extra border elements. The default behaviour is to set these equal to 0. However, we can specify the replicate flag, which copies values along the original border of the matrix and places them along the extra border elements with this new matrix. Because you want to go from 3 x 3 to 5 x 5, you just need a 1 element border along both dimensions. You specify this with the second parameter to padarray. The replicate flag is the third parameter:
>> B = reshape(1:9, 3, 3);
>> B2 = padarray(B, [1 1], 'replicate')
B2 =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9
Edit
If you don't want to use padarray, you can use the scatteredInterpolant class instead, with nearest as the interpolation flag. You would build a 3 x 3 2D spatial grid of coordinates that map to each value in B, then we'd specify a 5 x 5 spatial grid of coordinates where the border elements are outside of the range of the original 3 x 3 grid. Something like this:
>> [X,Y] = meshgrid(1:3,1:3);
>> [X2,Y2] = meshgrid(0:4,0:4);
>> F = scatteredInterpolant(X(:),Y(:),B(:),'nearest');
>> B2 = F(X2, Y2)
B2 =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9
The question was explicitly to add a single element as border, so try this (no toolbox needed):
B = [1 4 7; 2 5 8; 3 6 9] % or use B=rand(3,4), etc. to try something else.
B2 = B([1 1:end end],[1 1:end end])
This is the result (as desired):
B =
1 4 7
2 5 8
3 6 9
B2 =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9

plot two histograms (using the same y-axis) and a line plot (using a different y-axis) on the same figure

How can I plot two histograms (using the same y-axis) and a line plot (using a different y-axis) on the same figure? I am using Matlab 2014b. I am aware of this but it seems to only work for bar plots?
This is my histogram code:
A = [1 2 2 2 3 4 5 5 5 5 5 5 5 5 5 6 6 6 7 7];
B = [6 6 6 7 7 7 7 7 7 7 8 8 8 9 9 10 10];
hist(A,7);
hold on
hist(B,7);
h = findobj(gca,'Type','patch');
set(h(1),'FaceColor','b','EdgeColor','b','facealpha',0.2)
set(h(2),'FaceColor','r','EdgeColor','r','facealpha',0.2)
xlabel('Day','fontsize',14)
ylabel('Frequency','fontsize',14)
xlim([1 10])
Now say I have these data:
Day = [1 2 3 4 5 6 7 8 9 10];
Prevalence = [3 2 4 8 5 6 7 8 9 5];
I want to plot these data (plot(Day,Prevalence)) using the right y-axis.
Thanks.
I think this workaround will do what you want.
Basically create a new axes at the same position than the one in which the histograms are plot, however set its color property to 'none' and the YAxisLocation to the right. You can then assign the new axes the properties you want.
Code:
clear
clc
%// ====================
%// Your code
A = [1 2 2 2 3 4 5 5 5 5 5 5 5 5 5 6 6 6 7 7];
B = [6 6 6 7 7 7 7 7 7 7 8 8 8 9 9 10 10];
hist(A,7);
hold on
hist(B,7);
h = findobj(gca,'Type','patch');
set(h(1),'FaceColor','b','EdgeColor','b','facealpha',0.2)
set(h(2),'FaceColor','r','EdgeColor','r','facealpha',0.2)
xlabel('Day','fontsize',14)
ylabel('Frequency','fontsize',14)
xlim([1 10])
%// ====================
Day = [1 2 3 4 5 6 7 8 9 10];
Prevalence = [3 2 4 8 5 6 7 8 9 5];
%// Get the current axes position to place the new one.
AxesPos = get(gca,'Position');
hold on
hax2 = axes('Position',AxesPos);
%// Plot the data
plot(Day,Prevalence,'--k','LineWidth',4,'Parent',hax2)
%// Set properties of the axes.
set(hax2,'Color','none','YAxisLocation','right','XTick',[],'XTickLabel','','YLim',[0 15])
ylabel('Prevalence','FontSize',16)
%// Rotate the label to correct orientation
LabelPos = get(get(hax2,'YLabel'),'Position');
set(get(hax2,'YLabel'),'Position',[LabelPos(1)+.2 LabelPos(2) LabelPos(3)],'Rotation',-90)
Output:
Note that it's far from perfect ...for example the left border of the first axes is not visible...that could be fixed by playing around with the position of the new axes. Hopefully it does the job for you!

Plot 3d surface plot in matlab/freemat

I would like to ask about 3d surface plotting. As I am new to it, I was just trying out. Basically, I have 3 parameters, x, y ,z which I have the values from experimental datas and I would like to plot them out. As such, i tried,
x= [6 7 8 9 10 11 12 1]
x =
6 7 8 9 10 11 12 1
--> y=[2 3 4 5 6 1 6 8]
y =
2 3 4 5 6 1 6 8
--> z= [3 4 5 6 7 8 9 10]
z =
3 4 5 6 7 8 9 10
meshgrid(x,y,z)
surf(x,y,z)
The plot window did come out but there was no graph. Is my method wrong?
Thanks!
It sounds like you need to start with plot3, as you're just describing a set of points in 3D, rather than points on a mesh or surface. See if that does what you want.
x = [6 7 8 9 10 11 12 1];
y = [2 3 4 5 6 1 6 8];
z = [3 4 5 6 7 8 9 10];
plot3(x, y, z, '.');
This is how I would plot a surface :
%define the data
x=[6 7 8 9 10 11 12 1 6 7 8 9 10 11 12 1];
y=[2 3 4 5 6 1 6 8 2 3 4 5 6 1 6 8];
z=[3 4 5 6 7 8 9 10 3 4 5 6 7 8 9 10];
%Create 3D surface
[X,Y]=meshgrid(x,y);
Z=griddata(x,y,z,X,Y);
%Plot the surface
surface(X,Y,Z);
shading interp %makes it look sexy
%xlim([])
%ylim([])
Sometimes I use axis limets to make the plot look nicer (eliminates the unneeded white area's); for this set of data I could use xlim([6 11]) and ylim([2 6]).

Rearranging matrix using col2im in Matlab

My matrix is this:
0 3 0
0 1 2
4 4 1
I use im2col on it like this:
im2col(A, [2 2], 'sliding')
which correctly yields this:
0 0 3 1
0 4 1 4
3 1 0 2
1 4 2 1
I call this matrix K. Now I use col2im to go back to my original matrix. From the Matlab documentation I use this:
col2im(K, [2 2], [5 5],'sliding')
But this doesn't gives me my original matrix A. Reason being [5 5] should be [4 4] to get a 3*3 matrix for starters. But when I do that I get
??? Error using ==> reshape
To RESHAPE the number of elements must not change.
Why is that? And how can I get my original matrix back?
Fromthe docs:
A = col2im(B,[m n],[mm nn],'sliding') rearranges the row vector B into
a matrix of size (mm-m+1)-by-(nn-n+1). B must be a vector of size
1-by-(mm-m+1)*(nn-n+1). B is usually the result of processing the
output of im2col(...,'sliding') using a column compression function
(such as sum).
So that says to me you should be trying something like:
col2im(sum(K), [2 2], [4 4],'sliding')
however that would require K to have 9 columns. I don't have the image processing toolbox handy to test this right now
Your col2im doesn't work because it uses reshape and for that the number of elements of the matrix you wish to reshape (K) and the new one, need to be the same. This is not the case anymore, as through your transformation of A with im2col you obviously changed that. A has 9 and K 16 elements.
So you basically need to get back to a 3*3 matrix again by getting rid of the redundand doubled elements (due to the overlapping 2*2 blocks used in im2col) in K.
For that you could just make a new matrix (C) with the elements that you need:
C = [K([1,3,11;2,4,12;6,8,16])]
As long as you first went from a 3*3 to a 4*4 matrix using the same order of blocks this should work.
Maybe you could tell us more about what you really want to achieve, because I don't see any reason for this in the first place. It may also be possible that you might be better off using other functions instead, but I can only see that if I know what the reasoning behind your question is.
clear
clc
img = double(imread('tire.tif'));
[r c] = size(img);
w = 8;
imgBlock = im2col(img,[w w],'sliding'); imgBlock = imgBlock(:);
[x y] = meshgrid(1:c,1:r);
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
img2 = accumarray([yy xx], imgBlock, [], #mean);
figure,imshow(img, []);
figure,imshow(img2,[]);
% random matrix as image
img = randi(10,4)
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% matrix size
[r c] = size(img)
% patch size
w = 2;
% image to patch
imgBlock = im2col(img,[w w],'sliding')
% image patchs matrix to a vector
imgBlock = imgBlock(:);
r =
4
c =
4
imgBlock =
6 5 1 2 8 4 2 7 3
5 1 4 8 4 6 7 3 7
2 8 4 2 7 3 7 8 5
8 4 6 7 3 7 8 5 1
% index matrix size equal image size
[x y] = meshgrid(1:c,1:r)
% index matric to patchs;to vector
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
x =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
y =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
% yy :row index xx: column index
% applies the function mean to each subset of elements in imgBlock that have identical subscripts in [yy xx].
img2 = accumarray([yy xx], imgBlock, [], #mean);
img
img2
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
img2 =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% [col,row,value]
a = [xx,yy,imgBlock]
a =
1 1 6
1 2 5
2 1 2
2 2 8
1 2 5
1 3 1
2 2 8
2 3 4
1 3 1
1 4 4
2 3 4
2 4 6
2 1 2
2 2 8
3 1 2
3 2 7
2 2 8
2 3 4
3 2 7
3 3 3
2 3 4
2 4 6
3 3 3
3 4 7
3 1 2
3 2 7
4 1 7
4 2 8
3 2 7
3 3 3
4 2 8
4 3 5
3 3 3
3 4 7
4 3 5
4 4 1
% The number of times that img(2,2) occurs in the matrix img
a(xx == 2 & yy == 2,:)
ans =
2 2 8
2 2 8
2 2 8
2 2 8