I want to be able to plot a 3D circle in MATLAB's AppDesigner. How can I do so? - matlab

I have a code where I am taking x1, y1, z1 and the radius d as inputs from the user. In my callback function, I am reading these values and I have to plot a 3D circle in MATLAB's App Designer. How can I do so? I have a code for plotting a point in 2D but the same thing is not working when I am trying for a 3D plot.
x1 = app.NumericEditField.Value;
y1 = app.NumericEditField4.Value;
z1 = app.NumericEditField7.Value;
plot(app.UIAxes,x1,y1,'o'); %Code for a point in 2D plot.
grid(app.UIAxes,'on');

Plotting Circles and Spheres on UIAxes
A circle can be plotted in MATLAB app-designer by using the plot3() function. Sin() and cos() can then be used to get a set number of (x,y) points which can be stored in a matrix. Another matrix of the same size which stores the (z) points must also be created.
In short 3 vectors for the x,y,z points and plot3() are required. I also included a sphere just in case.
app = uifigure();
app.Color = '#FFFFFF';
Field_Height = 20;
Field_Width = 80;
%Creating input text field for x1%
x1 = uieditfield(app,'numeric');
x1.Position = [10 100 Field_Width Field_Height];
x1_Label = uilabel(app);
x1_Label.Text = 'x1';
x1_Label.Position = [100 100 Field_Width Field_Height];
%Creating input text field for y1%
y1 = uieditfield(app,'numeric');
y1.Position = [10 70 Field_Width Field_Height];
y1_Label = uilabel(app);
y1_Label.Text = 'y1';
y1_Label.Position = [100 70 Field_Width Field_Height];
%Creating input text field for z1%
z1 = uieditfield(app,'numeric');
z1.Position = [10 40 Field_Width Field_Height];
z1_Label = uilabel(app);
z1_Label.Text = 'z1';
z1_Label.Position = [100 40 Field_Width Field_Height];
%Creating input text field for the radius%
Radius = uieditfield(app,'numeric');
Radius.Position = [10 10 Field_Width Field_Height];
Radius_Label = uilabel(app);
Radius_Label.Text = 'Radius';
Radius_Label.Position = [100 10 Field_Width Field_Height];
%Creating 3D axes%
Axes_3D = uiaxes(app);
Axes_3D.Position = [150 20 400 400];
plot3(Axes_3D,0,0,0,'Color','b');
Axes_3D.XGrid = 'on';
Axes_3D.YGrid = 'on';
Axes_3D.ZGrid = 'on';
Axes_3D.XLabel.String = "x axis";
Axes_3D.YLabel.String = "y axis";
Axes_3D.ZLabel.String = "z axis";
Axes_3D.BackgroundColor = '#FFFFFF';
%Setting callback functions for each input field%
x1.ValueChangedFcn = #(x1,event) Plot_Sphere(x1,y1,z1,Radius,Axes_3D);
y1.ValueChangedFcn = #(y1,event) Plot_Sphere(x1,y1,z1,Radius,Axes_3D);
z1.ValueChangedFcn = #(z1,event) Plot_Sphere(x1,y1,z1,Radius,Axes_3D);
Radius.ValueChangedFcn = #(Radius,event) Plot_Sphere(x1,y1,z1,Radius,Axes_3D);
%Function that gets called when any input field is changed%
function [] = Plot_Sphere(X_Field,Y_Field,Z_Field,Radius_Field,Axes_3D)
%Grab the positions.offsets from each field%
X_Position = X_Field.Value;
Y_Position = Y_Field.Value;
Z_Position = Z_Field.Value;
Radius = Radius_Field.Value;
%Creating a matrix of points for the sphere%
[X_Base,Y_Base,Z_Base] = sphere;
%Multiplying the points depending on a given radius%
X = X_Base * Radius;
Y = Y_Base * Radius;
Z = Z_Base * Radius;
%Creating a matrix of points for the circle%
Number_Of_Data_Points = 200;
theta = linspace(0,2*pi,Number_Of_Data_Points);
X_Circle = Radius*cos(theta);
Y_Circle = Radius*sin(theta);
Z_Circle = zeros(1,Number_Of_Data_Points);
%Plotting the circle%
plot3(Axes_3D,X_Circle+X_Position,Y_Circle+Y_Position,Z_Circle+Z_Position);
%Switch this line to get sphere%
% plot3(Axes_3D,X+X_Position,Y+Y_Position,Z+Z_Position,'Color',[0, 0.4470, 0.7410]);
%Switch this line to get sphere filled%
% surf(Axes_3D,X+X_Position,Y+Y_Position,Z+Z_Position);
end
Ran using MATLAB R2019b

