How to plot 3d directed graph in matlab - matlab

I have an upper triangular adjacent matrix which represents a set of nodes which are connected. Every node is defined by three geographical coordinates: x y z.
My goal is to plot the network in order to see what it looks like by taking into account also the direction of the edges.
If I do not take into account the z coordinate, I am able to display the result easily:
The lines of code to get this result are:
A = [0 1 1 0 0 0 0;
0 0 1 1 0 0 0;
0 0 0 1 1 1 0;
0 0 0 0 1 1 0;
0 0 0 0 0 0 1;
0 0 0 0 0 0 1;
0 0 0 0 0 0 0];
xyz = [ 0 0 0;
-15 20 5;
17 24 -3;
-5 36 7;
-14 50 -8;
16 56 3;
3 70 -1];
F = digraph(A);
figure
p = plot(F,'XData',xyz(:,2),'YData',xyz(:,1)); axis equal;
highlight(p,1,'NodeColor','g'); highlight(p,size(A,1),'NodeColor','r');
view([0 90])
How should I modify my code in order to assign to the graph also the z coordinates so I can have a 3d graph? (remember I want to display the edge direction too!!).
What I tried to do is this:
p = plot3(F,'XData',xyz(:,2),'YData',xyz(:,1),'ZData',xyz(:,3));
but I had no success.

Cool problem. I had some spare time and produced this:
close all
clear all
A = [0 1 1 0 0 0 0;
0 0 1 1 0 0 0;
0 0 0 1 1 1 0;
0 0 0 0 1 1 0;
0 0 0 0 0 0 1;
0 0 0 0 0 0 1;
0 0 0 0 0 0 0];
xyz = [ 0 0 0;
-15 20 5;
17 24 -3;
-5 36 7;
-14 50 -8;
16 56 3;
3 70 -1];
figure; hold on
for jj=1:size(A,1) %cycle on nodes
conn=find(A(jj,:)); %find connections for each node
if numel(conn>0) %if there are non null connections
for kk=1:numel(conn) %plot them
a=conn(kk);
lh=quiver3(xyz(jj,1),xyz(jj,2),xyz(jj,3),...
xyz(a,1)-xyz(jj,1),xyz(a,2)-xyz(jj,2),xyz(a,3)-xyz(jj,3),0,'maxheadsize',0.5);
set(lh,'linewidth',4);
set(lh,'color',[1,0,0]);
end
end
end
scatter3(xyz(:,1),xyz(:,2),xyz(:,3),800,'b','.') %plot nodes
%number the nodes
for ii=1:size(xyz,1)
text(xyz(ii,1),xyz(ii,2),xyz(ii,3),num2str(ii),'Color','k','FontWeight','bold',...
'FontSize',14, 'HorizontalAlignment','right', 'VerticalAlignment','bottom')
end
xlabel('x')
ylabel('y')
zlabel('z')
view(-15,18)
grid on
That I think looks pretty much like what you want:
EDIT
If you want the arrow head to be at the midpoint of the two nodes you can use:
line([xyz(a,1) xyz(jj,1)],[xyz(a,2) xyz(jj,2)],[xyz(a,3) xyz(jj,3)],'color',[1 0 0],'linewidth',3)
lh=quiver3(xyz(jj,1),xyz(jj,2),xyz(jj,3),...
xyz(a,1)-xyz(jj,1),xyz(a,2)-xyz(jj,2),xyz(a,3)-xyz(jj,3),.5,'maxheadsize',0.5);
This draws a line first and the superimpose an arrow that reaches the midpoint (note the 0.5scaling factor in the quivercommand):

In the newest MATLAB Release (R2016b), it's now possible to plot a node-link graph in 3d by choosing a different layout method, or specifying x, y and z coordinates directly. In your example, replace the plotting line by
p = plot(F,'XData',xyz(:,2),'YData',xyz(:,1),'ZData',xyz(:,3));
Resulting plot:

Related

How to fix the plot of the symbolic eigenvalues of the 1st matrix (matlab)?

