I am trying to plot 5 subplots in a for loop, each iteration of which varies with x (1 to 5). However, I would also like to change the range of R for each iteration so that it is equal to 6*x:100 - so when x=1, R=6:100; when x=2, R=12:100; when x=3, R=18:100; and so on...
I've been trying to figure out how to do this for days, so help would be much appreciated.
% constants
de = 20;
b = 0.5;
% parameters
x = 1:1:5;
R = 6.*x:100;
S = 0:1:250;
[R,S]=meshgrid(R,S);
% function
k1=#(x)((factorial(R)).*exp(b.*(x.*(de))));
k2=#(x)((S.^(6.*x)).*(factorial(R-6.*x)));
kk=#(x)(k1(x)./(k1(x)+k2(x)));
figure
for i=x
subplot(3,2,i)
mesh(R,S,kk(i))
end
I modified a bit your code,without anonymous functions and inserting everything within the for loop, I hope its the answer you are looking for. for a clear visualization I linked your rotation axis, so youll allways look to the same angle in each of the 5 subplots.
% constants
de = 20;
b = 0.5;
% parameters
S = 0:1:250;
figure
for x=1:5
R = 6.*x:100;
[Rk,Sk]=meshgrid(R,S);
k1=((factorial(Rk)).*exp(b.*(x.*(de))));
k2=((Sk.^(6.*x)).*(factorial(Rk-6.*x)));
kk=(k1./(k1+k2));
h(x)=subplot(3,2,x)
mesh(Rk,Sk,kk)
end
linkprop(h, 'CameraPosition');
Result:
Related
I am attemping to plot a series of points on one single graph:
Klnvalue = [-1.516 -0.609 0.202 0.934 2.486 3.725 4.743 5.590];
temp = [3400 3600 3800 4000 4500 5000 5500 6000];
for i = 1:8
eqn = ((nh^2)/(1-nh))*68.045964 == exp(Klnvalue(i));
y = max(vpa(solve(eqn, nh)))
x = temp(i);
figure
plot(x,y)
hold on
end
But not only does eight graphs jumped out, not a single point is plotted, could you tell me why?
If you only want 1 graph, pass something like figure(1). Also, take figure out of the loop and instead do:
figure(1), clf, hold on
for i = 1:8
eqn = ((nh^2)/(1-nh))*68.045964 == exp(Klnvalue(i));
y = max(vpa(solve(eqn, nh)))
x = temp(i);
plot(x,y)
end
Otherwise you waste time calling the figure each time even when it is still the current figure. Good luck!
I need to plot multiple graphs in the same y-axis, but the x-axis is a bit tricky for me:
Assuming it goes from 0 to a, increasing by one, it needs to have an overall of a-1 different intervals.
Each one of them should finish at a, but it also has to have a different initialisation point. Only the first starts at 0, while each next one, starts by the previous plus one, as in the shape below. The two dashed lines, I used to visualise my thoughts as clear as I could, are not necessary.
I would appreciate any help!
Replicate your original interval 0 ... a a times (from my understanding, you'll have a intervals, not a-1), such that you get a matrix X of size [a x a+1]. Set the lower left triangle of X to NaN, so that the rows now represent your (shortening) intervals. Do your calculations on X. Pay attention, these have to support/neglect NaN values properly.
After that, you need to adjust the values in X properly, so that the intervals are plotted subsequently. Basically, we add some fixed value to each row.
Last, we need the proper xticks and xticklabels. Therefore, we extract all values from X and the modified X and get rid of the NaN values.
Here's a complete code snippet:
% Parameter
a = 7;
% Initialize intervals
X = repmat(0:a, a, 1);
X = X .* (ones(size(X)) + tril(nan(size(X)), -1));
% Calculation on these intervals; attention: there are NaN in X
Y = sin(X / a * 2 * pi);
% Modify X for plotting
X_plot = X;
X_plot(2:end, :) = X_plot(2:end, :) + cumsum(a:-1:2).';
% Get xticks
xt = X_plot.';
xt = xt(:);
xt(isnan(xt)) = [];
% Get xticklabels
xtl = X.';
xtl = xtl(:);
xtl(isnan(xtl)) = [];
% Plot
plot(X_plot.', Y.');
xticks(xt);
xticklabels(xtl);
The output (Octave 5.1.0, also tested with MATLAB Online) looks like this:
If you only want for example the start and end of each interval, you must further pre-process xt and xtl.
Hope that helps!
I am trying to draw a curve where each points are specific distance away from each other.
Now, blow shows pretty much what I wanted to do but I want sin like curve and not constant radius.
R = 50; %radius
Gap = 0.1; % gap between points
Curve = 180;
rad = 0;
n= pi*2*R*Curve/360/Gap; % n is length of arc
th = linspace( pi, rad ,n);
x = R*cos(th)+R;
y = R*sin(th)+100;
PathDB.Route1.x(1:1001,1)=0;
PathDB.Route1.y = (0:Gap:100)';
LengthY = length(PathDB.Route1.y);
PathDB.Route1.x(1001:1001+length(x)-1,1)=x ;
PathDB.Route1.y(LengthY:LengthY+length(y)-1) = y;
LengthX = length(PathDB.Route1.x);
LengthY = length(PathDB.Route1.y);
PathDB.Route1.x(LengthX:LengthX+1000,1)=PathDB.Route1.x(LengthX,1);
PathDB.Route1.y(LengthY:LengthY+1000,1)= (PathDB.Route1.y(LengthY,1):-Gap:0);
plot(PathDB.Route1.x, PathDB.Route1.y);
grid ;
axis equal
All I want to do is instead of perfect curve, I want to add sin like curve which are plotted by 0.1.
I'm sorry about my poor coding skills I hope you can understand and help me.
Any advice is appreciated!
Rui
If you want this to be robust, you'll probably need to use the Matlab Symbolic Toolbox. If you take a function f, and want to plot equidistant points along it's curve between a and b, you could do something like this (using sin(x) as the example function):
sym x;
f = sin(x);
g = diff(f); %derivative of f
b=5;
a=0;
%check syntax on this part
arc_length = int(sqrt(1+g^2)); %create function for arc_length
Sc = arc_length(b)-arc_length(a); %calculate total arc length
n = 30 %number of points to plot (not including b)
Sdist = Sc/n; %distance between points
xvals = zeros(1,(n+1)); %initialize array of x values, n+1 to include point at b
Next, we will want to iterate through the intervals to find equidistant points. To do this we take each S_ij where i represents the x value of the low end of the interval and j represents the high end. We start with i=a and stop when i=b. Using the inverse of our arc length equation we can solve for j. Sdist == S_ij => Sdist = arc_length(j) - arc_length(i) => Sdist+arc_length(i)=arc_length(j). Using this, we can compute: j = arc_length_inverse(Sdist+arc_length(i)). One way of implementing this would be as follows:
arc_length_inv = finverse(arc_length);
i=a
xvals(1)=i;
for ii=1:n
j = arc_length_inv(Sdist+arc_length(i)); %calculate high end
i = j %make high end new low end
xvals(ii+1)=i; %put new low end value in x array
end
With this array of x values, you can compute yvals=sin(xvals) and plot(xvals,yvals)
Some of this code probably needs tweaking but the math should be sound (the formula for arc length came from http://en.wikipedia.org/wiki/Arc_length). Mathematically, this should work for any function integrable on [a,b] and whose arc_length function has an inverse; that said, I do not know the capabilities of the int() and finverse() functions.
If you do not need robustness you can follow these steps for your specific function, doing the math by hand and entering the functions manually;
Hi i'm having a problem where I have a dataset which ranges between -10^3 to 10^3
I need to be able to plot this as with a log scale but semilogy cannot plot negative values
Say for example my data is:
x = [-3,-2,-1,0,1,2,3];
y = [-1000,-100,-10,1,10,100,1000];
(or in general y=sign(x).*10.^abs(x);)
How can I plot this in MATLAB with a log scale? If possible It would be great if the log scale ticks could be on the Y-axis too
Use your actual data as labels, but scale the plotted data with log10.
% data
x = -3:0.1:3;
y = sign(x).*10.^abs(x);
% scaling function
scale = #(x) sign(x).*log10(abs(x));
N = 7; % number of ticks desired
% picking of adequate values for the labels
TickMask = linspace(1,numel(y),N);
YTickLabels = y(TickMask);
% scale labels and plotdata, remove NaN ->inconsistency, do you really want that?
YTick = scale( YTickLabels );
Y = scale(y);
YTick(isnan(YTick)) = 0;
Y(isnan(Y)) = 0;
% plot
plot(x,Y)
set(gca,'YTick',YTick,'YTickLabels',YTickLabels)
grid on
For N = 7:
For N = 11
How to find a valid value for N?
The following function (thanks to gnovice) will return all possible values you could choose for N:
n = numel(x);
N = find(rem(n./(1:n), 1) == 0) + 1;
about the semilogy-style labels: by adding the following line before the plot:
YTickLabels = cellfun(#(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)
you could at least achieve something like this:
not beautiful and not generic, but a good point to start for you.
The reason you can't make a logarithmic axis that crosses zero, is that it doesn't make sense!
Since a logarithmic scale is generally displayed as eg. 100 - 10 - 1 - 1/10 - 1/100 - ..., you would need an infinite amount of space to make the axis cross zero.
How about this:
x=logspace(-3,3);
y=sign(x).*10.^abs(x);
loglog(x,y)
#thewaywewalk has already given a beautiful solution to it. The one I'm suggesting is an epsilon improvement on it. If you make two changes
(a) Define a new MATLAB function signia that basically extracts the sign before a number.
function value = signia(x)
if(x>=0)
value = '';
else
value = '-';
end
and (b) make this little change that instead of
YTickLabels = cellfun(#(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)
you use
YTickLabels = cellfun(#(x) [signia(x) '10^{' num2str(x) '}'], num2cell(YTick),'UniformOutput',false);
(notice the presence of curly braces), you'll get an improvement in the Y ticks display. I got the following.
enter image description here
I've written this code which makes an animation of 2 ellipsoids. Parameter k1 of these ellipsoids must depend on time (so they'd move asynchronously), but I need to animate them in one figure. Can I use loop for it or is it better to use timer & some kind of callback functions? The second problem - I need to move inner ellipsoid so they would have one common side. How can I do this?
You should use a loop. The majority of your time will be spent plotting and with the "getFrame" command. You can use profile to verfiy this. The for loop won't add significant overhead and is easiest to code and understand
As for your second question, I'm not sure exactly what you're asking, but if you want to keep a point in common, you should parametrize your surface in terms of the radii, skew angle, etc. and the common point, then just move the point around. You might want to consider writing a "drawEllipsoid" function, which would simplify and clarify your code.
The loop seems fine for this job. A timer would work as well.
I'm not sure quite what you mean when you say "have one common side". It looks like you're close with adding 5 to X2, but you would need a scaling term since they're not the same shape. Could you elaborate?
One suggestion though. I think that you'll be a lot happier if you move the object creation out of the loop like this:
a=5;
b=a;
c=10;
u = (0:0.05*pi:2*pi)'; %'
v = [0:0.05*pi:2*pi];
X = a*sin(u)*cos(v);
Y = a*sin(u)*sin(v);
Z = c*cos(u)*ones(size(v));
Z(Z>0)=0; % cut upper
V1=4/3*pi*a*b*c;
d=1/2;
e=2^d;
a2=a/e;
b2=a/e;
c2=c;
V2=4/3*pi*a2*b2*c2;
X2 = a2*sin(u)*cos(v);%-2.5;
Y2 = b2*sin(u)*sin(v);
Z2 = c2*cos(u)*ones(size(v));%+0.25;
Z2(Z2>0)=0; % cut
h=1/3;
hS1=surf(X,Y,Z);
alpha(.11)
hold on
hS2=surf(X2,Y2,Z2);
hold off
axis([-20 20 -20 20 -20 20]);
for j = 1:20
k1=(sin(pi*j/20)+0.5)^h;
a=a*k1;
c=c*k1;
X = a*sin(u)*cos(v);
Y = a*sin(u)*sin(v);
Z = c*cos(u)*ones(size(v));
Z(Z>0)=0;
a2=a2*k1;
b2=a2*k1;
c2=c2*k1;
X2 = a2*sin(u)*cos(v)+5;%-2.5;
Y2 = b2*sin(u)*sin(v);
Z2 = c2*cos(u)*ones(size(v));%+0.25;
Z2(Z2>0)=0;
set(hS1,'XData',X,'YData',Y,'ZData',Z);
set(hS2,'XData',X2,'YData',Y2,'ZData',Z2);
drawnow;
F(j) = getframe;
end
movie(F,4)
The drawnow is not strictly necessary here because the getframe contains one, but it is good to insert one so that you can see what's going on if you remove the getframe.
OK, here's the shortcut to doing a trimmed surface I mentioned in my earlier comment. What you're going to do is put NaNs into the coordinates everywhere the surface is outside the domain. Then the surface object will drop any quads which touch those coordinates. That doesn't give you a nice clean edge, but it is really easy.
a=5;
b=a;
c=10;
u = (0:0.05*pi:pi)'; %'
v = [0:0.05*pi:2*pi];
X = a*sin(u)*cos(v);
Y = a*sin(u)*sin(v);
Z = c*cos(u)*ones(size(v));
Z(Z>0)=0; % cut upper
V1=4/3*pi*a*b*c;
d=1/2;
e=2^d;
a2=a/e;
b2=a/e;
c2=c;
V2=4/3*pi*a2*b2*c2;
X2 = a2*sin(u)*cos(v);%-2.5;
Y2 = b2*sin(u)*sin(v);
Z2 = c2*cos(u)*ones(size(v));%+0.25;
Z2(Z2>0)=0; % cut
h=1/3;
hS1=surf(X,Y,Z);
alpha(.11)
hold on
hS2=surf(X2,Y2,Z2);
hold off
axis([-20 20 -20 20 -20 20]);
for j = 1:20
k1=(sin(pi*j/20)+0.5)^h;
a=a*k1;
c=c*k1;
X = a*sin(u)*cos(v);
Y = a*sin(u)*sin(v);
Z = c*cos(u)*ones(size(v));
Z(Z>0)=0;
a2=a2*k1;
b2=a2*k1;
c2=c2*k1;
X2 = a2*sin(u)*cos(v)+5;%-2.5;
Y2 = b2*sin(u)*sin(v);
Z2 = c2*cos(u)*ones(size(v));%+0.25;
Z2(Z2>0)=0;
set(hS1,'XData',X,'YData',Y,'ZData',Z);
% substitute into implicit form of 1st ellipsoid
d = (X2.^2) / a^2 + (Y2.^2) / a^2 + (Z2.^2) / c^2;
% and zap any that are outside [0 1]
X2(d>1) = nan;
Y2(d>1) = nan;
Z2(d>1) = nan;
set(hS2,'XData',X2,'YData',Y2,'ZData',Z2);
drawnow;
F(j) = getframe;
end
movie(F,4)
Note that I also changed the range of u. That's because you were actually drawing 2 copies of the surface. That was causing some problems with how the transparency was rendered.