How to prevent an object from being illuminated by camlight in Matlab? - matlab

[Hereafter are 4 snippets, one should only be interested in reading the two first ones. However by copy-pasting all of these, one should be able to launch what I see, although screenshots are provided at the end.]
Hi, by launching this main.m :
%To see if plotting a tick after setting camlight headlight will leads to
%its background becoming gray or not
%clear all
figure
arrow = arrow3D([0 0 0], [1 1 1], 'r', 0.8, 0.2, 1.5);
set(arrow, 'EdgeColor', 'interp', 'FaceColor', 'interp');
%camlight headlight %might be interesting to uncomment this line
pause(5)
surfaceHandle = rotateAxisTicks('lol','r',10,-0.3,0.5,0.5,1,1,1,0);
pause(5)
camlight headlight
%material(surfaceHandle,'default') %doesn't work
%surfaceHandle1.FaceLighting = 'none' %doesn't work
, which uses that function rotateAxisTicks.m
function surfaceHandle = rotateAxisTicks(str,color,fontsize,zmax,graduSpace,boxHeight,perc,labelNumber,axnumber,thetaInput)
%https://stackoverflow.com/questions/9843048/matlab-how-to-plot-a-text-in-3d
%zmax : give it a negative value to not overlap the axis
%graduSpace : space between each graduation, within the projected on [0,1] axis if axis = x||y, OR local (not yet projected on x,y) axis !!
%boxHeight : width of the boxes depend on how much the axis graduations are refined, so height shouldn't depend on graduSpace
%perc : if perc = 1 (100%), then the labels are all sticked together with no space inbetween
%labelNumber : the first tick to be displayed is actually associated to the second graduation (0 can't get several labels)
%axnumber : out of nbParams, 1 for x, 2 for y, then, from closest to x, to closest to y : 3 to nbParams.
%thetaInput : (angle around z, from x to the axis) has to be in degree
%% Seems like there is no way to get rid of the black contouring...
hFigure = figure(1000);
set(hFigure,'Color', 'w', ... % Create a figure window
'MenuBar', 'none', ...
'ToolBar', 'none');
hText = uicontrol('Parent', hFigure, ... % Create a text object
'Style', 'text', ...
'String', str, ...
'BackgroundColor', 'w', ...
'ForegroundColor', color, ...
'FontSize', fontsize, ...
'FontWeight', 'normal');
set([hText hFigure], 'Pos', get(hText, 'Extent')); %# Adjust the sizes of the
%# text and figure
imageData = getframe(hFigure); %# Save the figure as an image frame
delete(hFigure);
textImage = imageData.cdata; %# Get the RGB image of the text
%% MAKE THE X,Y,Z (text) REVERSE DEPENDING ON AZIMUT VALUE (launch a fig and see on the bottom in real time the azimut value)
% X or Y or Z(1,1) = _______
% * |
% | |
% |_______|
% X or Y or Z(1,2) = _______
% | *
% | |
% |_______|
% X or Y or Z(2,1) = _______
% | |
% | |
% x_______|
% X or Y or Z(2,2) = _______
% | |
% | |
% |_______x
if axnumber == 2 %axis = y
X = [0 0; 0 0];
Y = [0 perc*graduSpace; 0 perc*graduSpace] + labelNumber*graduSpace - perc*graduSpace/2;
%(graduSpace/2)/2 to center under the graduation, (1-perc)/2) to
%additionally shift a bit so that the perc% of graduSpace stay centered
%under the graduation
else %I assume axis = x, that I might later rotate if it's not actually x
X = [0 perc*graduSpace; 0 perc*graduSpace] + labelNumber*graduSpace - perc*graduSpace/2; %+labelNumber*((graduSpace/2)+((1-perc)/2)*graduSpace)
Y = [0 0; 0 0];
end
Z = [zmax zmax; zmax-boxHeight zmax-boxHeight];
surfaceHandle = surf(X, Y, Z, 'FaceColor', 'texturemap', 'CData', textImage);
if axnumber > 2
rotate(surfaceHandle, [0 0 1], thetaInput,[0 0 0]);
end
end
as well as that function arrow3D.m :
function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, cylRad, radRatioCone)
% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
% pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
% deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
% colorCode - Color parameters as per the 'surf' command. For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
% stemRatio - The ratio of the length of the stem in proportion to the arrowhead. For example, a call of:
% arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
% of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.
%
% Example:
% arrow3D([0,0,0], [4,3,7]); %---- arrow with default parameters
% axis equal;
%
% Author: Shawn Arseneau
% Created: September 14, 2006
% Updated: September 18, 2006
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2 || nargin>6
error('Incorrect number of inputs to arrow3D');
end
if numel(pos)~=3 || numel(deltaValues)~=3
error('pos and/or deltaValues is incorrect dimensions (should be three)');
end
if nargin<3
colorCode = 'interp';
end
if nargin<4
stemRatio = 0.75;
end
X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
Y = pos(2);
Z = pos(3);
[sphi, stheta, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));
%******************************************* CYLINDER == STEM *********************************************
%cylinderRadius = 0.05*srho;
cylinderRadius = cylRad;
cylinderLength = srho*stemRatio;
[CX,CY,CZ] = cylinder(cylinderRadius);
CZ = CZ.*cylinderLength; %---- lengthen
%----- ROTATE CYLINDER
[row, col] = size(CX); %---- initial rotation to coincide with X-axis
newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); %CX(:) actually reshape the 2xN matrices in a 2N vert vector, by vertically concatenating each column
CX = reshape(newEll(:,1), row, col);
CY = reshape(newEll(:,2), row, col);
CZ = reshape(newEll(:,3), row, col);
[row, col] = size(CX);
newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
stemX = reshape(newEll(:,1), row, col);
stemY = reshape(newEll(:,2), row, col);
stemZ = reshape(newEll(:,3), row, col);
%----- TRANSLATE CYLINDER
stemX = stemX + X;
stemY = stemY + Y;
stemZ = stemZ + Z;
%******************************************* CONE == ARROWHEAD *********************************************
coneLength = srho*(1-stemRatio);
coneRadius = cylinderRadius*radRatioCone;
incr = 100; %---- Steps of cone increments
coneincr = coneRadius/incr;
[coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0); %---------- CONE
coneZ = coneZ.*coneLength;
%----- ROTATE CONE
[row, col] = size(coneX);
newEll = rotatePoints([0 0 -1], [coneX(:), coneY(:), coneZ(:)]);
coneX = reshape(newEll(:,1), row, col);
coneY = reshape(newEll(:,2), row, col);
coneZ = reshape(newEll(:,3), row, col);
newEll = rotatePoints(deltaValues, [coneX(:), coneY(:), coneZ(:)]);
headX = reshape(newEll(:,1), row, col);
headY = reshape(newEll(:,2), row, col);
headZ = reshape(newEll(:,3), row, col);
%---- TRANSLATE CONE
V = [0, 0, srho*stemRatio]; %---- centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder
Vp = rotatePoints([0 0 -1], V);
Vp = rotatePoints(deltaValues, Vp);
headX = headX + Vp(1) + X;
headY = headY + Vp(2) + Y;
headZ = headZ + Vp(3) + Z;
%************************************************************************************************************
hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
hold on
hBottStem = fill3(stemX(1,:),stemY(1,:),stemZ(1,:), colorCode, 'EdgeColor', 'none');
hold on
hHead = surf(headX, headY, headZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
hold on
hBottCone = fill3(headX(1,:),headY(1,:),headZ(1,:), colorCode, 'EdgeColor', 'none');
if nargout==1
arrowHandle = [hStem, hBottStem, hHead, hBottCone];
end
which itself uses that function rotatePoints.m :
function rotatedData = rotatePoints(alignmentVector, originalData)
% rotatedData = rotatePoints(alignmentVector, originalData) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Rotate the 'originalData' in the form of Nx2 or Nx3 about the origin by aligning the x-axis with the alignment vector
%
% Rdata = rotatePoints([1,2,-1], [Xpts(:), Ypts(:), Zpts(:)]) - rotate the (X,Y,Z)pts in 3D with respect to the vector [1,2,-1]
%
% Rotating using spherical components can be done by first converting using [dX,dY,dZ] = cart2sph(theta, phi, rho); alignmentVector = [dX,dY,dZ];
%
% Example:
% %% Rotate the point [3,4,-7] with respect to the following:
% %%%% Original associated vector is always [1,0,0]
% %%%% Calculate the appropriate rotation requested with respect to the x-axis. For example, if only a rotation about the z-axis is
% %%%% sought, alignmentVector = [2,1,0] %% Note that the z-component is zero
% rotData = rotatePoints(alignmentVector, [3,4,-7]);
%
% Author: Shawn Arseneau
% Created: Feb.2, 2006
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
alignmentDim = numel(alignmentVector); %number of elements in a matrix
DOF = size(originalData,2); %---- DOF = Degrees of Freedom (i.e. 2 for two dimensional and 3 for three dimensional data)
if alignmentDim~=DOF
error('Alignment vector does not agree with originalData dimensions');
end
if DOF<2 || DOF>3
error('rotatePoints only does rotation in two or three dimensions');
end
if DOF==2 % 2D rotation...
[rad_theta, rho] = cart2pol(alignmentVector(1), alignmentVector(2));
deg_theta = -1 * rad_theta * (180/pi);
ctheta = cosd(deg_theta); stheta = sind(deg_theta);
Rmatrix = [ctheta, -1.*stheta;...
stheta, ctheta];
rotatedData = originalData*Rmatrix;
%assumption: rotate all the datas from the original base to the
%base where the original x becomes alignmentVector
else % 3D rotation...
[rad_theta, rad_phi, rho] = cart2sph(alignmentVector(1), alignmentVector(2), alignmentVector(3));
rad_theta = rad_theta * -1;
deg_theta = rad_theta * (180/pi);
deg_phi = rad_phi * (180/pi);
ctheta = cosd(deg_theta); stheta = sind(deg_theta); %MM : is it more accurate??
Rz = [ctheta, -1.*stheta, 0;...
stheta, ctheta, 0;...
0, 0, 1]; %% First rotate as per theta around the Z axis
rotatedData = originalData*Rz;
[rotX, rotY, rotZ] = sph2cart(-1* (rad_theta+(pi/2)), 0, 1); %% Second rotation corresponding to phi
%assuming alignmentVector is the x for the new base, then the
%hereabove argument corresponds to the y (z inversed)
%the hereabove output = newX(in base 0) vectorial product -z(in base0)
rotationAxis = [rotX, rotY, rotZ];
u = rotationAxis(:)/norm(rotationAxis); %% Code extract from rotate.m from MATLAB
cosPhi = cosd(deg_phi);
sinPhi = sind(deg_phi);
invCosPhi = 1 - cosPhi;
x = u(1);
y = u(2);
z = u(3);
Rmatrix = [cosPhi+x^2*invCosPhi x*y*invCosPhi-z*sinPhi x*z*invCosPhi+y*sinPhi; ...
x*y*invCosPhi+z*sinPhi cosPhi+y^2*invCosPhi y*z*invCosPhi-x*sinPhi; ...
x*z*invCosPhi-y*sinPhi y*z*invCosPhi+x*sinPhi cosPhi+z^2*invCosPhi]';
rotatedData = rotatedData*Rmatrix;
end
I end up getting:
while I would like to conserve both intermediate plots containing the interp arrow:
and the text on flashy white background:
So there are actually two questions:
1) Why calling my text tick disables the interp effect (varying color from blue to yellow) ?
2) How can I keep the camlight without enlightening my tick box? (i.e while keeping its background white)
Basically one should only need to look at the two first snippets, the later 2 ones are useless for my issue.
By thanking you a lot!