Related

Line with NumericRuler-properties in Matlab

I want to create a relative axis in Matlab like the $\Delta I$-rulers in the following plot.
Before I start writing up a function that constructs it manually, I would like to know if there's way of creating an object with the NumericRuler-properties (like the default axes of a figure())
So I ended up using the link provided by Sardar Usama's comment as inspiration and wrote a function to create an axes-object relative to the values of a "parent"-axes:
function ax = create_value_axes(hAx, pos)
%% ax = create_value_axes(hAx, pos)
%
% Create axes at the value points of hAx.
%
% pos(1) = x-position
% pos(2) = y-position
% pos(3) = x-width
% pos(4) = y-width
%
% Get "parent" position and value limits
hAx_pos = hAx.Position;
hAx_xlm = hAx.XLim;
hAx_ylm = hAx.YLim;
% Get relative position increment pr value increment
x_step = hAx_pos(3) / (hAx_xlm(2) - hAx_xlm(1));
y_step = hAx_pos(4) / (hAx_ylm(2) - hAx_ylm(1));
% Set position
subaxes_abs_pos(1) = (pos(1)-hAx_xlm(1)) * x_step + hAx_pos(1);
subaxes_abs_pos(2) = (pos(2)-hAx_ylm(1)) * y_step + hAx_pos(2);
subaxes_abs_pos(3) = pos(3) * x_step;
subaxes_abs_pos(4) = pos(4) * y_step;
% Create axes
ax = axes('Position', subaxes_abs_pos);
% Remove background
ax.Color = 'none';
end
Sidenote: I found that I didn't need plotboxpos to get the correct positions of the "parent"-axes, using Matlab r2019b on macOS Mojave 10.14.6
Anyway, this is what I end up with:
Using the code:
% Just some random data
mockup_data_ild = [-10 -7 -4 0 4 7 10];
mockup_data_itd_45 = [-40 -20 -10 0 10 20 40];
mockup_data_itd_60 = [-30 -15 -5 0 5 15 30];
% Create figure
figure('Color', 'w')
x_axis_offset = [0 30];
hold on
% Plot 45 dB result
p1 = plot_markers(x_axis_offset(1) + mockup_data_ild, mockup_data_itd_45, ii);
% Plot 60 dB results
p2 = plot_markers(x_axis_offset(2) + mockup_data_ild, mockup_data_itd_60, ii);
p2.Color = p1.Color;
p2.HandleVisibility = 'off';
hold off
% Set axes properties
ax = gca;
ax.XAxis.TickValues = [x_axis_offset(1) x_axis_offset(2)];
ax.XAxis.TickLabels = {'45 dB' '60 dB'};
ax.XAxis.Limits = [x_axis_offset(1)-15 x_axis_offset(2)+15];
ax.XAxisLocation = 'top';
ax.YAxis.Limits = [-80 100];
ax.YAxis.Label.String = 'Interaural Time Difference, \Deltat, in samples';
ax.YGrid = 'on';
% Create 45 dB axis
ax2 = create_DeltaI_axis(ax, x_axis_offset(1));
% Create 60 dB axis
ax3 = create_DeltaI_axis(ax, x_axis_offset(2));
% Create legend
leg = legend(ax, {'P1'});
leg.Location = 'northwest';
%% Helpers
function ax = create_DeltaI_axis(hAx, x_pos)
y_pos = -70;
y_height = 170;
range = 20;
ax = create_value_axes(hAx, [x_pos-range/2 y_pos range y_height]);
ax.XAxis.TickValues = [0 .25 .5 .75 1];
ax.XAxis.TickLabels = {'-10'
'-5'
'0'
'5'
'10'};
ax.XAxis.Label.String = '\DeltaI';
ax.XGrid = 'on';
ax.XMinorGrid = 'on';
ax.YAxis.Visible = 'off';
end
function p = plot_markers(x, y, ii)
markers = {'square','^', 'v', 'o', 'd'};
p = plot(x, y);
p.LineWidth = 1.5;
p.LineStyle = 'none';
p.Marker = markers{ii};
end