I'm calculating the eigenvalues of a 8x8-matrix including a symbolic variable "W". Plotting the 8 eigenvalues as functions of W returns a strange result in the plot which looks like someone rode his bike over my diagram.
For the 2nd matrix, where I just set some off-diagonal elements equal to 0, everything works fine. But I don't know what the problem with the 1st one is.
syms W;
w0=1/780;
wl=1/1064;
h=1; % for now this seems unnecessary, but I want to change this value later on
% This is the 1st matrix which causes some strange plotting results
A=h*[w0+3*wl 2*W 0 0 0 sqrt(3)*W 0 0;
2*W 4*wl 0 0 0 0 0 0;
0 0 2*wl+w0 sqrt(3)*W 0 0 0 sqrt(2)*W;
0 0 sqrt(3)*W 3*wl 0 0 0 0;
0 0 0 0 wl+w0 sqrt(2)*W 0 0;
sqrt(3)*W 0 0 0 sqrt(2)*W 2*wl 0 0;
0 0 0 0 0 0 w0 W;
0 0 sqrt(2)*W 0 0 0 W wl];
% This is the 2nd matrix for which everything is working fine
B=h*[w0+3*wl 2*W 0 0 0 0 0 0;
2*W 4*wl 0 0 0 0 0 0;
0 0 2*wl+w0 sqrt(3)*W 0 0 0 0;
0 0 sqrt(3)*W 3*wl 0 0 0 0;
0 0 0 0 wl+w0 sqrt(2)*W 0 0;
0 0 0 0 sqrt(2)*W 2*wl 0 0;
0 0 0 0 0 0 w0 W;
0 0 0 0 0 0 W wl];
X = eig(A);
X2 = eig(B);
eva22 = X2(1);
eva1 = X(1);
figure(1);
fplot(X2,[-0.002 0.002]);
hold on;
fplot(X,[-0.002 0.002]);
hold off;
xlabel('Rabi frequency [THz]','FontSize',11);
ylabel('dressed states','FontSize',11);
grid on;
box on;
I'm expecting the plot for matrix A to just be similar to the plot of matrix B, but somehow it doesn't work properly. I'd appreciate some tips and tricks how to fix this.
The second plot looks like that because the eigenvalues of B are imaginary. When using plot(), it plots the real part of complex numbers by default, but apparently fplot() doesn't. You can do fplot(real(X), [-0.002 0.002]) instead to plot just the real part of the eigenvalues (assuming that's what you want).

How to sum the 8-neighbor pixel values of the current pixel.