Place it in another axes
As I said in comment, you have 2 graphic objects in the same axes which have to interpret their CData in a completely different manner.
The first options I looked for was to modify one of the arrow3d or rotateAxisTicks so their graphic objects would be "compatible" (in the way the color data are interpolated on an axes), but it would be quite intensive and the aspect of the 3d text would have to be constantly monitored/adjusted for any other change in the figure.
So the easiest option is a classic MATLAB hack ... place your graphic objects in different containers (different axes), then superimpose them on a figure, and match some properties (limits, view, etc ...) so they appear to be only one.
Here it goes:
%% Draw your main arrow in the main figure
mainfig = figure ;
ax1 = axes ;
arrow = arrow3D([0 0 0], [1 1 1], 'r', 0.8, 0.2, 1.5);
set(arrow, 'EdgeColor', 'interp', 'FaceColor', 'interp');
camlight headlight
%% Draw your text in a temporary figure
tempfig = figure ;
ax2 = axes ;
surfaceHandle = rotateAxisTicks('lol','r',10,-0.3,0.5,0.5,1,1,1,0);
camlight headlight
%material(surfaceHandle,'default') %doesn't work
%surfaceHandle1.FaceLighting = 'none' %doesn't work
%% Prepare and set matching limits
xl = [ax1.XLim ; ax2.XLim] ;
xl = [min(xl(:,1)) , max(xl(:,2))] ;
yl = [ax1.YLim ; ax2.YLim] ;
yl = [min(yl(:,1)) , max(yl(:,2))] ;
zl = [ax1.ZLim ; ax2.ZLim] ;
zl = [min(zl(:,1)) , max(zl(:,2))] ;
hax = [ax1;ax2] ;
set(hax,'XLim',xl,'YLim',yl,'ZLim',zl)
% Adjust the view to be sure
ax2.View = ax1.View ;
%% Remove secondary axes background, then move it to main figure
ax2.Visible = 'off' ;
ax2.Parent = mainfig ;
delete(tempfig)
%% link the view between axes
hl = linkprop( hax , 'View' ) ;
% or link even more properties at once
% hl = linkprop( hax , 'View' , 'XLim','YLim','ZLim') ;
Which gives you:
note: Your 3d arrow is also made up of 2 different graphic objects (2x surf and 2x patch). The 2 patches are not rendered when you set the interp mode. You should modify the arrow3d function to either (a) changes the patch objects to surf so everything is the same type and compatible, or (b) remove them completely from the function (if they are not rendered they are only annoying ... triggering warnings everywhere).
edit
And here is the modified code for arrow3d.m. I changed it so the output is now only one surface object, easier to assign properties and no danger of mismatch between patch and surf. I also simplified it, removed a few bits that were not necessary, and reduced the total number of points necessary for the surface.
With this you get the bottom of the stem and the under-cone:
function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, cylRad )
% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
% pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
% deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
% colorCode - Color parameters as per the 'surf' command. For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
% stemRatio - The ratio of the length of the stem in proportion to the arrowhead. For example, a call of:
% arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
% of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.
%
% Example:
% arrow3D([0,0,0], [4,3,7]); %---- arrow with default parameters
% axis equal;
%
% Author: Shawn Arseneau
% Created: September 14, 2006
% Updated: September 18, 2006
%
% Updated: December 20, 2018
% Tlab - refactored to have only one surface object as ouput
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2 || nargin>6
error('Incorrect number of inputs to arrow3D');
end
if numel(pos)~=3 || numel(deltaValues)~=3
error('pos and/or deltaValues is incorrect dimensions (should be three)');
end
if nargin<3
colorCode = 'interp';
end
if nargin<4
stemRatio = 0.75;
end
Ncol = 21 ; % default number of column for the "cylinder.m" function
X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
Y = pos(2);
Z = pos(3);
[~, ~, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));
%******************************************* CYLINDER == STEM *********************************************
cylinderRadius = cylRad;
cylinderLength = srho*stemRatio;
[CX,CY,CZ] = cylinder(cylinderRadius,Ncol-1);
CZ = CZ.*cylinderLength; %---- lengthen
%******************************************* CONE == ARROWHEAD *********************************************
coneLength = srho*(1-stemRatio);
[coneX, coneY, coneZ] = cylinder([cylinderRadius*2 0],Ncol-1); %---------- CONE
coneZ = coneZ.*coneLength;
% Translate cone on top of the stem cylinder
coneZ = coneZ + cylinderLength ;
% now close the bottom and add the cone to the stem cylinder surface
bottom = zeros(1,Ncol) ;
CX = [ bottom ; CX ; coneX ] ;
CY = [ bottom ; CY ; coneY ] ;
CZ = [ bottom ; CZ ; coneZ ] ;
Nrow = size(CX,1);
%----- ROTATE
%---- initial rotation to coincide with X-axis
newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); %CX(:) actually reshape the 2xN matrices in a 2N vert vector, by vertically concatenating each column
CX = reshape(newEll(:,1), Nrow, Ncol);
CY = reshape(newEll(:,2), Nrow, Ncol);
CZ = reshape(newEll(:,3), Nrow, Ncol);
newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
stemX = reshape(newEll(:,1), Nrow, Ncol);
stemY = reshape(newEll(:,2), Nrow, Ncol);
stemZ = reshape(newEll(:,3), Nrow, Ncol);
%----- TRANSLATE
stemX = stemX + X;
stemY = stemY + Y;
stemZ = stemZ + Z;
%----- DISPLAY
hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
%----- DISPLAY
if nargout==1
arrowHandle = hStem ;
end