How to display a group of subplots as a movie?

I have 30 heatmap subplots. How could I present these subplots as an animation or a movie (i.e. one heatmap each 0.5 seconds)?
The subplots are obtained with the following code:
var = {'GeneX','GeneY','GeneZ'};
syms x y z S
alpha_x = 3.9e-2;
beta_x = 6.1;
z_x = 1.3e-5;
n_zx = 2.32;
alpha_y= 4.3e-2;
beta_y = 5.7;
x_y = 7.9e-4;
n_xy = n_zx;
delta_y = 1.05;
x_z = 12e-2;
n_xz = n_zx;
y_z = 11e-3;
n_yz = n_zx;
delta_z = 0.2;
ACDC_X = (alpha_x+beta_x*S)/(1+S+(z/z_x)^n_zx)-x;
ACDC_Y = (alpha_y+beta_y*S)/(1+S+(x/x_y)^n_xy)-delta_y*y;
ACDC_Z = 1/(1+(x/x_z)^n_xz+(y/y_z)^n_yz)-delta_z*z;
ACDCsys_div = [ ACDC_X, ACDC_Y, ACDC_Z ];
J = jacobian(ACDCsys_div,[x;y;z]);
Jsolnew(x,y,z,S) = [J];
%%Construction of the coordinates as a matrix
A = load('matlab.mat','unnamed');% import data from directory
a2 = struct2array(A);% coordinates of the equilibrium point.
numofGraphs = 80;
bx = length(a2(1,1:numofGraphs));
%% Construction of the heatmaps
figure;
hmapax = ceil(sqrt(bx));
for kk = 1:bx %bnx %All bin windows = iteration
JacACDCnew(:,:,kk) = Jsolnew(a2(1,kk),a2(2,kk),a2(3,kk),a2(4,kk));
ACDC_HmapJnew = double(JacACDCnew(:,:,kk));
subplot(hmapax,hmapax,kk);%
heatmap(var,var,ACDC_HmapJnew,'ColorScaling','log');
S = a2(4,kk);
title(['Jac','s=',num2str(S)]);
end
Consider the following example:
function q56130816
% Load some data:
frames = imread('https://i.stack.imgur.com/03kN8.gif');
frames(frames > 1) = 2;
% Create subplots:
figure('WindowState','maximized'); subplot(2,4,1);
for ind1 = 1:8
subplot(2,4,ind1);
imagesc(frames(:,:,1,ind1)); axis image; axis off;
end
colormap([255 255 255; 188 188 188; 244 128 36]./255);
% Capture subplots as frames:
for ind1 = 8:-1:1
frameHolder(ind1) = getframe( subplot(2, 4 ,ind1) );
end
% Play as movie:
hF = figure(); movie(hF, frameHolder, 20, 2);
Which will turn:
Into:
As you can see, in the example above I used getframe, but frames can also be captured using print, as mentioned in the getframe docs. Frames can also be exported to a video file, as explained here.
Animation credit: frames were screen-captured from Johan Lindell's Codepen example.

Plot equally spaced markers along a spiral