I have a binary image. I want to find the pixel value = 1 and label it as the current pixel. Then, I want to sum its 8-neighbor pixel values. If the summation of the 8-neighbor pixel values of the current pixel = 1, then mark that current pixel with marker. Some part of a binary image as follows:
0 0 0 0 0
0 1 0 0 0
0 0 1 1 0
0 0 0 0 1
0 0 0 0 0
I tried the following matlab code but it has some errors (at this line -> Sums = sum(currentPix, nOffsets);). How can I fix it?
Sums = 0;
S = size(BW,1);
nOffsets = [S, S+1, 1, -S+1, -S, -S-1, -1, S-1]'; %8-neighbors offsets
BW_Out = BW;
for row=1:S
for col=1:S
if BW(row,col),
break;
end
end
idx = sub2ind(size(BW),row,col);
neighbors = bsxfun(#plus, idx, nOffsets);
currentPix = find(BW==1); %if found 1, define it as current pixel
while ~isempty(currentPix)
% new current pixel list is set of neighbors of current list.
currentPix = bsxfun(#plus, currentPix, nOffsets);
currentPix = currentPix(:);
Sums = sum(currentPix, nOffsets); %error at this line
if (Sums==1) %if the sum of 8-neighbor values = 1, mark ROI
plot(currentPix,'r*','LineWidth',1);
end
% Remove from the current pixel list pixels that are already
currentPix(BW_Out(currentPix)) = [];
% Remove duplicates from the list.
currentPix = unique(currentPix);
end
end
I think you can actually do this in one line (after defining a kernel that is)
I = [0 0 0 0 0
0 1 0 0 0
0 0 1 1 0
0 0 0 0 1
0 0 0 0 0];
K = [1 1 1;
1 0 1;
1 1 1;];
(conv2(I,K,'same')==1) & I
ans =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 0 1
0 0 0 0 0
Breaking this up:
M = conv2(I,K, 'same'); %// convolving with this specific kernel sums up the 8 neighbours excluding the central element (i.e. the 0 in the middle)
(M==1) & I %// Only take results where there was a 1 in the original image.

how to make sure that all Y axes on subplots have the same value

Here is the problem I am facing. I have the code, which builds some bar plots.
In order to compare them better, I need all them have the same scale. Looking at doc bar, I was not able to find how to specify that a bar plot has a specific maximum height.
So in my case, for example I have the following code:
c = [0 0 12 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
e = [0 2 5 6 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0];
f = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19];
b = [0 9 7 0 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0];
subplot(2,2,1)
bar(b)
subplot(2,2,2)
bar(e)
subplot(2,2,3)
bar(f)
subplot(2,2,4)
bar(c)
The first subplot has height of 10, than 6, than 20 than 15.
Is there an easy way to have all of them their maximum height as 20.
You can use the linkaxes command:
h(1) = subplot(2,2,1)
bar(b)
h(2) = subplot(2,2,2)
bar(e)
h(3) = subplot(2,2,3)
bar(f)
h(4) = subplot(2,2,4)
bar(c)
linkaxes(h)
ylim([0 20])
You can easily change axes properties using the set command and the handles (=identifiers) of the axes. If you haven't stored the axes handles (first output of subplot), you first have to find them:
%# collect axes handles
axH = findall(gcf,'type','axes');
%# set the y-limits of all axes (see axes properties for
%# more customization possibilities)
set(axH,'ylim',[0 20])

bicubic interpolation of 3D surface

I am writing an algorithm in matlab to for bicubic interpolation of a surface Psi(x,y). I have a bug in the code and cannot seem to track it down. I am trying a test case with Psi=X^2-0.25 so that its easier to track down the bug. It seems as if my interpolation has an offset. My comments are included in my code. Any help would be appreciated.
Plot of Psi=X^2 in blue and interpolation in red
Countour lines of Psi are plotted and the red dot is the point I am computing the interpolation about. The thick red line is the interpolation which is offset quite a bit from the red dot.
function main()
epsilon=0.000001;
xMin=-1+epsilon;
xMax= 1+epsilon;
yMin=-1+epsilon;
yMax= 1+epsilon;
dx=0.1; Nx=ceil((xMax-xMin)/dx)+1;
dy=0.1; Ny=ceil((yMax-yMin)/dy)+1;
x=xMin:dx:xMax; x=x(1:Nx);
y=yMin:dy:yMax; y=y(1:Ny);
[XPolInX,XPolInY]=GetGhostMatricies(Nx,Ny); %Linear extrapolation matrix
[D0x,D0y]=GetDiffMatricies(Nx,Ny,dx,dy); %derivative matricies: D0x is central differencing in x
[X,Y]=meshgrid(x,y);
Psi=X.^2-0.25; %Note that my algorithm is being written for a Psi that may not have a analytic representation. This Psi is only a test case.
psi=zeros(Nx+2,Ny+2); %linearly extrapolate psi (for solving differential equation not shown here)
psi(2:(Nx+1),2:(Ny+1))=Psi';
psi=(XPolInY*(XPolInX*psi)')';
%compute derivatives of psi
psi_x =D0x*psi; psi_x =(XPolInY*(XPolInX*psi_x)')';
psi_y =(D0y*psi')'; psi_y =(XPolInY*(XPolInX*psi_y)')';
psi_xy=D0x*psi_y; psi_xy=(XPolInY*(XPolInX*psi_xy)')';
% i have verified that my derivatives are computed correctly
biCubInv=GetBiCubicInverse(dx,dy);
i=5; %lets compute the bicubic interpolation at this x(i), y(j)
j=1;
psiVoxel=[psi( i,j),psi( i+1,j),psi( i,j+1),psi( i+1,j+1),...
psi_x( i,j),psi_x( i+1,j),psi_x( i,j+1),psi_x( i+1,j+1),...
psi_y( i,j),psi_y( i+1,j),psi_y( i,j+1),psi_y( i+1,j+1),...
psi_xy(i,j),psi_xy(i+1,j),psi_xy(i,j+1),psi_xy(i+1,j+1)]';
a=biCubInv*psiVoxel; %a=[a00 a01 ... a33]; polynomial coefficients; 1st index is power of (x-xi), 2nd index is power of (y-yj)
xi=x(5); yj=y(1);
clear x y
x=(xi-.2):.01:(xi+.2); %this is a local region about the point we are interpolating
y=(yj-.2):.01:(yj+.2);
[dX,dY]=meshgrid(x,y);
Psi=dX.^2-0.25;
figure(2) %just plotting the 0 level contour of Psi here
plot(xi,yj,'.r','MarkerSize',20)
hold on
contour(x,y,Psi,[0 0],'r','LineWidth',2)
set(gca,'FontSize',14)
axis([x(1) x(end) y(1) y(end)])
grid on
set(gca,'xtick',(xi-.2):.1:(xi+.2));
set(gca,'ytick',(yj-.2):.1:(yj+.2));
xlabel('x')
ylabel('y')
[dX dY]=meshgrid(x-xi,y-yj);
%P is my interpolating polynomial
P = a(1) + a(5) *dY + a(9) *dY.^2 + a(13) *dY.^3 ...
+ a(2)*dX + a(6)*dX .*dY + a(10)*dX .*dY.^2 + a(14)*dX .*dY.^3 ...
+ a(3)*dX.^2 + a(7)*dX.^2.*dY + a(11)*dX.^2.*dY.^2 + a(15)*dX.^2.*dY.^3 ...
+ a(4)*dX.^3 + a(8)*dX.^3.*dY + a(12)*dX.^3.*dY.^2 + a(16)*dX.^3.*dY.^3 ;
[c h]=contour(x,y,P)
clabel(c,h)
figure(3)
plot(x,x.^2-.25) %this is the exact function
hold on
plot(x,P(1,:),'-r*')
%See there is some offset here
end
%-------------------------------------------------------------------------
function [XPolInX,XPolInY]=GetGhostMatricies(Nx,Ny)
XPolInX=diag(ones(1,Nx+2),0);
XPolInY=diag(ones(1,Ny+2),0);
XPolInX(1,1) =0; XPolInX(1,2) =2; XPolInX(1,3) =-1;
XPolInY(1,1) =0; XPolInY(1,2) =2; XPolInY(1,3) =-1;
XPolInX(Nx+2,Nx+2)=0; XPolInX(Nx+2,Nx+1)=2; XPolInX(Nx+2,Nx)=-1;
XPolInY(Ny+2,Ny+2)=0; XPolInY(Ny+2,Ny+1)=2; XPolInY(Ny+2,Ny)=-1;
fprintf('Done GetGhostMatricies\n')
end
%-------------------------------------------------------------------------
function [D0x,D0y]=GetDiffMatricies(Nx,Ny,dx,dy)
D0x=diag(ones(1,Nx-1),1)-diag(ones(1,Nx-1),-1);
D0y=diag(ones(1,Ny-1),1)-diag(ones(1,Ny-1),-1);
D0x(1,1)=-3; D0x(1,2)=4; D0x(1,3)=-1;
D0y(1,1)=-3; D0y(1,2)=4; D0y(1,3)=-1;
D0x(Nx,Nx)=3; D0x(Nx,Nx-1)=-4; D0x(Nx,Nx-2)=1;
D0y(Ny,Ny)=3; D0y(Ny,Ny-1)=-4; D0y(Ny,Ny-2)=1;
%pad with ghost cells which are simply zeros
tmp=D0x; D0x=zeros(Nx+2,Nx+2); D0x(2:(Nx+1),2:(Nx+1))=tmp; tmp=0;
tmp=D0y; D0y=zeros(Ny+2,Ny+2); D0y(2:(Ny+1),2:(Ny+1))=tmp; tmp=0;
%scale appropriatley by dx & dy
D0x=D0x/(2*dx);
D0y=D0y/(2*dy);
end
%-------------------------------------------------------------------------
function biCubInv=GetBiCubicInverse(dx,dy)
%p(x,y)=a00+a01(x-xi)+a02(x-xi)^2+...+a33(x-xi)^3(y-yj)^3
%biCubic*a=[psi(i,j) psi(i+1,j) psi(i,j+1) psi(i+1,j+1) psi_x(i,j) ... psi_y(i,j) ... psi_xy(i,j) ... psi_xy(i+1,j+1)]
%here, psi_x is the x derivative of psi
%I verified that this matrix is correct by setting dx=dy=1 and comparing to the inverse here http://en.wikipedia.org/wiki/Bicubic_interpolation
biCubic=[
%00 10 20 30 01 11 21 31 02 12 22 32 03 13 23 33
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
1 dx dx^2 dx^3 0 0 0 0 0 0 0 0 0 0 0 0;
1 0 0 0 dy 0 0 0 dy^2 0 0 0 dy^3 0 0 0;
1 dx dx^2 dx^3 dy dx*dy dx^2*dy dx^3*dy dy^2 dx*dy^2 dx^2*dy^2 dx^3*dy^2 dy^3 dx*dy^3 dx^2*dy^3 dx^3*dy^3;
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 1 2*dx 3*dx^2 0 0 0 0 0 0 0 0 0 0 0 0;
0 1 0 0 0 dy 0 0 0 dy^2 0 0 0 dy^3 0 0;
0 1 2*dx 3*dx^2 0 dy 2*dx*dy 3*dx^2*dy 0 dy^2 2*dx*dy^2 3*dx^2*dy^2 0 dy^3 2*dx*dy^3 3*dx^2*dy^3;
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 1 dx dx^2 dx^3 0 0 0 0 0 0 0 0;
0 0 0 0 1 0 0 0 2*dy 0 0 0 3*dy^2 0 0 0;
0 0 0 0 1 dx dx^2 dx^3 2*dy 2*dx*dy 2*dx^2*dy 2*dx^3*dy 3*dy^2 3*dx*dy^2 3*dx^2*dy^2 3*dx^3*dy^2;
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 1 2*dx 3*dx^2 0 0 0 0 0 0 0 0;
0 0 0 0 0 1 0 0 0 2*dy 0 0 0 3*dy^2 0 0;
0 0 0 0 0 1 2*dx 3*dx^2 0 2*dy 4*dx*dy 6*dx^2*dy 0 3*dy^2 6*dx*dy^2 9*dx^2*dy^2];
biCubInv=inv(biCubic);
end
%-------------------------------------------------------------------------
I found my error. I pad my matricies with ghost cells, however I forget that now the i in Psi without ghost cells is i+1 in psi with ghost cells. Hence, I should be evaluating my interpolating polynomial P at xi=x(6); yj=y(2), not xi=x(5); yj=y(1).

From 4-connectivity to 8-connectivity in MATLAB

Say I have an boundary image in a logical matrix where true means boundary and false means region interior. The image encodes a tessellation of a 2D domain.
I was wondering if there is a compact way in MATLAB to "fix" those pixel neighborhoods where the separation between adjacent regions is only 4-connected and transform them into 8-connected in a manner that preserves the topology of the tessellation.
I believe this can be done with LUTs, but I'm not sure how to proceed. Do I have to, and if so, how do I exactly evaluate all the 3x3 pixel regions where the connectivity is only 4-wise to fill-in the corresponding pixels?
My proposed solution: use BWHITMISS to find the pixels whose neighborhood is at least 4-connected, dilate the result with a rectangular-shaped structuring element to convert those neighborhoods to 8-connected, finally we combine with the original image using logical-OR.
Example:
bw = [
0 0 0 1 0 1 0
0 0 1 1 1 1 1
0 1 1 1 0 1 0
0 0 1 0 1 0 0
0 1 1 0 0 0 0
0 0 1 0 1 1 1
0 0 1 0 0 1 0
];
hm = bwhitmiss(bw, [0 1 0; 1 1 1; 0 1 0]); %# [-1 1 -1; 1 1 1; -1 1 -1]
bw2 = imdilate(hm,ones(3)) | bw;
We can visualize the result:
[r c] = find(hm);
subplot(121), imshow(bw), hold on, plot(c(:),r(:),'o')
subplot(122), imshow(bw2)