MATLAB - adding plot to another plot after loop, more sophisticatedly - matlab

i have a problem and i hope that i will find help there.
This is my example code. Its only part of my algorithm. For imagine, how the point are moving, during the equations, i need show contour of function with two variables and into the points. Becase i have more difficult function than parabolic function, so the equations are too long than i need. For this reason i move contour ploting before the loop. But i have problem. I need show countour always and points only for i-loop and my solution doesnt work. Please help me!
[R S] = meshgrid(-5:0.1:5, -5:0.1:5);
figure
contour(R, S, R.^2 + S.^2, 5);
axis([-5,5,-5,5])
axis square
hold on
for i=1:50
a = 0;
b = 1:2
B = repmat(b,5,1)
A = unifrnd(a,B)
x = A(1:5,1);
y = A(1:5,2);
scatter(x,y,'fill')
hold off
pause(0.5)
end

You should store the handle to your scatter plot and simply update the XData and YData properties of it rather than destroying the plot objects every time
[R S] = meshgrid(-5:0.1:5, -5:0.1:5);
figure
contour(R, S, R.^2 + S.^2, 5);
axis([-5,5,-5,5])
axis square
hold on
% Create a scatter plot and store the graphics handle so we can update later
hscatter = scatter(NaN, NaN, 'fill');
for i=1:50
a = 0;
b = 1:2
B = repmat(b,5,1)
A = unifrnd(a,B)
x = A(1:5,1);
y = A(1:5,2);
% Update the X and Y positions of the scatter plot
set(hscatter, 'XData', x, 'YData', y);
pause(0.5)
end

Related

Empty plot when using for loop

I want to use a for loop to plot a function. The code is
y = 0;
for k = 0:0.1:2
y = y + k;
plot(k, y);
hold on;
end
However, by running the code, the plot window is empty! How can I fix that in order to see a line on a 2D area?
Matlab automatically plots the linear interpolation between the points that are given to the plot function. Thus as you only give a single point, no interpolation can happen.
What you can do is to save the old y value and the old x value to ask Matlab to plot a linear interpolation between these two points. e.g.
yold = 0; %Init
kold=0; %Init
for k = 0:0.1:2
y = yold + k; %New y value
plot([kold,k], [yold,y]); %Plot a linear interpolation
kold = k; %Save the new values as old
yold = y; %Same
hold on;
end
EDIT/NOTE:
When adding new plots to the same window, MATLAB automatically changes color, thus the above will give you a rainbow, which is nice, but in case you want to keep it professional, you can add a color to the plot command, e.g.
plot([kold,k], [yold,y],'blue');

Speed up creation of impoint objects

I have to create some draggable points on an axes. However, this seems to be a very slow process, on my machine taking a bit more than a second when done like so:
x = rand(100,1);
y = rand(100,1);
tic;
for i = 1:100
h(i) = impoint(gca, x(i), y(i));
end
toc;
Any ideas on speed up would be highly appreciated.
The idea is simply to provide the user with the possibility to correct positions in a figure that have been previously calculated by Matlab, here exemplified by the random numbers.
You can use the the ginput cursor within a while loop to mark all points you want to edit. Afterwards just click outside the axes to leave the loop, move the points and accept with any key.
f = figure(1);
scatter(x,y);
ax = gca;
i = 1;
while 1
[u,v] = ginput(1);
if ~inpolygon(u,v,ax.XLim,ax.YLim); break; end;
[~, ind] = min(hypot(x-u,y-v));
h(i).handle = impoint(gca, x(ind), y(ind));
h(i).index = ind;
i = i + 1;
end
Depending on how you're updating your plot you can gain a general speedup by using functions like clf (clear figure) and cla (clear axes) instead of always opening a new figure window as explained in this answer are may useful.
Alternatively the following is a very rough idea of what I meant in the comments. It throws various errors and I don't have the time to debug it right now. But maybe it helps as a starting point.
1) Conventional plotting of data and activating of datacursormode
x = rand(100,1);
y = rand(100,1);
xlim([0 1]); ylim([0 1])
f = figure(1)
scatter(x,y)
datacursormode on
dcm = datacursormode(f);
set(dcm,'DisplayStyle','datatip','Enable','on','UpdateFcn',#customUpdateFunction)
2) Custom update function evaluating the chosen datatip and creating an impoint
function txt = customUpdateFunction(empt,event_obj)
pos = get(event_obj,'Position');
ax = get(event_obj.Target,'parent');
sc = get(ax,'children');
x = sc.XData;
y = sc.YData;
mask = x == pos(1) & y == pos(2);
x(mask) = NaN;
y(mask) = NaN;
set(sc, 'XData', x, 'YData', y);
set(datacursormode(gcf),'Enable','off')
impoint(ax, pos(1),pos(2));
delete(findall(ax,'Type','hggroup','HandleVisibility','off'));
txt = {};
It works for the, if you'd just want to move one point. Reactivating the datacursormode and setting a second point fails:
Maybe you can find the error.