I want to move a red star marker along the spiral trajectory with an equal distance of 5 units between the red star points on its circumference like in the below image.
vertspacing = 10;
horzspacing = 10;
thetamax = 10*pi;
% Calculation of (x,y) - underlying archimedean spiral.
b = vertspacing/2/pi;
theta = 0:0.01:thetamax;
x = b*theta.*cos(theta)+50;
y = b*theta.*sin(theta)+50;
% Calculation of equidistant (xi,yi) points on spiral.
smax = 0.5*b*thetamax.*thetamax;
s = 0:horzspacing:smax;
thetai = sqrt(2*s/b);
xi = b*thetai.*cos(thetai);
yi = b*thetai.*sin(thetai);
plot(x,y,'b-');
hold on
I want to get a figure that looks like the following:
This is my code for the circle trajectory:
% Initialization steps.
format long g;
format compact;
fontSize = 20;
r1 = 50;
r2 = 35;
r3= 20;
xc = 50;
yc = 50;
% Since arclength = radius * (angle in radians),
% (angle in radians) = arclength / radius = 5 / radius.
deltaAngle1 = 5 / r1;
deltaAngle2 = 5 / r2;
deltaAngle3 = 5 / r3;
theta1 = 0 : deltaAngle1 : (2 * pi);
theta2 = 0 : deltaAngle2 : (2 * pi);
theta3 = 0 : deltaAngle3 : (2 * pi);
x1 = r1*cos(theta1) + xc;
y1 = r1*sin(theta1) + yc;
x2 = r2*cos(theta2) + xc;
y2 = r2*sin(theta2) + yc;
x3 = r3*cos(theta3) + xc;
y3 = r3*sin(theta3) + yc;
plot(x1,y1,'color',[1 0.5 0])
hold on
plot(x2,y2,'color',[1 0.5 0])
hold on
plot(x3,y3,'color',[1 0.5 0])
hold on
% Connecting Line:
plot([70 100], [50 50],'color',[1 0.5 0])
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0, 1, 1]);
drawnow;
axis square;
for i = 1 : length(theta1)
plot(x1(i),y1(i),'r*')
pause(0.1)
end
for i = 1 : length(theta2)
plot(x2(i),y2(i),'r*')
pause(0.1)
end
for i = 1 : length(theta3)
plot(x3(i),y3(i),'r*')
pause(0.1)
end
I can't think of a way to compute distance along a spiral, so I'm approximating it with circles, in hopes that it will still be useful.
My solution relies on the InterX function from FEX, to find the intersection of circles with the spiral. I am providing an animation so it is easier to understand.
The code (tested on R2017a):
function [x,y,xi,yi] = q44916610(doPlot)
%% Input handling:
if nargin < 1 || isempty(doPlot)
doPlot = false;
end
%% Initialization:
origin = [50,50];
vertspacing = 10;
thetamax = 5*(2*pi);
%% Calculation of (x,y) - underlying archimedean spiral.
b = vertspacing/(2*pi);
theta = 0:0.01:thetamax;
x = b*theta.*cos(theta) + origin(1);
y = b*theta.*sin(theta) + origin(2);
%% Calculation of equidistant (xi,yi) points on spiral.
DST = 5; cRes = 360;
numPts = ceil(vertspacing*thetamax); % Preallocation
[xi,yi] = deal(NaN(numPts,1));
if doPlot && isHG2() % Plots are only enabled if the MATLAB version is new enough.
figure(); plot(x,y,'b-'); hold on; axis equal; grid on; grid minor;
hAx = gca; hAx.XLim = [-5 105]; hAx.YLim = [-5 105];
hP = plot(xi,yi,'r*');
else
hP = struct('XData',xi,'YData',yi);
end
hP.XData(1) = origin(1); hP.YData(1) = origin(2);
for ind = 2:numPts
P = InterX([x;y], makeCircle([hP.XData(ind-1),hP.YData(ind-1)],DST/2,cRes));
[~,I] = max(abs(P(1,:)-origin(1)+1i*(P(2,:)-origin(2))));
if doPlot, pause(0.1); end
hP.XData(ind) = P(1,I); hP.YData(ind) = P(2,I);
if doPlot, pause(0.1); delete(hAx.Children(1)); end
end
xi = hP.XData(~isnan(hP.XData)); yi = hP.YData(~isnan(hP.YData));
%% Nested function(s):
function [XY] = makeCircle(cnt, R, nPts)
P = (cnt(1)+1i*cnt(2))+R*exp(linspace(0,1,nPts)*pi*2i);
if doPlot, plot(P,'Color',lines(1)); end
XY = [real(P); imag(P)];
end
end
%% Local function(s):
function tf = isHG2()
try
tf = ~verLessThan('MATLAB', '8.4');
catch
tf = false;
end
end
function P = InterX(L1,varargin)
% DOCUMENTATION REMOVED. For a full version go to:
% https://www.mathworks.com/matlabcentral/fileexchange/22441-curve-intersections
narginchk(1,2);
if nargin == 1
L2 = L1; hF = #lt; %...Avoid the inclusion of common points
else
L2 = varargin{1}; hF = #le;
end
%...Preliminary stuff
x1 = L1(1,:)'; x2 = L2(1,:);
y1 = L1(2,:)'; y2 = L2(2,:);
dx1 = diff(x1); dy1 = diff(y1);
dx2 = diff(x2); dy2 = diff(y2);
%...Determine 'signed distances'
S1 = dx1.*y1(1:end-1) - dy1.*x1(1:end-1);
S2 = dx2.*y2(1:end-1) - dy2.*x2(1:end-1);
C1 = feval(hF,D(bsxfun(#times,dx1,y2)-bsxfun(#times,dy1,x2),S1),0);
C2 = feval(hF,D((bsxfun(#times,y1,dx2)-bsxfun(#times,x1,dy2))',S2'),0)';
%...Obtain the segments where an intersection is expected
[i,j] = find(C1 & C2);
if isempty(i), P = zeros(2,0); return; end
%...Transpose and prepare for output
i=i'; dx2=dx2'; dy2=dy2'; S2 = S2';
L = dy2(j).*dx1(i) - dy1(i).*dx2(j);
i = i(L~=0); j=j(L~=0); L=L(L~=0); %...Avoid divisions by 0
%...Solve system of eqs to get the common points
P = unique([dx2(j).*S1(i) - dx1(i).*S2(j), ...
dy2(j).*S1(i) - dy1(i).*S2(j)]./[L L],'rows')';
function u = D(x,y)
u = bsxfun(#minus,x(:,1:end-1),y).*bsxfun(#minus,x(:,2:end),y);
end
end
Result:
Note that in the animation above, the diameter of the circle (and hence the distance between the red points) is 10 and not 5.

Shortest line between boundary points that passes through the centroid of a shape

lesion image
I have an irregularly shaped object in which I have to find the greatest and smallest diameter.
To find the greatest diameter, I extracted the boundary points and found the distances between all the points. I took the maximum distance amongst those distances which gave me my greatest diameter.
boundaries = bwboundaries(binaryImage);
numberOfBoundaries = size(boundaries, 1);
for blobIndex = 1 : numberOfBoundaries
thisBoundary = boundaries{blobIndex};
x = thisBoundary(:, 2); % x = columns.
y = thisBoundary(:, 1); % y = rows.
% Find which two boundary points are farthest from each other.
maxDistance = -inf;
for k = 1 : length(x)
distances = sqrt( (x(k) - x) .^ 2 + (y(k) - y) .^ 2 );
[thisMaxDistance, indexOfMaxDistance] = max(distances);
if thisMaxDistance > maxDistance
maxDistance = thisMaxDistance;
index1 = k;
index2 = indexOfMaxDistance;
end
end
I have attached my image containing the longest diameter.
I also need a line segment that passes through the centroid connecting the two boundary points whose length is shortest. When I try to find the shortest diameter by modifying the above code, to find min(distances), I am getting an error that says:
Error using griddedInterpolant
The coordinates of the input points must be finite values; Inf and NaN are not permitted.
What do I need to do to find the shortest "diameter" (that is, passing through the centroid) of this object?
it's possible to use a polar image like this:
lesion = imread('lesion.jpg');
bw = lesion > 100;
c = regionprops(bw,'Centroid');
c = c.Centroid;
% polar args
t = linspace(0,2*pi,361);
t(end) = [];
r = 0:ceil(sqrt(numel(bw)/4));
[tg,rg] = meshgrid(t,r);
[xg,yg] = pol2cart(tg,rg);
xoff = xg + c(1);
yoff = yg + c(2);
% polar image
pbw = interp2(double(bw),xoff,yoff,'nearest') == 1;
[~,radlen] = min(pbw,[],1);
radlen(radlen == 1) = max(r);
n = numel(radlen);
% add two edges of line to form diameter
diamlen = radlen(1:n/2) + radlen(n/2+1:n);
% find min diameter
[mindiam,tminidx1] = min(diamlen);
tmin = t(tminidx1);
rmin = radlen(tminidx1);
tminidx2 = tminidx1 + n/2;
xx = [xoff(radlen(tminidx1),tminidx1) xoff(radlen(tminidx2),tminidx2)];
yy = [yoff(radlen(tminidx1),tminidx1) yoff(radlen(tminidx2),tminidx2)];
% viz
figure;
subplot(121);
imshow(pbw);
title('polar image');
subplot(122);
imshow(bw);
hold on
plot(c(1),c(2),'or')
plot(xx,yy,'g')
legend('centroid','shortest diameter');
and the output is:

Matlab surf only points, not lines

I have to draw a hipsometric map on a 3D plot. I have two vectors 1x401 (named xLabels and yLabels) which are the geo coordinates, and401x401(namedA`) matrix with the altitude data. To plot the data I use:
surf(xLabels, yLabels,A,'EdgeColor','None','Marker','.');
which leads to something like that:
But i would like to have something like that:
On the second image, only the surface is plotted, while my image looks like pillars.
I tried even make my vectors to 401x401 using meshgrid but it did not have any effect.
Do you have any idea what I should change?
#EDIT
I checked for X and Y data. I quess is too small interval (0.0083), but when i try plot good second of upper plots with same interval it draws correctly.
#EDIT2:
sizeX = 4800;
sizeY = 6000;
pixdegree = 0.0083; % 1 pixel is 0.0083 degree on map
intSize = 2;
lon = 37 + (35/60);
lat = 55+ (45/60);
fDEM = 'E020N90';
fHDR = 'E020N90.HDR';
[startXY, endXY] = calcFirstPixel(lon, lat); %calc borders for my area
f = fopen('E020N90.DEM');
offset = (startXY(1,2)*sizeX*intSize)+(startXY(1,1)*intSize);
fseek(f, offset,0); %seek from curr file pos
x = 0;
A = [];
BB = [];
jump = (intSize*sizeX)-(401*2);
while x<401
row = fread(f, 802);
fseek(f, jump, 0); %jump 2 next row
A = [A row];
x = x+1;
end
fclose(f);
A = A';
A = A(:,2:2:802);
m1 = min(A(:)); %wartość minimalna dla naszej podziałki
m2 = max(A(:)); %wartość maksymalna dla naszej podziałki
step = m2/8; % będzie 8 kolorów
highScale = m1:step:m2-step; %wartości graniczne dla każdego z nich
%handles.axes1 = A;
colormap(hObject, jet(8));
startXtick = 20 + pixdegree*startXY(1,1);
endXtick = 20 + pixdegree*endXY(1,1);
startYtick = 90 - pixdegree*endXY(1,2);
endYtick = 90 - pixdegree*startXY(1,2);
[XX,YY] = ndgrid(startXtick:pixdegree:endXtick,startYtick:pixdegree:endYtick);
xLabels = startXtick:pixdegree:endXtick;
yLabels = startYtick:pixdegree:endYtick;
surf(xLabels, yLabels,A,'EdgeColor','None','Marker','.');
set(gca,'YDir','normal');
grid on;
view([45 45])
And .DEM files
function [startXY, endXY] = calcFirstPixel(lon,lat)
global fHDR;
format = '%s %s';
f = fopen(fHDR);
cont = textscan(f, format);
LonStart = str2double(cont{1,2}{11,1});
LatStart = str2double(cont{1,2}{12,1});
diffPerPix = str2double(cont{1,2}{13,1});
fclose(f);
x = LonStart;
countX = 0
y = LatStart;
countY= 0;
while x<lon
x=x+diffPerPix
countX = countX +1;
end
while y>lat
y=y-diffPerPix
countY = countY+1;
end
startXY= [countX-200 countY-200];
endXY = [countX+200 countY+200];
end