Related

How do i obtain a cross section from a 3D volume?

I want to obtain a 2D slice from the 3D volume in the example (slightly modified) How do I resolve this issue with 3D image visualization? as follows:
% create input image
imageSizeX = 10;
imageSizeY = 10;
imageSizeZ = 10
% generate 3D grid using voxel size = 0.5
[Xq, Yq, Zq] = ndgrid(1:0.5:imageSizeX-1, 1:0.5:imageSizeY-1, 1:0.5:imageSizeZ-1);
% obtain coordinates of all internal vertices, faces, and edges
allCoords = [Xq(:), Yq(:), Zq(:)]; % i need this bit for something very important but not shown in the question.
% Re-generate 3D grid using voxel size = 1
[columnsInImage, rowsInImage, pagesInImage] = ndgrid(1: imageSizeX-1, 1: imageSizeY-1, 1: imageSizeZ-1);
% create the sphere in the image.
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
diameter = 4;
radius = diameter/2;
sphereVoxels = flipud((rowsInImage - centerY).^2 ...
+ (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2);
% change image from logical to numeric labels.
Img = double(sphereVoxels);
for ii = 1:numel(Img)
if Img(ii) == 0
Img(ii) = 2; % intermediate phase voxels
end
end
% specify the desired angle
angle = 30;
% specify desired pixel height and width of solid
width = imageSizeX;
height = imageSizeY;
page = imageSizeZ;
% Find the row point at which theta will be created
y = centerY - ( radius*cos(angle * pi/180) )
% determine top of the solid bar
y0 = max(1, y-height);
% label everything from y0 to y to be = 3 (solid)
Img(1:width, y0:y, 1:page)=3;
%%%%%% Plot the surfaces
[X, Y, Z, C] = build_voxels(Img > 0);
hSurface = patch(X, Y, Z, Img(C),...
'AmbientStrength', 0.5, ...
'BackFaceLighting', 'unlit', ...
'EdgeColor', 'none', ...
'FaceLighting', 'flat');
colormap([1 0 0; 1 1 0]);
axis equal;
axis tight;
view(45, 45);
grid on;
xlabel('x-axis (voxels)');
ylabel('y-axis (voxels)');
zlabel('z-axis (voxels)');
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');
zoom on;
hold on;
Vq = griddata(columnsInImage, rowsInImage, pagesInImage, Img, Xq, Yq, Zq);
figure
h1 = slice(permute(Xq, [2 1 3]),permute(Yq, [2 1 3]),permute(Zq, [2 1 3]), Vq, 5,2,5);
When i run the code, i get an Error message:
"The number of data point locations should equal the number of data point values.
Error in griddata>useScatteredInterp (line 188)
F = scatteredInterpolant(inargs{1}(:),inargs{2}(:),inargs{3}(:), ..."
I want to believe this is so because the size of columnsInImage and size of pagesInImage are not equal to size(P,1) and size(P,3), respectively.
Nonetheless, I also tried to use a vector as follows:
figure
h1 = slice(Img(:,1), Img(:,2), Img(:,3), Img, 5,2,5);
I however still end up with the error message:
"Error using griddedInterpolant
The grid was created from grid vectors that were not strictly monotonic increasing.
Error in interp3 (line 142)
F = griddedInterpolant(X, Y, Z, V, method,extrap);"
Please, guys i need suggestions/ideas on how i could remedy these. Many thanks in advance!..

Calculate area above and below a set level using trapz MATLAB within a range

Data Plot
%% Data
% Imports the array data (x and y) to the workspace by loading Excel data
% that has been imported and converted to *.mat format.
load('900day_r') % y data.
load('x_degreesb'); % x axis data
%% Remove non linear trends
opol = 0;% Degree of filtering on original profile
[p,s,mu] = polyfit(x_degreesb,x900day_r,opol);
f_y = polyval(p,x_degreesb,[],mu);
x900day_r = x900day_r - f_y;
max_x = max(x900day_r);% Find maximum in array
x900day_r = x900day_r/max_x;% Normalize height to max
min_x = min(x900day_r);% Find minimum in array
x900day_r = x900day_r - min_x;% Shift profile (lowest value in array = 0)
%% Find Peaks & Valleys
[pks, locs] = findpeaks(x900day_r); % returns peaks & locations
x900day_r_Inv = max(x900day_r)-x900day_r; % invert y data
vlys = max(vlys)-vlys; % invert data for valley markers
%% Plot Profile
% Plot profile and markers for peaks
plot(x_degreesb,x900day_r,'b',x_degreesb(locs),pks+0.04,'v','markersize',5,'markerfacecolor','b','linewidth',1);
hold on
% Plot profile and markers for valleys
plot(x_degreesb(min_locs),vlys-0.04,'^','markersize',5,'markerfacecolor','b','linewidth',1);
% Plot characteristics
axis('tight') % Makes the graph fill the figure.
grid on % Turns the grid on (major not minor).
% Sets up the figure (fig) for display
fig = gca;
set(fig,'fontname','Bodoni 72','fontsize',20);
% Set y limits to auto. Set x limits and x tick marks
ylim('auto'); % Sets the y limits
xlim([0, 360]); % Sets the x limits from 0 to 360
set (fig, 'XTick', [0, 45, 90, 135, 180, 225, 270, 315, 360]) % Sets x axis tick marks
% Set fig for presentation appearance
x = xlabel('$Location On Cylinder Perimiter {[degrees]}$'); % x label.
y = ylabel('$Curve Height {[mm]}$'); % y label.
t = title('$900 Days Cylinder$ r'); % Title (presentation fraction).
% Set vertical lines at quadrant boundaries
hold on
x1 = 90;
x2 = 180;
x3 = 270;
x4 = 360;
y1 = get(gca, 'ylim');
plot ([x1 x1],y1,'k')%Caudal Medial(0:90)
plot ([x2 x2],y1,'k')%Cranial Medial(90:180)
plot ([x3 x3],y1,'k')%Cranial Lateral(180:270)
plot ([x4 x4],y1,'k')%Cadual Lateral(270:360)
hold on
% Interpretation of text characters for presentation
set(t,'Interpreter','Latex');
set(x,'Interpreter','Latex');
set(y,'Interpreter','Latex');
%% Isolate Cranial Medial & Lateral Section of Profile
x = x_degreesb;% Quadrant data
y = x900day_r;% Profile data
indx = (x >= 90) & (x <= 270);% Index section
[pks, locs, widths, proms] = findpeaks(y(indx));% Find peaks in section
Rmax = max(pks);% Find maximum peak
Rmin = min(y(indx));% Find minimum in section
CL = (Rmax + Rmin)/2;% Center line of sectioned profile
%% Plot Center Line
hold on
x1 = 90;
x2 = 270;
y1 = CL;
plot ([x1 x2],[y1 y1],'r','linewidth',1.5);
%% Plot Rmax
hold on
x1 = 90;
x2 = 270;
y1 = Rmax;
plot ([x1 x2],[y1 y1],'k','linewidth',1.5);
%% Plot Rmin
hold on
x1 = 90;
x2 = 270;
y1 = Rmin;
plot ([x1 x2],[y1 y1],'k','linewidth', 1.5);
%% Highlight Region of Interest
%subplot(2,1,2)
x = x_degreesb;% Quadrant data
y = x900day_r;% Profile data
indx = (x >= 90) & (x <= 270);% Index section
plot(x(indx),y(indx),'k','linewidth',2)% Plot 90:270 curve in black
level = CL;% set the centerline as the level for area shading
% Shade the area of the curve in the indexed section grey [.7 .7 .7] above the level CL
area(x(indx), max(y(indx), level),level, 'EdgeColor', 'none', 'FaceColor',[.7 .7 .7],'showbaseline', 'off');
% Shade the area of the curve in the indexed section dark grey below the level CL
area(x(indx), min(y(indx), level),level, 'EdgeColor', 'none', 'FaceColor',[.5 .5 .5],'showbaseline','off');
Does anyone know how I can find the area above (light grey) and below (dark grey) the centerline (red) for the specific range between 90:270 using MATLAB? I have been trying to use trapz, setting the level (red line in Data Plot picture) but can't seem to get trapz to calculate just the highlighted areas. I posted the code, but not the data, as its a rather large set of data that makes up the curve. Any help would be greatly appreciated!
RP
#Some Guy: Thanks for the quick responses. Here is an example script that you can run. You can change the ratio of blue area to grey area by changing the level value. In pic 1 with level set to 2 they should be equal. In pic 2 blue should be more than grey with level set to 1.6. Thats what I was trying to do. Any thoughts?
%% Example
x = 0:.01:4*pi;% x data
y = sin(x)+2;% y data
level = 1.6;% level
plot(x, y)
hold on
x_interest = 0:.01:x(length(y));
y_interest = sin(x_interest)+2;
xlim ([0 x(length(y))])
% Shaded area above level
area(x_interest, max(y_interest, level), level, ...
'EdgeColor', 'none', 'FaceColor', [.6 .7 .8], ...
'ShowBaseLine', 'off');
% Shaded area below level
area(x_interest, min(y_interest, level), level, ...
'EdgeColor', 'none', 'FaceColor', [.5 .5 .5], ...
'ShowBaseLine', 'off');
y_above = max(y_interest - level,0); % Take only the part of curve above y_split
y_below = max(-y_above,0); % Take the part below y_split
A_above = trapz(y_above)
A_below = trapz(y_below)
If I had data in a vector y and a scalar y_split at which I wanted to split I would do:
y_above = y - y_split;
y_below = max(-y_above,0); % Take the part below y_split
y_above = max(y_above,0); % Take the part above y_split
A_above = trapz(y_above);
A_below = trapz(y_below);
You can plot y_above and y_below to make sure you are integrating as you intend to.
EDIT: With OPs example script the areas with level = 2 is:
A_above =
399.9997
A_below =
399.9976
And level = 1.6 is
A_above =
683.5241
A_below =
181.1221

hexagonal lattice which is randomly colored with black and white color

I am trying to draw a (10,000 x 10,000) hexagonal lattice which is randomly half black and half white.I don't know how to fill hexagons of this lattice randomly to black and white.(this is a sample of what i really want from this code but I couldn't make it.).here is the code(written in matlab):
clc
x=input('enter the value of x: ');
y=input('enter the value of y: ');
r=input('enter the value of R: ');
n=input('enter the value of N: ');
d=sqrt(3*n)*r
axis([0 x 0 y ])
c=r;
v=30:60:390;
cv=r*cosd(v);
sv=r*sind(v);
for y=0:2:y
for w=0:2:x
line(w*sqrt(3)/2*c+cv,y*1.5*c+sv,'tag','h');
end
end
for m=1:2:y
for k=1:2:x
line(k*sqrt(3)/2*c+cv,m*1.5*c+sv,'tag','h');
end
end
can anyone help me through this?
Not recommended!
You can achieve your desired output using fill and by coordinating through the lattice correctly:
m = 100; % horizontal count
n = 50; % vertical count
blackratio = 0.5; % here you can choose the ratio of black hexagons
% parametric definition of a hexagon
t = (1/12:1/6:1)'*2*pi;
x = cos(t);
y = sin(t);
blacks = rand(m, n) < blackratio;
d=sqrt(3)/2;
figure;
hold on
for ii = 1:m
for jj = 1:n
if blacks(ii, jj)
% draw a black hexagon
fill(x + d*(mod(2*ii+jj, 2*m)), y+1.5*jj, 'k', 'EdgeColor', 'None')
else
% draw a white hexagon
fill(x + d*(mod(2*ii+jj, 2*m)), y+1.5*jj, 'w', 'EdgeColor', 'None')
end
end
end
axis equal tight off
With this output:
Note that on my laptop for 100x50 it took 6 seconds to get the result. For 1000x1000 my computer crashed.
The second fill function in my code replaces the transparency with white color. If you are fine with having transparency instead of white filling, you can remove this part of the code and double the speed.
You can plot multiple filled polygons using patch. This approach is extremely faster than drawing hexagons with fill one by one in a loop.
m = 100; % horizontal count
n = 50; % vertical count
blackratio = 0.5; % here you can choose the ratio of black hexagons
blacks = rand(m, n) > blackratio;
hexcount = sum(blacks(:));
whitecount = m * n - hexcount;
% parametric definition of a hexagon
t = (1/12:1/6:1)' * 2 * pi;
x = cos(t);
y = sin(t);
% coordinates of all black hexagons
Xb = zeros(6, hexcount);
Yb = zeros(6, hexcount);
% coordinates of all white hexagons
Xw = zeros(6, whitecount);
Yw = zeros(6, whitecount);
d=sqrt(3)/2;
bcount = 0;
wcount = 0;
for ii = 1:m
for jj = 1:n
if blacks(ii, jj)
bcount = bcount + 1;
Xb(:, bcount) = x + d * (mod(2 * ii + jj, 2 * m));
Yb(:, bcount) = y + 1.5 * jj;
else
wcount = wcount + 1;
Xw(:, wcount) = x + d * (mod(2 * ii + jj, 2 * m));
Yw(:, wcount) = y + 1.5 * jj;
end
end
end
figure; hold on
patch(Xb, Yb, 'k', 'EdgeColor', 'None')
patch(Xw, Yw, 'w', 'EdgeColor', 'None')
axis equal off
This gives you the desired output:

How to make colorbar refer to markers in 3D-plot and not the surface in Matlab

I have a plot of the following type:
I have created the black-white surface using the surf-function and the markers I have plotted using plot3-function. For each marker I have defined a colormap between Red-Yellow-Green depending on the value of the marker. As you can see from the plot the colorbar refers at the moment to the surface but I would like it to refer to the markers. How can I do this?
Thank you!
Here is MWE basically showing what I do now:
% Plot the surface with a colormap
Z = peaks;
Z = peaks./max(Z(:));
Z = (Z+1)*3/2;
surf(Z)
colormap(flipud(gray))
shading interp
hold on
% Create the 4-dimensional marker data
x = (50-10).*rand(50,1) + 10;
y = (50-10).*rand(50,1) + 10;
z = (3-1).*rand(50,1) + 1;
q = 5.*rand(50,1); % This dimension is used to select the color
% Create the color map for the markers
c1=[0 1 0]; %G
c2=[1 1 0]; %Y
c3=[1 0 0]; %R
n1 = 20;
n2 = 20;
cmap=[linspace(c1(1),c2(1),n1);linspace(c1(2),c2(2),n1);linspace(c1(3),c2(3),n1)];
cmap(:,end+1:end+n2)=[linspace(c2(1),c3(1),n2);linspace(c2(2),c3(2),n2);linspace(c2(3),c3(3),n2)];
cmap = cmap';
% Select the colors for the markers
marker_colors = zeros(size(50, 1), 3);
q_interval = max(q)-min(q);
q_int = q_interval/(n1+n2);
q_vals = zeros(n1+n2,1);
q_vals(1) = min(q);
for i = 2:size(q_vals,1)
q_vals(i) = min(q) + (i-1)*q_int;
end
for i = 1:50
d = abs(q_vals - q(i));
ind = find(d == min(d));
marker_colors(i,:) = cmap(ind,:);
% Plot the marker
plot3(x(i), y(i), z(i), 'o', 'color', [0 0 0], 'MarkerFaceColor', marker_colors(i,:))
end
% Lastly I plot the colorbar, which refers to the surface... :/
colorbar
If you do not rely on plot3 function you can use scatter3 instead.
%% Data for surface
[X,Y]=meshgrid(-2:.1:2, -2:.1:2);
Z=max(0,peaks(X,Y));
C=1-cat(3,Z,Z,Z)/max(Z(:));
%% data for points
x=(rand(50,1)*4)-2;
y=(rand(50,1)*4)-2;
z=max(0,peaks(x,y));
c=0.5*rand(50,1);
%% Colormap
c1=[0 1 0]; %G
c2=[1 1 0]; %Y
c3=[1 0 0]; %R
n1 = 20;
n2 = 20;
cmap=[linspace(c1(1),c2(1),n1);linspace(c1(2),c2(2),n1);linspace(c1(3),c2(3),n1)];
cmap(:,end+1:end+n2)=[linspace(c2(1),c3(1),n2);linspace(c2(2),c3(2),n2);linspace(c2(3),c3(3),n2)];
cmap = cmap';
%% Create surface with texture defined in C
surf(X,Y,Z,C)
shading interp
hold on
%% plot points in coordinates x,y,z with markers with 12 pt in diameter,
%% coloured according to c values, filled and with black marker edges.
scatter3(x,y,z,12,c,'filled','markerEdgeColor','k')
%% set colormap (change will apply only for scatter because surf uses texxture map)
colormap(cmap)
colorbar

Plotting too slow on Matlab

I am having some issues with a code I am writing, simply because it is too long to plot. What I am trying to do is for matlab to plot a series of ellipses filled with colors depending on a specific parameter.
Here is the code I am using:
clearvars -except data colheaders
close all
clc
data(:,15)=data(:,9)*pi/180; % Convers Column 9 (angle of rotation) in rad
data(:,16)=1196-data(:,6); % Reset the Y coordinate axis to bottom left
delta = 0 : 0.01 : 2*pi; % Converts roation angle in rad
theta=45*pi/180; % Sample cutting angle
imax=5352; % Numbers of rows in data sheet
% Define variables for colors
beta=acos(data(1:imax,8)./data(1:imax,7));%./acos(0);
phi=atan(sin(beta).*cos(data(1:imax,15))./(sin(theta)*sin(beta).*sin(data(1:imax,15))+cos(theta)*cos(beta)))/(pi/2);
phi2=phi/2+1/2; % Set phi within 0 and 1 for colormap
gamma=atan((cos(theta)*sin(beta).*sin(data(1:imax,15))-sin(theta)*cos(beta))./...
(sin(theta)*sin(beta).*sin(data(1:imax,15))+cos(theta)*cos(beta)))/(pi/2);
gamma2=gamma+1/2; % Set gamma between 0 and 1 for colormap
cm = colormap(jet) ; % returns the current color map
% Sort and get their index to access the color array
[~,idx] = sort(phi);
for i=1:imax
x = data(i,7)/2 * cos(delta) * cos(data(i,15)) - data(i,8)/2 * sin(delta) * sin(data(i,15)) + data(i,5);
y = data(i,8)/2 * sin(delta) * cos(data(i,15)) + data(i,7)/2 * cos(delta) * sin(data(i,15)) + data(i,16);
colorID1 = max(1, sum(phi2(i) > [0:1/length(cm(:,1)):1]));
colorID2 = max(1, sum(gamma2(i) > [0:1/length(cm(:,1)):1]));
ColorMap1(i,:) = cm(colorID1, :); % returns your color
ColorMap2(i,:) = cm(colorID2, :); % returns your color
hold on
% Columns (5,6) are the centre (x,y) of the ellipse
% Columns (7,8) are the major and minor axes (a,b)
% Column 9 is the rotation angle with the x axis
figure(1);
fill(x,y,ColorMap1(i,:),'EdgeColor', 'None');
title('Variation of In-plane angle \phi')
colorbar('SouthOutside')
grid on;
caxis([-90 90])
%text(data(i,5),data(i,16),[num2str(0.1*round(10*acos(0)*180*phi(i)/pi))])
figure(2);
fill(x,y,ColorMap2(i,:),'EdgeColor', 'None');
title('Variation of Out-of-plane angle \gamma')
colorbar('SouthOutside')
grid on;
caxis([-45 45])
%text(data(i,5),data(i,16),[num2str(0.1*round(10*acos(0)*180*gamma(i)/pi))])
% Assigns angle data to each ellipse
end
axis equal;
Maybe someone knows how to make that it doesnt take ages to plot ( i know figure is a bad method, but I want 2 specific colormap for the 2 variables phi and gamma).
Cheers guys
Example data you can use to run the code
data(:,5) = [3 ;5 ;12; 8]; % Centre location X
data(:,6) = [1; -5 ;-2; 4]; % Centre location Y
data(:,7) = [6 ;7;8;9]; % Major Axis a
data(:,8) = [2;3;3;5]; % Minor axis b
data(:,9) = [10;40;45;90]; % Angle of rotation
All you need to do is change imax for 4 instead of 5352 and it should work
Dorian