MATLAB - How to make multiple markers moving simultaneous in 3d plot in MATLAB

I am currently working on a project simulating the movement of two spacecraft and a moon (Phobos) around Mars. A MATLAB tool called SPICE gives me an array with the x, y and z distances and I have used these to plot the orbit which works fine. Now I want to get markers for each of the spacecraft and Phobos to see when they flyby each other. I got the markers working but not at the same time, they run after each other. I found an example on youtube so it must be possible but he has not released the code how to do it (https://www.youtube.com/watch?v=nArR2P0o4r4).
This is the code I have:
a = position_MEX_Mars(1,:);
b = position_MEX_Mars(2,:);
c = position_MEX_Mars(3,:);
k = position_MAVEN_Mars(1,:);
l = position_MAVEN_Mars(2,:);
m = position_MAVEN_Mars(3,:);
x = position_Phobos_Mars(1,:);
y = position_Phobos_Mars(2,:);
z = position_Phobos_Mars(3,:);
ah = axes;
set(ah,'XLim',[min(x) max(x)],'YLim',[min(y) max(y)],...
'ZLim',[min(z) max(z)]);
plot3(0,0,0,'ro-',x,y,z,a,b,c,k,l,m);
grid on;
hold on;
hpoint = line('XData', 0,'YData', 0,'ZData', 0,'Color','black','Marker',...
'o','MarkerSize',10);
ht = hgtransform('parent',ah);
set(hpoint,'Parent',ht);
for i =2:length(x)
trans = makehgtform('translate',[x(i) y(i) z(i)]);
set(ht,'Matrix',trans);
pause(0.001);
end
This will run a nice animated plot of the trajectory of Phobos in time but only Phobos and not simultaneous with MEX and MAVEN (spacecraft from ESA and NASA).
I tried this but does not work:
a = position_MEX_Mars(1,:);
b = position_MEX_Mars(2,:);
c = position_MEX_Mars(3,:);
k = position_MAVEN_Mars(1,:);
l = position_MAVEN_Mars(2,:);
m = position_MAVEN_Mars(3,:);
x = position_Phobos_Mars(1,:);
y = position_Phobos_Mars(2,:);
z = position_Phobos_Mars(3,:);
ah = axes;
set(ah,'XLim',[min(x) max(x)],'YLim',[min(y) max(y)],...
'ZLim',[min(z) max(z)]);
plot3(0,0,0,'ro-',x,y,z,a,b,c,k,l,m);
grid on;
hold on;
hpoint = line('XData', 0,'YData', 0,'ZData', 0,'Color','black','Marker',...
'o','MarkerSize',10);
ht = hgtransform('parent',ah);
set(hpoint,'Parent',ht);
for i =2:length(x)
trans1 = makehgtform('translate',[x(i) y(i) z(i)]);
set(ht,'Matrix',trans1);
trans2 = makehgtform('translate',[a(i) b(i) c(i)]);
set(ht,'Matrix',trans2);
pause(0.001);
end
I also tried merging the arrays so that it plots them each one step after each other but that makes the animation not smooth and is not satisfying for the project.
a = position_MEX_Mars(1,:);
b = position_MEX_Mars(2,:);
c = position_MEX_Mars(3,:);
k = position_MAVEN_Mars(1,:);
l = position_MAVEN_Mars(2,:);
m = position_MAVEN_Mars(3,:);
x = position_Phobos_Mars(1,:);
y = position_Phobos_Mars(2,:);
z = position_Phobos_Mars(3,:);
tempx = [position_MEX_Mars(1,:); position_Phobos_Mars(1,:); position_MAVEN_Mars(1,:)];
xt = tempx(:);
tempy = [position_MEX_Mars(2,:); position_Phobos_Mars(2,:); position_MAVEN_Mars(2,:)];
yt = tempy(:);
tempz = [position_MEX_Mars(3,:); position_Phobos_Mars(3,:); position_MAVEN_Mars(3,:)];
zt = tempz(:);
ah = axes;
set(ah,'XLim',[min(x) max(x)],'YLim',[min(y) max(y)],...
'ZLim',[min(z) max(z)]);
plot3(0,0,0,'ro-',x,y,z,a,b,c,k,l,m);
grid on;
hold on;
hpoint = line('XData', 0,'YData', 0,'ZData', 0,'Color','black','Marker',...
'o','MarkerSize',10);
ht = hgtransform('parent',ah);
set(hpoint,'Parent',ht);
for i =2:length(x)
trans = makehgtform('translate',[xt(i) yt(i) zt(i)]);
set(ht,'Matrix',trans);
pause(0.001);
end
I think I am close but I seem to be missing something and my knowledge of MATLAB is not that great yet. I hope you can help me out.
Cheers Jeroen
Here's a simplified (and not physically correct) example that could perhaps be useful:
t = linspace(0,2,1000); %// time parameter
x1 = 10*cos(2*pi*t+1);
y1 = 5*sin(2*pi*t+1); %// trajectory of object 1
x2 = 2*cos(6*pi*t-2);
y2 = 3*sin(6*pi*t-2); %// trajectory of object 1
plot(x1,y1,'color',[.5 .5 .5]); %// plot trajectory of object 1
hold on
plot(x2,y2,'color',[.5 .5 .5]); %// plot trajectory of object 2
h1 = plot(x1(1),y1(1),'ro'); %// plot initial position of object 1
h2 = plot(x2(1),y2(1),'b*'); %// plot initial position of object 2
axis([-12 12 -12 12]) %// freeze axis size
grid on
for n = 1:numel(t)
set(h1, 'XData', x1(n), 'YData', y1(n)); %// update position of object 2
set(h2, 'XData', x2(n), 'YData', y2(n)); %// update position of object 2
drawnow %// refresh figure
end
The thing that you tries to do is not really as easy as you think. The main issue is that you need to update everything at the same time. This have been implemented in several ways during the years. One way to do this is by using a so called a double buffer.
This means that you have two "surfaces" to paint on. In matlab this is translated to 2 axes (or 2 figures maybe). However, you do only have one axes visible at the same time. This means that you will have time to paint everything on the "hidden surface" before displaying the content. When you are done with everything you need you just switch which surface being visible.
It is possible that this can be done in a simpler way, but I am not familiar with the hgtransfrom functions in matlab.
EDIT
This is an example how it can be done
function test()
fig = figure;
ax1 = axes;
plot(1:10);
ax2 = axes;
plot(1:10,'r');
setVisibility(ax2,'off');
pause(1);
for k = 1:5
setVisibility(ax2,'on');
setVisibility(ax1,'off');
pause(1);
setVisibility(ax1,'on');
setVisibility(ax2,'off');
pause(1);
end
function setVisibility(ax, visibility)
set(ax, 'visible', visibility)
set(findall(ax), 'visible', visibility)

Animating plot with matlab / octave

I'm trying to animate a plot for this equation see below I'm trying to animate it for b when 300>= b <= 486
clear all, clc,clf,tic
m=3.73;
a=480;
b=486;
r=1;
fs=44100;
x=linspace(0,2*pi,fs)';
y=m^3*cos(sqrt(a*r*x)).^(0.77)/r + m^3*cos(sqrt(b*r*x)).^(0.77)/r-20;
normalize_y=(y/max(abs(y))*0.8);
plot(x,y)
I'm using octave 3.8.1 which is a clone of matlab
Put your plotting code in a for loop with b as the iterating variable, then place a pause for a small amount of time. After, plot your graph, then use drawnow to refresh the plot. In other words, try this code. I've placed %// Change comments in your code where I have introduced new lines:
m=3.73;
a=480;
r=1;
fs=44100;
x=linspace(0,2*pi,fs)';
figure;
for b = 300 : 486 %// Change
y=m^3*cos(sqrt(a*r*x)).^(0.77)/r + m^3*cos(sqrt(b*r*x)).^(0.77)/r-20;
normalize_y=(y/max(abs(y))*0.8);
pause(0.1); %// Change
plot(x,y);
title(['b = ' num2str(b)]); %// Change
drawnow; %// Change
end
As a bonus, I've put what the current value of b is at each drawing of the plot. BTW, I don't know why normalize_y is in your code when you aren't using it. Do you mean to plot normalize_y instead of y? Just an after thought. Anyway, try that out and see how it looks. Good luck!
Another solution would be to use the handle of a plot and then only update the 'YData'-property of a plot. That is especially useful for more complex plots where there are more than 1 line but you only want to change one line. Also Axis-labels are not overwritten then, which generally prevents alot of overhead.
In Matlabcode it could look like this:
% // Parameter and x-range
m=3.73;
a=480;
r=1;
fs=44100;
x=linspace(0,2*pi,fs)';
% // function to compute y for given x and parameter b
f = #(x, b) m^3*cos(sqrt(a*r*x)).^(0.77)/r + m^3*cos(sqrt(b*r*x)).^(0.77)/r-20;
% // first plot out of loop (to get plot handle)
figure;
b = 300;
y = f(x, b);
handle = plot(x, y);
xlabel('x') % // only set once
ylabel('y=f(x,b)') % // only set once
title(['b = ' num2str(b)]);
pause(0.1);
% // animate for b = 301 to 86
for b = 301:486 %// Change
set(handle, 'YData', f(x, b)) % set new y-data in plot handle
pause(0.1); %// update plot
title(['b = ' num2str(b)]); %// update title
end
This will work with octave 3.8.1
% // Parameter and x-range
m=3.73;
a=480;
r=1;
fs=44100;
x=linspace(0,2*pi,fs)';
% // function to compute y for given x and parameter b
f = #(x, b) m^3*cos(sqrt(a*r*x)).^(0.77)/r + m^3*cos(sqrt(b*r*x)).^(0.77)/r-20;
% // first plot out of loop (to get plot handle)
figure;
b = 300;
y = f(x, b);
handle = plot(x, y);
xlabel('x') % // only set once
ylabel('y=f(x,b)') % // only set once
title(['b = ' num2str(b)]);
pause(0.1);
% // animate for b = 301 to 86
for b = 301:486 %// Change
%set(handle, 'YData', f(x, b)) % set new y-data in plot handle
%To work with octave 3.8.1 use the line below
set(handle, 'YData', real (f(x, b)))
pause(0.1); %// update plot
title(['b = ' num2str(b)]); %// update title
end

Draw log graph curve on Matlab by clicking?

I'd like to draw a curve on an empty (semilog-y) graph by clicking the points I want it to run through, on the X-Y plane.
Is there a function for this?
edit: I'm trying to do this by obtaining the position of last pointer click -
axis([0 3000 0 1000]);
co=get(gcf, 'CurrentPoint');
It seems to return the cursor position at the time of execution, but it does not change later.
edit2: Here's what works for me. The actual drawing I can do by using the arrays of points collected.
clear
clc
h=plot(0);
grid on;
xlim([0 3000]);
ylim([0 1000]);
datacursormode on;
% Enlarge figure to full screen.
screenSize = get(0,'ScreenSize');
set(gcf, 'units','pixels','outerposition', screenSize);
hold on;
% Print the x,y coordinates - will be in plot coordinates
x=zeros(1,10); y=zeros(1,10);
for p=1:10;
[x(p),y(p)] = ginput(1) ;
% Mark where they clicked with a cross.
plot(x(p),y(p), 'r+', 'MarkerSize', 20, 'LineWidth', 3);
% Print coordinates on the plot.
label = sprintf('(%.1f, %.1f)', x(p), y(p));
text(x(p)+20, y(p), label);
end
Not really, but now there is:
function topLevel
%// parameters
xrange = [0 100];
yrange = [1e-4 1e4];
%// initialize figure, plot
figure, clf, hold on
plot(NaN, NaN);
axis([xrange yrange]);
set(gca, 'YScale', 'log')
t = text(sum(xrange)/2, sum(yrange)/2, ...
'<< Need at least 3 points >>',...
'HorizontalAlignment', 'center');
%// Main loop
xs = []; p = [];
ys = []; P = [];
while true
%// Get new user-input, and collect all of them in a list
[x,y] = ginput(1);
xs = [xs; x]; %#ok<AGROW>
ys = [ys; y]; %#ok<AGROW>
%// Plot the selected points
if ishandle(p)
delete(p); end
p = plot(xs, ys, 'rx');
axis([xrange yrange]);
%// Fit curve through user-injected points
if numel(xs) >= 3
if ishandle(t)
delete(t); end
%// Get parameters of best-fit in a least-squares sense
[A,B,C] = fitExponential(xs,ys);
%// Plot the new curve
xp = linspace(xrange(1), xrange(end), 100);
yp = A + B*exp(C*xp);
if ishandle(P)
delete(P); end
P = plot(xp,yp, 'b');
end
end
%// Fit a model of the form y = A + B·exp(C·x) to data [x,y]
function [A, B, C] = fitExponential(x,y)
options = optimset(...
'maxfunevals', inf);
A = fminsearch(#lsq, 0, options);
[~,B,C] = lsq(A);
function [val, B,C] = lsq(A)
params = [ones(size(x(:))) x(:)] \ log(abs(y-A));
B = exp(params(1));
C = params(2);
val = sum((y - A - B*exp(C*x)).^2);
end
end
end
Note that as always, fitting an exponential curve can be tricky; the square of the difference between model and data is exponentially much greater for higher data values than for lower data values, so there will be a strong bias to fit the higher values better than the lower ones.
I just assumed a simple model and used a simple solution, but this gives a biased curve which might not be "optimal" in the sense that you need it to be. Any decent solution really depends on what you want specifically, and I'll leave that up to you ^_^