A 2D circle divided into 10 sectors in the 3D plot.

2 views (last 30 days)
Dmitriy on 15 Feb 2024
Commented: Star Strider on 28 Feb 2024
Hello, for the visualization of my research results, I would like to create a 3D chart with a circle split in sectors, similar to the one attached. But I need a circle divided into 10 sectors, and I would like to assign concentrations for each sector, for example like in the chart where circle is separated in squares. How can I do it?

Star Strider on 15 Feb 2024
I am not exactly certain what you want.
One approach —
r = 7.5;
ac = linspace(0, 2*pi, 500).';
xc = r*cos(ac);
yc = r*sin(ac);
zc = zeros(size(ac));
as = linspace(0, 2*pi, 11).';
xs = r*cos(as);
ys = r*sin(as);
zs = zeros(size(as));
data = rand(50,3).*[2*pi r 150]; % 'Data': [Angle, Radius, Z-Value]
[X,Y,Z] = pol2cart(data(:,1), data(:,2), data(:,3)); % Convert To Cartesian For Plot
figure
plot3(xc, yc, zc, '-k');
hold on
plot3([zs xs].', [zs ys].', [zs zs].', '-k');
scatter3(X, Y, Z, 25, Z, 'filled')
hold off
grid on
colormap(turbo)
daspect([1 1 15]) % Sets Axes Aspect Ratio
figure
plot3(xc, yc, zc, '-k');
hold on
plot3([zs xs].', [zs ys].', [zs zs].', '-k');
plot3(xc, yc, zc+150, '-k');
plot3([zs xs].', [zs ys].', [zs zs].'+150, '-k');
scatter3(X, Y, Z, 25, Z, 'filled')
hold off
grid on
colormap(turbo)
daspect([1 1 15])
To assign them to specific segments in the plot, consider using stem3 as well, with 'Marker','none'. This will connect each data point to the ‘Z’ surface with a line, and can make the plot easier to understand.
.
Dmitriy on 28 Feb 2024
I got it! Now I understand, have succesfully made charts for my work, thank You very much for your help!
Star Strider on 28 Feb 2024
As always, my pleasure!

Adam Danz on 16 Feb 2024
Edited: Adam Danz on 16 Feb 2024
Creating a polar heatmap within Cartesian coordinates
The basic idea is to create a polar grid centered under the data, plotted as a surface. The color in the surface is defined by the density of points that fall within each sector of the polar grid. To compute density, the 3D points are convered to 2D polar coordinates, ignoring z-coordinates. Then, each point is assigned to a section of the grid using logical conditions. Then the polar grid is converted back to Cartesian units and centered under the data.
Important caveat: The polar grid cells do not have the same area. This means that larger cells will contain more data points than smaller cells in a uniform distribution. This biases the interpretation of the colored regions. This could be corrected by normalizing the color values to the area of each segment in which case the colors would not indicate number of points but instead, number of points per unit of area.
Please also see a limitation to this visualization at the end of the answer.
Demo
Create data
data is an nx3 matrix of [x,y,z] coordinates.
rng default
data = pearsrnd(0,1,.6,4,500,3); % requires stats toolbox
% data = randn(200,3).*[1.2,1,1]+[2,-1,0]; % Alternative
Convert data to polar coordinates
% Shift data to be centered on (0,0) and convert to polar
center = mean(data(:,1:2)); % (x,y) center of the data
Create a polar grid
nThetaSectors determines the number of sections around the circle, starting and ending at -pi, pi.
nRadiiSectors determines the number of sections between the center and outer edge of the circle.
% Compute polar grid
nThetaSectors = 10; % parameter
thetaGrid = linspace(-pi,pi,nThetaSectors+1);
Compute the density of data points within each polar grid cell
% Assign each point to a grid cell
% This only works when there is a border at -pi and pi
[thetaGroup, ~] = find((xTheta(:)>thetaGrid(1:nThetaSectors) & xTheta(:)<=thetaGrid(2:end))');
% Create density grid
density(gidx) = gcounts;
Convert the polar grid to Cartesian coordinates
Here, we also shift the polar grid to the center of the data.
The grid is located under the data along the z-axis by finding the minimum z value and shifting downward by 5 % of the range of z-data.
% Create the polar grid in cartesian coordinates
[tg,rg] = ndgrid(thetaGrid,radiiGrid); % meshgrid requires transpose
[px, py] = pol2cart(tg,rg);
px = px + center(1);
py = py + center(2);
[minZ,maxZ] = bounds(data(:,3));
pFloor = minZ*(0.05*(maxZ-minZ));
pz = zeros(size(px)) + pFloor;
Plot the 3D scatter points
scatter3(data(:,1),data(:,2),data(:,3),'ko')
grid on
axis equal
zlim([pFloor,inf])
hold on
h = surf(px,py,pz,density,'FaceAlpha',.5,'EdgeAlpha',.3);
cb = colorbar();
cb.Label.String = 'Density';
axis vis3d
View from the bottom
view(0,-90)
Limitations
Points are assigned to the segments assuming the segments are circular. The segments aren't plotted circularly, they are plotted as trapazoids. This means in some cases a point will appear outside of a segment when it was, in fact, counted as a member of that segment.
This is illustrated in the image below where a yellow segment indicates that it contains 1 data point. The yellow segement on the left counts the point just outside of the segment because it is within the circular zone (dotted line). This could lead to some confusing results.
One way to improve that is to compute density using inpolygon so belongingness is defined by the plotted trapezoidal segments.
Another way to improve this is to plot circular zones instead of trapezoidal zone.
Neither of these improvements would be quick and easy so I'll leave that to the next person.