Related
I wish to generate a .gif file of a sphere that grows in size(radius) over time based on a specified function relating radius and time. I'm having some trouble with how to formulate the animation.
Here is what I have so far:
%% Parameters
dt = 0.05;
time = 0:dt:1;
radius = 1
%% generate sphere
[X, Y, Z] = sphere(25);
X=X*radius;
Y=Y*radius;
Z=Z*radius;
mySphere = surf(X,Y,Z, 'FaceLighting','gouraud');
axis equal
shading interp
mySphere.FaceAlpha = 0.3
view([61 15])
colormap bone
hold on
%% generate gif
filename = 'Sizechange.gif';
for n = 1:20
radius = 1 + time(n)
im = frame2im(getframe(1));
[imind,cm] = rgb2ind(im,256);
if n == 1;
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',dt);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',dt);
end
end
Here I am trying to get it to go from radius 1 to radius 2 in steps of 0.05.
When I run this however, the gif stays still at 1 and there is no animation.
Any help would be greatly appreciated.
As #cris-luengo said, you should redraw your sphere for each iteration on the radius.
%% Parameters
dt = 0.05;
time = 0:dt:1;
radius = 1 ;
%% generate sphere
[X, Y, Z] = sphere(25);
X=X*radius;
Y=Y*radius;
Z=Z*radius;
%figure;
%mySphere = surf(X,Y,Z, 'FaceLighting','gouraud');
% axis equal
% shading interp
% mySphere.FaceAlpha = 0.3;
% view([61 15])
% colormap bone
% hold on
%% generate gif
filename = 'Sizechange.gif';
figure;
for n = 1:20
radius = 1+ time(n);
%====================================================
X=X*radius;
Y=Y*radius;
Z=Z*radius;
mySphere = surf(X,Y,Z, 'FaceLighting','gouraud');
axis equal
shading interp
mySphere.FaceAlpha = 0.3;
view([61 15])
colormap bone
%====================================================
im = frame2im(getframe(1));
[imind,cm] = rgb2ind(im,256);
if n == 1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',dt);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',dt);
end
end
This is the main code
%%%%%%%%%%%% Valori pentru Rcsc
%%%%Pozitiile si vitezele pe cele 3 axe
y0(1,1)= 743322.3616 ;
y0(2,1)= -6346021.219 ;
y0(3,1)= -3394131.349 ;
y0(4,1)= 5142.38067;
y0(5,1)= 4487.44895 ;
y0(6,1)= -7264.00872;
%%%% Timpul
tspan=[0 :864];
%%%% Masa(kg) si aria suprafetei satelitului (m^2)
m = 217 ; %320;
A = 1.2; %8;
%%%% Metoda Runge-Kutta de ordin 4
h=1;
y = zeros(6, tspan(end)/h);
y(:,1) = y0;
for i=1:(tspan(end)/h)
H=sqrt(y(1,i)^2+y(2,i)^2+y(3,i)^2);
k_1 = proiectia(tspan(i), y(:,i), H, m, A, y(4:6, i));
k1=double(k_1);
k_2 = proiectia(tspan(i)+0.5*h, y(:,i)+0.5*h*k_1, H, m, A, y(4:6, i));
k2=double(k_2);
k_3 = proiectia((tspan(i)+0.5*h), (y(:,i)+0.5*h*k_2), H, m, A, y(4:6, i));
k3=double(k_3);
k_4 = proiectia((tspan(i)+h),(y(:,i)+k_3*h), H, m, A, y(4:6, i));
k4=double(k_4);
y(:,i+1) = double(y(:,i) + (1/6)*(k1+2*k2+2*k3+k4)*h);
end
%%% Distanta satelitului
Rcsc = ((y(1,:).^2 + y(2,:).^2 + y(3,:).^2).^0.5);
n=50;
%plot(tspan,Rcsc)
%% Textured 3D Earth example
%
% Ryan Gray
% 8 Sep 2004
% Revised 9 March 2006, 31 Jan 2006, 16 Oct 2013
%% Options
space_color = 'k';
npanels = 180; % Number of globe panels around the equator deg/panel = 360/npanels
alpha = 1; % globe transparency level, 1 = opaque, through 0 = invisible
GMST0 = []; % Don't set up rotatable globe (ECEF)
%GMST0 = 4.89496121282306; % Set up a rotatable globe at J2000.0
% Earth texture image
% Anything imread() will handle, but needs to be a 2:1 unprojected globe
% image.
image_file = 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Land_ocean_ice_2048.jpg/1024px-Land_ocean_ice_2048.jpg';
% Mean spherical earth
erad = 6371008.7714; % equatorial radius (meters)
prad = 6371008.7714; % polar radius (meters)
erot = 7.2921158553e-5; % earth rotation rate (radians/sec)
%% Create figure
figure('Color', space_color);
hold on;
orbit=animatedline;
addpoints(orbit,y(1,:),y(2,:),y(3,:));
drawnow
% Turn off the normal axes
set(gca, 'NextPlot','add', 'Visible','off');
axis equal;
axis auto;
% Set initial view
view(0,30);
axis vis3d;
%% Create wireframe globe
% Create a 3D meshgrid of the sphere points using the ellipsoid function
[x, y, z] = ellipsoid(0, 0, 0, erad, erad, prad, npanels);
globe = surf(x, y, -z, 'FaceColor', 'none', 'EdgeColor', 0.5*[1 1 1]);
%% Texturemap the globe
% Load Earth image for texture map
cdata = imread(image_file);
% Set image as color data (cdata) property, and set face color to indicate
% a texturemap, which Matlab expects to be in cdata. Turn off the mesh edges.
set(globe, 'FaceColor', 'texturemap', 'CData', cdata, 'FaceAlpha', alpha, 'EdgeColor', 'none');
What I wanna do is that when I run the script a figure with the Earth should appear, and while the positions are being caluclated by the runge kutta algorithm it should upload the orbit in real time. But now the figure appears only after the Rk algorithm is being calculated till the end of tspan and the orbit from the figure is already uploaded without intermediate points. What should I do? I've seen on github that others use animatedline and drawnow.
I was thinking about
orbit=animatedline;
addpoints(orbit,y(1,:),y(2,:),y(3,:));
drawnow
end
But where should I put this line exactly? if I put it in the rk loop it doesn't work and if I put it
% Create figure
figure('Color', space_color);
%%
orbit=animatedline;
addpoints(orbit,y(1,:),y(2,:),y(3,:));
drawnow
it first displays a figure with the orbit but not by intermediate points and then a different figure with the Earth ,while the orbit and the Earth should be in the same figure.
You are using animatedline in a wrong way.
The line:
orbit = animatedline;
should be placed before the loop that calculates the points, and the lines:
addpoints(orbit,y(1,i),y(2,i),y(3,i));
drawnow
should be placed within it, to add one (or several) points to the line on each iteration. But, a better approach, would be to first calculate all the orbit and then use a loop for the animation. This way you have more control over the rate of the animation. Here is a small example using your case:
orbit = animatedline;
for k = 1:size(y,2)
addpoints(orbit,y(1,k),y(2,k),y(3,k));
drawnow
end
Alternative option
Don't use animated line just keep updating the data in the plot. Here is a simple workout for this:
% create a sphere with earth map on it:
set(gcf,'Color','k')
earth = imread('earth.jpg');
[X,Y,Z] = sphere(50);
warp(-X,Y,-Z,earth)
axis off
view(-46,17)
% set an animation of a simple orbit:
Nframes = 100; % number of steps in the orbit
% calculation of the orbit:
orb = linspace(-pi,pi,Nframes);
x = cos(orb).*1.5;
y = sin(orb);
hold on
% plot the whole orbit invisible, just for setting the axes limits:
tmp = plot(x,y,'Color','none');
p = plot(x(1),y(1),'LineWidth',3,'Color','m'); % plot the first step
hold off
for k = 1:numel(orb)
p.XData = x(1:k); % update the data of the plot
p.YData = y(1:k);
pause(0.05) % delay
end
The result:
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
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
I am trying to use either the contourf or colormap functions to plot filled ellipses with colors according to their arcsin(b/a) value (a=major axis, b=minor axis).
clearvars -except data colheaders
close all
clc
data(:,9)=data(:,9)*pi/180; % Convers Column 9 (angle of rotation) in rad
data(:,6)=1196-data(:,6); % Reset the Y coordinate axis to bottom left
theta = 0 : 0.01 : 2*pi; % Converts phi in rad
imax=29;
% Define colors
cvalues=asin(data(1:imax,8)./data(1:imax,7))./asin(1);
cm = colormap; % returns the current color map
% Sort and get their index to access the color array
[~,idx] = sort(cvalues);
% Create colormap
%ColorMap=jet;
for i=1:imax
x = data(i,7)/2 * cos(theta) * cos(data(i,9)) - data(i,8)/2 * sin(theta) * sin(data(i,9)) + data(i,5);
y = data(i,8)/2 * sin(theta) * cos(data(i,9)) + data(i,7)/2 * cos(theta) * sin(data(i,9)) + data(i,6);
colorID = max(1, sum(cvalues(i) > [0:1/length(cm(:,1)):1]));
ColorMap(i,:) = cm(colorID, :); % 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
%% TRYING A FASTER WAY OF PLOTTING
%A(:,i)=x';
%B(:,i)=y';
%%
fill(x,y,ColorMap(i,:),'EdgeColor', 'None')
text(data(i,5),data(i,6),[num2str(asin(1)*180*cvalues(i)/pi)]) % Assigns number to each ellipse
end
%%
%fill(A,B,ColorMap(1:200,3)','EdgeColor', 'None')
%%
% Adds colorbar to plot
colorbar('SouthOutside')
caxis([0 90])
axis equal;
%xlim([0 7649]);
%ylim([0 15927]);
grid on;
I get a picture that looks like this which I think works well:
Instead of adding numbers in the ellipses, I have added the angle I obtained (90 for circles, 0 for very long ellipse). Now is my real experiment i will have to plot several thousands ellipses, and we found out that it takes quite alot of time to plot them, you'll see we tried another method to basically record the data and plot all in one go. But we haven't succeeded so far if you have any advice :)
Here is a way using built-in colormaps in Matlab (look here for a complete list).
The trick is to create a n x 3 array where n is the number of colors you wish to represent. Here it's the number of ellipses.
You can create a colormap like so:
MyColorMap = jet(n)); %// jet or anything listed in the link above. You can also create your own colormap.
So that's what we're going to do in the following code. In order to get the order right, we need to sort the values of asin(b/a) and fetch each index for the right ellipse. The code is commented so it's quite easy to follow. I added 4 ellipses in the plot to see the difference in color better:
clear
clc
close all
%// Define dummy data
data = zeros(8,9);
data(:,5) = [3;5;12;8;2;7;4;6]; % Centre location X
data(:,6) = [1; -5 ;-2; 4;2;-3;9;5]; % Centre location Y
data(:,7) = [6 ;7;8;6;1;4;2;5]; % Major Axis a
data(:,8) = [2;5;4;2;2;5;3;7]; % Minor axis b
data(:,9) = [10;40;45;90;35;70;85;110]; % Angle of rotation phi
data(:,9)=data(:,9)*pi/180; % Converts phi in rads
theta = 0 : 0.01 : 2*pi;
%// Define colors here
cvalues = asin(data(:,8)./data(:,7));
%// Sort and get their index to access the color array
[~,idx] = sort(cvalues);
%// Create colormap with the "jet" colors
ColorMap = jet(numel(cvalues));
This is the array containing the "colors". It looks like this:
ColorMap =
0 0 1
0 0.5 1
0 1 1
0.5 1 0.5
1 1 0
1 0.5 0
1 0 0
0.5 0 0
So each row represents a combination of red, blue and green (RGB) and there are as many rows as there are ellipses to plot. Now filling the ellipses:
hold all
for i=1:numel(idx)
k = idx(i);
x = data(k,8)/2 * cos(theta) * cos(data(k,9)) - data(k,7)/2 * sin(theta) * sin(data(k,9)) + data(k,5);
y = data(k,7)/2 * sin(theta) * cos(data(k,9)) + data(k,8)/2 * cos(theta) * sin(data(k,9)) + data(k,6);
fill(x,y,ColorMap(i,:))
plot(x, y, 'LineWidth', 1);
% Label each ellipse with a number
text(data(i,5),data(i,6),num2str(i),'Color','k','FontSize',12)
end
axis equal;
grid on;
Output with the jet colormap: blue is the first ellipse plotted and red is the last. You can add a colorbar if you want (add colorbar)
Using another colormap, the bone colormap, gives the following:
Hope that helps!