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
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
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.
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.
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:
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