I am struggling with the concepts behind plotting a surface polar plot.
I am trying to plot the values measured by a sensor at a combination of different angles over a hemisphere.
I have an array containing the following information:
A(:,1) = azimuth values from 0 to 360º
A(:,2) = zenith values from 0 to 90º
A(:,3) = values measured at the combination of angles of A(:,1) and A(:,2)
For example, here is a snippet:
0 15 0.489502132167206
0 30 0.452957556748497
0 45 0.468147850273115
0 60 0.471115818950192
0 65 0.352532182508945
30 15 0.424997863795610
30 30 0.477814980942155
30 45 0.383999653859467
30 60 0.509625464595446
30 75 0.440940431784788
60 15 0.445028058361392
60 30 0.522388502880219
60 45 0.428092266657885
60 60 0.429315072676194
60 75 0.358172892912138
90 15 0.493704001125912
90 30 0.508762762699997
90 45 0.450598496609200
90 58 0.468523071441297
120 15 0.501619699042408
120 30 0.561755273071577
120 45 0.489660355057938
120 60 0.475478615354648
120 75 0.482572226928475
150 15 0.423716506205776
150 30 0.426735372570756
150 45 0.448548968227972
150 60 0.478055144126694
150 75 0.437389584937356
To clarify, here is a piece of code that shows the measurement points on a polar plot.
th = A(:,1)*pi/180
polar(th,A(:,2))
view([180 90])
This gives me the following plot:
I would like now to plot the same thing, but instead of the points, use the values of these points stored in A(:,3). Then, I would like to interpolate the data to get a colored surface.
After some research, I found that I need to interpolate my values over a grid, then translate to Cartesian coordinates. From there I do not know how to proceed. Could someone point me in the right direction?
I have trouble getting the concept of the interpolation, but this is what I have attempted:
x1 = linspace(0,2*pi,100)
x2 = linspace(0,90,100)
[XX,YY] = meshgrid(x1,x2)
[x,y] = pol2cart(th,A(:,2))
gr=griddata(x,y,A(:,3),XX,YY,'linear')
With this piece of code, your example data points are converted into cartesian coords, and then plotted as "lines". The two tips of a line are one data point and the origin.
az = bsxfun(#times, A(:,1), pi/180);
el = bsxfun(#times, A(:,2), pi/180);
r = A(:,3);
[x,y,z] = sph2cart(az,el,r);
cx = 0; % center of the sphere
cy = 0;
cz = 0;
X = [repmat(cx,1,length(x));x'];
Y = [repmat(cy,1,length(y));y'];
Z = [repmat(cz,1,length(z));z'];
Still thinking how to interpolate the data so you can draw a sphere. See my comments to your question.
I have an array in Matlab that is updated for every time step: each row corresponds to a time and each column represents a temperature at a certain radius from the center. It would also be handy if a color gradient could be applied to the plot using the meshgrid and contourf commands. So far, this is the Matlab code that I have, but I am not sure how to get the temperature into the plot and animate the change in temperature.
Tinf = 200; % ambient temperature
% where r1 = radius1, r2 = radius2, etc.
% t = time
% rows = time
% columns = radius
% r1 r2 r3 r4 r5
T = [98 105 110 118 128; % t=1
109 110 117 124 134; % t=2
110 118 120 130 144]; % t=3
r = 0.08; % radius of circle
rx = -r:0.01:r;
ry = r:-0.01:-r;
[x_coor, y_coor] = meshgrid(rx, ry);
radius = sqrt(x_coor.^2+y_coor.^2);
figure(1)
contourf(radius,'edgecolor','none')
I am trying to create a circular plot in Matlab that would show the temperature (color) at each radius and animate that temperature (change color) as it increases or decreases with time.
An example of such a plot at a certain time would be:
So column 1 in the T array corresponds to node 1 in the picture, column 2 corresponds to node 2, etc. Thus at time = 0 then node1 = 98, node2 = 105, node3 = 110, node4 = 118, node5 = 128; at time = 1 then node1 = 109, node2 = 110, node3 = 117, node4 = 124, node5 = 134; and so on.
Any suggestions to accomplish such a plot would be very helpful.
Same as #Magla's nice answer but draws a single surface (not an overlay) allowing interpolation
T = [98 105 110 118 128;
109 110 117 124 134;
114 118 120 130 138];
Rmax = 30;
[x,y,z] = sphere(100);
x=x*Rmax;
y=y*Rmax;
rxy2 = x.^2+y.^2;
r = [0 10 20 30];
r2 = r.^2;
figure('Color', 'w');
for ind_t = 1:size(T,1)
for ii = 1:length(r2)-1
ir_find = find(rxy2<=r2(ii+1) & rxy2>r2(ii));
z(ir_find) = T(ind_t,ii);
end
hax = axes('Position',[0 0 1 1]);
h = surf(x,y,z) % sphere centered at origin
shading interp
set(h, 'EdgeColor', 'None');
view(0,90);
axis equal;
set(hax, 'Visible', 'Off', 'CLim', [min(T(:)) max(T(:))]);
pause(0.5);
end
edit
Rewrote to use meshgrid and to use the particular radii etc of interest. Make sure to adjust r_res to a value you find adequate.
T = [98 105 110 118 128;
109 110 117 124 134;
114 118 120 130 138];
%---------------------------------------
r = 0.08; % radius of circle
r_res = 0.0005;
rx = -r:r_res:r;
ry = rx;
[x, y] = meshgrid(rx, ry);
rxy2 = x.^2+y.^2;
z=ones(size(rxy2))*NaN;
%---------------------------------------
Nshells = size(T,2);
r = [0:1/Nshells:1]*r;
r2 = r.^2;
figure('Color', 'w');
colormap hot
for ind_t = 1:size(T,1)
for ii = 1:Nshells
ir_find = find(rxy2<=r2(ii+1) & rxy2>r2(ii));
z(ir_find) = T(ind_t,ii);
end
hax = axes('Position',[0 0 1 1]);
h = surf(x,y,z) % sphere centered at origin
shading interp
set(h, 'EdgeColor', 'None');
view(0,90);
axis equal;
set(hax, 'Visible', 'Off', 'CLim', [min(T(:)) max(T(:))]);
pause(0.5);
end
Here is a solution that makes use of sphere. sphere generates the matrices x and y that are multiply by a decreasing radius r, and matrix z that is reduced to a single value (a sphere becomes a disk). z is multiplied by the temperature and disks are plotted on top of each other. Colors depend on the min and max of the whole input matrix. Animation is done with pause.
T = [98 105 110 118 128;
109 110 117 124 134;
114 118 120 130 138];
[x,y,z] = sphere(100);
r = [50 40 30 20 10];
figure('Color', 'w');
for ind_t = 1:size(T,1)
hax = axes('Position',[0 0 1 1]);
for ii = 1:length(r)
h = surf(x*r(ii),y*r(ii),z*0+T(ind_t,ii)) % sphere centered at origin
set(h, 'EdgeColor', 'None');
hold on;
end
view(0,90);
axis equal;
set(hax, 'Visible', 'Off', 'CLim', [min(T(:)) max(T(:))]);
pause(0.5);
end
This gives
I want to plot a heart shape wireframe as shown in the following image
(source):
I have tried to make it by using this MATLAB program:
n=100;
x=linspace(-3,3,n);
y=linspace(-3,3,n);
z=linspace(-3,3,n);
[X,Y,Z]=ndgrid(x,y,z);
F=((-(X.^2) .* (Z.^3) -(9/80).*(Y.^2).*(Z.^3)) + ((X.^2) + (9/4).* (Y.^2) + (Z.^2)-1).^3);
isosurface(F,0)
lighting phong
caxis
axis equal
colormap('flag');
view([55 34]);
But I didn't get the desired shape of framework as shown in the figure.
I have identified the problem: to create a wireframe we usually use the command mesh(). But this plotting facility only allow us to plot a function of two variables such as z=f(x,y). But my program makes use of three variables: F(x,y,z).
How can I solve the problem?
Here's my best attempt at reproducing the entire figure:
Generating the contoured heart mesh:
I used the contourc function to generate a series of contours in the x-y, x-z, and y-z planes. Notice that in the image you want to reproduce, the mesh lines on the back-facing side of the heart are not rendered. The quickest and easiest way I could think of to reproduce that aspect of the plot was to use isosurface to render a white surface just beneath the inside surface of the mesh, blocking the view of the back side.
Here's the code for the function heart:
function heart
% Initialize the volume data, figure, and axes:
[X,Y,Z] = meshgrid(linspace(-3,3,101));
F = -X.^2.*Z.^3-(9/80).*Y.^2.*Z.^3+(X.^2+(9/4).*Y.^2+Z.^2-1).^3;
hFigure = figure('Position',[200 200 400 400],'Color','w');
hAxes = axes('Parent',hFigure,'Units','pixels',...
'Position',[1 1 400 400],'NextPlot','add',...
'DataAspectRatio',[1 1 1],'Visible','off',...
'CameraViewAngle',10,...
'XLim',[32 70],'YLim',[39 63],'ZLim',[34 73]);
view([-39 30]);
% Create and plot contours in the y-z plane:
for iX = [35 38 41 45 48 51 54 57 61 64 67]
plane = reshape(F(:,iX,:),101,101);
cData = contourc(plane,[0 0]);
xData = iX.*ones(1,cData(2,1));
plot3(hAxes,xData,cData(2,2:end),cData(1,2:end),'k');
end
% Create and plot contours in the x-z plane:
for iY = [41 44 47 51 55 58 61]
plane = reshape(F(iY,:,:),101,101);
cData = contourc(plane,[0 0]);
yData = iY.*ones(1,cData(2,1));
plot3(hAxes,cData(2,2:end),yData,cData(1,2:end),'k');
end
% Create and plot contours in the x-y plane:
for iZ = [36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 69 71]
plane = F(:,:,iZ);
cData = contourc(plane,[0 0]);
startIndex = 1;
if size(cData,2) > (cData(2,1)+1)
startIndex = cData(2,1)+2;
zData = iZ.*ones(1,cData(2,1));
plot3(hAxes,cData(1,2:(startIndex-1)),...
cData(2,2:(startIndex-1)),zData,'k');
end
zData = iZ.*ones(1,cData(2,startIndex));
plot3(hAxes,cData(1,(startIndex+1):end),...
cData(2,(startIndex+1):end),zData,'k');
end
% Fill the inside of the mesh with an isosurface to
% block rendering of the back side of the heart:
p = patch(isosurface(F,-0.001));
set(p,'FaceColor','w','EdgeColor','none');
end
Putting the figure together:
To reproduce the entire figure I first generated the heart mesh using the heart function above, then added the other elements around it. I also used a few submissions from The MathWorks File Exchange:
arrow.m from Erik Johnson (to generate the arrows)
myaa.m from Anders Brun (to create a nice anti-aliased final image)
Here's the code for the function I_Heart_Math (which generates the above figure):
function I_Heart_Math
% Initialize heart plot and adjust figure and axes settings:
heart;
set(gcf,'Position',[200 200 700 300],'Name','Original image');
offset = get(gca,'CameraPosition')-get(gca,'CameraTarget');
offset = 35.*offset./norm(offset);
set(gca,'Position',[65 -9 300 300],'CameraViewAngle',6,...
'XLim',[21+offset(1) 70],'YLim',[16+offset(2) 63],...
'ZLim',[32 81+offset(3)]);
% Create the axes and labels, offsetting them in front of the
% heart to give the appearance they are passing through it:
arrowStarts = [81 51 51; 51 86 51; 51 51 32]+repmat(offset,3,1);
arrowEnds = [21 51 51; 51 16 51; 51 51 81]+repmat(offset,3,1);
arrow(arrowStarts,arrowEnds,5,40,40);
text('Position',[22 52 48]+offset,'String','x','FontSize',12);
text('Position',[50 17 49]+offset,'String','y','FontSize',12);
text('Position',[46.5 51 81.5]+offset,'String','z','FontSize',12);
% Create the equation text:
text('Position',[51 47 28],'FontName','Bookman','FontSize',8,...
'HorizontalAlignment','center',...
'String',{'(x^2+^9/_4y^2+z^2-1)^3-x^2z^3-^9/_{80}y^2z^3=0'; ...
'-3 \leq x,y,z \leq 3'});
% Create the large-type text:
hI = text('Position',[4 52 69.5],'String','I',...
'FontAngle','italic','FontName','Trebuchet MS',...
'FontSize',116,'FontWeight','bold');
hM = text('Position',[80.5 50 42.5],'String','Math',...
'FontAngle','italic','FontName','Trebuchet MS',...
'FontSize',116,'FontWeight','bold');
% Create an anti-aliased version of the figure too (the larger
% fonts need some adjustment to do this... not sure why):
set(hI,'Position',[4 52 68],'FontSize',86);
set(hM,'Position',[80.5 50 41],'FontSize',86);
myaa;
set(hI,'Position',[4 52 69.5],'FontSize',116);
set(hM,'Position',[80.5 50 42.5],'FontSize',116);
set(gcf,'Name','Anti-aliased image');
end
A very elegant solution is given by #gnovice. I though I extend it by adding the other elements to replicate the figure pointed by the OP. I also added some cool animations!
% volume data
[X,Y,Z] = meshgrid(linspace(-3,3,101));
F = -X.^2.*Z.^3 - (9/80).*Y.^2.*Z.^3 + (X.^2 + (9/4).*Y.^2 + Z.^2 - 1).^3;
% initialize figure
hFig = figure('Menubar','none', 'Color','w');
pos = get(hFig, 'Position');
set(hFig, 'Position', [pos(1)-0.15*pos(3) pos(2) 1.3*pos(3) pos(4)]);
% initialize axes
hAxes = axes('Parent',hFig, 'DataAspectRatio',[1 1 1], ...
'XLim',[30 120], 'YLim',[35 65], 'ZLim',[30 75]);
view(-39,30);
axis off
% Fill the inside of the mesh with an isosurface to
% block rendering of the back side of the heart
patch(isosurface(F,-1e-3), 'FaceColor','w', 'EdgeColor','none')
hidden on % hidden surface removal
% contours in the y-z plane
for iX = [35 38 41 45 48 51 54 57 61 64 67]
plane = reshape(F(:,iX,:), [101 101]);
cData = contourc(plane, [0 0]);
xData = iX.*ones(1,cData(2,1));
line(xData, cData(2,2:end), cData(1,2:end), ...
'Color','r', 'Parent',hAxes)
pause(.1)
end
% contours in the x-z plane
for iY = [41 44 47 51 55 58 61]
plane = reshape(F(iY,:,:), [101 101]);
cData = contourc(plane, [0 0]);
yData = iY.*ones(1,cData(2,1));
line(cData(2,2:end), yData, cData(1,2:end), ...
'Color','r', 'Parent',hAxes)
pause(.1)
end
% contours in the x-y plane
for iZ = [36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 69 71]
plane = F(:,:,iZ);
cData = contourc(plane, [0 0]);
startIndex = 1;
if size(cData,2) > (cData(2,1)+1)
startIndex = cData(2,1)+2;
zData = iZ.*ones(1,cData(2,1));
line(cData(1,2:(startIndex-1)), cData(2,2:(startIndex-1)), zData, ...
'Color','r', 'Parent',hAxes)
end
zData = iZ.*ones(1,cData(2,startIndex));
line(cData(1,(startIndex+1):end), cData(2,(startIndex+1):end), zData, ...
'Color','r', 'Parent',hAxes)
pause(.1)
end
% text
props = {'FontWeight','bold', 'FontAngle','italic', 'FontSize',100};
pause(.2)
text(7,50,70, 'I', props{:})
pause(.5)
text(80,50,43, 'Math', props{:})
pause(.2)
% xyz axes
line([20 80], [50 50], [52.5 52.5], 'Color','k')
line([50 50], [20 80], [52.5 52.5], 'Color','k')
line([50 50], [50 50], [30 80], 'Color','k')
text(20,50,50, 'x')
text(48,20,50, 'y')
text(45,50,80, 'z')
drawnow
% equation
props = {'FontSize',10, 'Interpreter','latex'};
text(20,65,30, '$(x^2+9/4y^2+z^2-1)^3 - x^2z^3-9/80y^2z^3=0$', props{:});
text(30,45,30, '$-3 \leq x,y,z \leq 3$', props{:});
drawnow
(The above GIF file was created using GETFRAME and IMWRITE).
This code plots the shaded surface:
% volume data
step = 0.05;
[X,Y,Z] = meshgrid(-3:step:3, -3:step:3, -3:step:3);
F = (-(X.^2).*(Z.^3)-(9/80).*(Y.^2).*(Z.^3))+((X.^2)+(9/4).*(Y.^2)+(Z.^2)-1).^3;
% shaded surface
isosurface(X,Y,Z,F,0)
lighting phong
axis equal
view(-39,30)
set(gcf, 'Color','w')
colormap flag
We could instead plot the wireframe only:
% volume data
step = 0.05;
[X,Y,Z] = meshgrid(-3:step:3, -3:step:3, -3:step:3);
F = (-(X.^2).*(Z.^3)-(9/80).*(Y.^2).*(Z.^3))+((X.^2)+(9/4).*(Y.^2)+(Z.^2)-1).^3;
% wireframe
patch(isosurface(X,Y,Z,F,0), 'FaceColor','w', 'EdgeColor','b')
daspect([1 1 1])
view(3)
axis tight equal
set(gcf, 'Color','w')