I am trying to create a spherical histogram and I have found an addon that creates a spherical histogram, however it uses equal area quadrilaterals and for my purposes I would like to preserve the lines found on the traditional sphere created with MATLAB so they can match latitude and longitude lines.
I found a way to color a given subset of the sphere by setting the min/max Azimuth and Elevation values of the region I want to shade, and to try and test out coloring each cell of the sphere I have tried dividing the azimuth and elevation total angles by a given n value and looping through to assign a random color to each cell. This works for about 2/3s of the cells, however there are random azimuth/elevation sections where there is no color assigned, indicating some type of problem with the surf() function presumably. I thought the count n for the sphere being only 20 might cause rounding errors that would be the main contributing factor for this, but there are proportionally similar sized gaps found for a 50x50 cell sphere as well. My best guess is some kind of rounding precision error that causes the given cell region to skip assigning a color due to the given bounds being too far from matching an actual cell, essentially having the given bounds being in between two lines. How can I iterate through every cell based on its azimuth and elevation range for a given sphere of size n?
n = 20;
%// Change your ranges here
minAzimuth = -180;
maxAzimuth = 180;
minElevation = 0;
maxElevation = 180;
%// Compute angles - assuming that you have already run the code for sphere
[x,y,z] = sphere(n);
theta = acosd(z);
phi = atan2d(y, x);
%%%%%// Begin highlighting logic
ind = (phi >= minAzimuth & phi <= maxAzimuth) & ...
(theta >= minElevation & theta <= maxElevation); % // Find those indices
x2 = x; y2 = y; z2 = z; %// Make a copy of the sphere co-ordinates
x2(~ind) = NaN; y2(~ind) = NaN; z2(~ind) = NaN; %// Set those out of bounds to NaN
%%%%%// Draw our original sphere and then the region we want on top
r = 1;
surf(r.*x,r.*y,r.*z,'FaceColor', 'white', 'FaceAlpha',0); %// Base sphere
hold on;
%surf(r.*x2,r.*y2,r.*z2,'FaceColor','red', 'FaceAlpha',0.5); %// Highlighted portion
%// Adjust viewing angle for better view
for countAz = 1:1:n
current_minAzimuth = -180 (countAz-1) * (360/n);
current_maxAzimuth = -180 (countAz) * (360/n);
for countE = 1:1:n
current_minElevation = 0 (countE-1) * (180/n);
current_maxElevation = 0 (countE) * (180/n);
theta = acosd(z);
phi = atan2d(y, x);
%%%%%// Begin highlighting logic
ind = (phi >= current_minAzimuth & phi <= current_maxAzimuth) & ...
(theta >= current_minElevation & theta <= current_maxElevation); % // Find those indices
x2 = x; y2 = y; z2 = z; %// Make a copy of the sphere co-ordinates
x2(~ind) = NaN; y2(~ind) = NaN; z2(~ind) = NaN;
random_color = rand(1,3);
surf(r.*x2,r.*y2,r.*z2,'FaceColor',random_color, 'FaceAlpha',1);
end
end
axis equal;
view(40,40);
And here is an n=20 sphere
CodePudding user response:
You're doing more conversions to and from spherical/Cartesian coordinates than you need to, and subsequently doing more floating point comparisons than required.
You are essentially just looping through all of the 2x2 index blocks in the x
, y
and z
arrays.
It's simpler to just directly create the index arrays you're trying to use and then pull out those values of the existing surface coordinates.
for countAz = 1:1:n
for countE = 1:1:n
% Linear index for a 2x2 patch of the matrices
idx = countAz [0,1,n (1:2)] (countE-1)*n;
% Pull out the coordinates, reshape for surf
x2 = x(idx); x2 = reshape(x2,2,2);
y2 = y(idx); y2 = reshape(y2,2,2);
z2 = z(idx); z2 = reshape(z2,2,2);
random_color = rand(1,3);
surf(r*x2,r*y2,r*z2,'FaceColor',random_color, 'FaceAlpha',1);
end
end