drawnow performance/plot speed - matlab

I am life plotting a dataset for creating hysteresis loops. I agreed with the plot speed before but since I added the scatter it got really slow.
The scatter adds a marker to the current plotted datapoint so that if the plot overwrites you can still pursuite the animated line.
Here is my code:
hAL = animatedline; % line handle
hAL.LineStyle='-';
hAL.Color='blue';
% defaults for the marker
hAx=gca; % get the axis handle
sz=10; % size of marker
clr='b'; % color
hS=scatter(hAx,nan,nan,sz,clr); % initial point won't show but creates handle
x = mmatrix(:,2);
y = mmatrix(:,1);
for k = 1:length(x)
addpoints(hAL,x(k),y(k));
set(hS,'xdata',x(k),'ydata',y(k)) % update the marker position
drawnow
end
Do you know of an option to regulate the plot speed?
I tried drawnow limitrate but it's to fast.
Regards jw

Related

Separate initialization and display of plot

What is a proper way to separate the initialization and the display of plots in Matlab? (I mean plots in a wide sense here; could be plot, plot3, scatter etc.) To give a concrete example, I have a pretty complex 3D visualization that uses sphere and mesh to draw a static sphere mesh and then scatter3 to plot a moving trajectory on the sphere. To be able to do this in real time I have implemented some simple optimizations, such as only updating the scatter3 object each frame. But the code is a bit messy, making it hard to add additional features that I want, so I would like improve code separation.
I also feel like it might sometimes be useful to return some kind of plot object from a function without displaying it, for example to combine it with other plots in a nice modular way.
An example of what I have in mind would be something like this:
function frames = spherePlot(solution, options)
% Initialize sphere mesh and scatter objects, configure properties.
...
% Configure axes, maybe figure as well.
...
% Draw sphere.
...
if options.display
% Display figure.
end
for step = 1:solution.length
% Update scatter object, redraw, save frame.
% The frames are saved for use with 'movie' or 'VideoWriter'.
end
end
Each step might also be separated out as a function.
So, what is a neat and proper way to do stuff like this? All documentation seems to assume that one wants to display everything right away.
For example
% some sample data
N = 100;
phi = linspace(-pi, pi, N);
theta = linspace(-pi, pi, N);
f = #(phi, theta) [sin(phi).*cos(theta); sin(phi).*sin(theta); cos(phi)];
data = f(phi, theta);
% init plot
figure(1); clf
plot3(data(1,:), data(2,:), data(3,:)); % plot path, not updated
hold on
p = plot3([0 data(1,1)], [0 data(2,1)], [0 data(3,1)]); % save handle to graphics objects to update
s = scatter3(data(1,1), data(2,1), data(3,1), 'filled');
axis equal
xlabel('x'); ylabel('y'); zlabel('z');
t = title('first frame'); % also store handle for title or labels to update during animation
% now animate the figure
for k = 1:N
p.XData = [0 data(1,k)]; % update line data
p.YData = [0 data(2,k)];
p.ZData = [0 data(3,k)];
s.XData = data(1,k); % update scatter data
s.YData = data(2,k);
s.ZData = data(3,k);
t.String = sprintf('frame %i', k); % update title
drawnow % update figure
end
Basically you can update all values for a graphics handle, in this case 'p' and 's'. If you open the matlab doc for plot or plot3 you will find a link to all properties of that primitive: e.g. Line Properties. Similar documentation pages exist for scatter/imagesc etc.
So the general idea is to first create a figure with the first frame, save the handles to the objects you would like to update (p = plot(...), and then enter a loop in which you update the required property of that graphics object (e.g. p.Color = 'r', or p.XData = ...).

Get currently selected data point from axes in a figure

I have a MATLAB figure with an axes containing a scatter plot.
Every point on this scatter plot has a signal data array associated with it.
I want to take user input as point selection from scatter plot and plot the corresponding signal data in another axes on the same figure.
Combine a global definition of your second axes with an UpdateFcn on the datacursor. See example below, which generates a sine wave based on a random variable selected.
function getSelectedDataPoint()
% create figure
fig = figure;
% make second axes a global to adress in myupdatefcn
global ax2
% define axes
ax1 = axes('parent',fig,'position',[0.05 0.05 0.9 0.4]);
ax2 = axes('parent',fig,'position',[0.05 0.55 0.9 0.4]);
% Random scatter
scatter(ax1,rand(25,1),rand(25,1),25,'filled')
% Set datacursormode to on
dcm_obj = datacursormode(fig);
datacursormode on
% Specify objective function for clock
set(dcm_obj,'UpdateFcn',#myupdatefcn)
% Define objective function
function text = myupdatefcn(~,obj)
text = sprintf('X: %f \n Y: %f',[obj.Position(1),obj.Position(2)]);
% Find corresponding signal
id = find(and(obj.Position(1) == obj.Target.XData,obj.Position(2) ==
obj.Target.YData));
% Do your thing with the signals
x = 0:0.1:100;
y = sin(obj.Target.XData(id)*x);
% plot on second axes
plot(ax2,x,y)
end
end
I am not sure I entirely understand what you want to do, but you might want to use the "Tag" option available for many objects in MATLAB.
Replace line under "Random scatter" by:
% Random scatter
hold(ax1,'on')
scatTag = cell(1,10);
for i = 1:10
scatTag{i} = scatter(ax1,rand(1,1),rand(1,1),25,'filled');
scatTag{i}.Tag = num2str(i);
end
In the data cursor update function, replace the line "id= find(..."
tagname = obj.Target.Tag;
And modify the signal function to point to your target tag, whatever function that is. In my example, you could do this to define the y-values:
y = sin(str2double(tagname)*x);
It will generate another sine wave, based on the tag.
Hope this helps :)

Matlab - refresh 3D volume (slice) with GUI

I would like to refresh my figure (3D, obtained with the matlab slice command) using a slider (GUI) to update the slice position.
Here is my code to create the figure (it works):
% Create figure
Fig_3dview = figure;
Fig_3dview.Name= 'Microstructure viewer';
% hold on;
% The data to be displayed are within "Volume", a n*m*k matrix
Domain_size = size(Volume)
% Initial position of the slices
% Basically, the 6 faces of the volume
xslice = [1,Domain_size(1)];
yslice = [1,Domain_size(2)];
zslice = [1,Domain_size(3)];
% Display all the slices
imslice = slice(Volume,xslice,yslice,zslice,'parent',Fig_3dview);
% Remove voxel edge
set(imslice,'edgecolor','none')
% Current axis label
ax_3d_slice = gca;
% Set axis equal and tight
axis equal tight
hold off;
The code for the GUI, to control the slice position (it doesn't work):
% Create GUI figure
Fig_3dview_GUI = figure;
Fig_3dview_GUI.Name= 'Microstructure viewer 3D GUI';
% Create slider
h_slice1 = uicontrol('Style','slider','BackgroundColor','w',...
'Unit','pixels','Position',[10,200,250,50],'Parent',Fig_3dview_GUI,...
'Callback',{#slider_slice1_Callback});
% Define function associated with h_slice1
function slider_slice1_Callback(source,eventdata)
% Determine the selected data set.
pos_normalized = source.Value;
position_slice_1= round(pos_normalized*Domain_size(1)); % Get closest integer value
position_slice_1=max(1,position_slice_1); % 0 must be avoided
% Update figure
And here I don't know how to update the figure Fig_3dview with the new position for the slice normal to the first direction.
I would like the new figure looks like:
xslice = [position_slice_1,Domain_size(1)];
imslice = slice(Volume,xslice,yslice,zslice,'parent',Fig_3dview);
I do not want to close the figure and regenerate it, I want to refresh it, so that I get a smooth visualization.
% Update figure
end
Thanks for any advice.
François

How to animate points on an image in MATLAB?

I have the pixel locations of P points on a -constant- image, for T iterations of an algorithm, so locations = [T x 2*P] double.
Now I want to create an animation where it plots the image, then plots the points, pauses for N seconds and updates their location to the next step. I don't know if there is a standard way to follow. I think I need something like:
figure;
imshow(img);
hold on;
for t=1:T
anim = updatePlot(locations(t,:), anim); % ?
end
How can I implement this updatePlot function?
Thanks for any help!
You can do this a couple of different ways. The first way would be to give the plotted points a handle so that you can delete them before the next iteration:
figure
imshow(img);
hold on;
for t = 1:T
% delete the previous points plotted (skip t = 1 since they won't exist)
if t > 1
delete(hPoints);
end
hPoints = plot(xLocations(t,:),yLocations(t,:),'.');
getframe;
pause(N);
end
(I am not exactly sure how you parse your locations along each row to separate the x and y components, so I've just used xLocations and yLocations to represent those values.)
The second way would be to re-draw the entire image at each iteration:
figure
for t = 1:T
clf;
imshow(img);
hold on;
plot(xLocations(t,:),yLocations(t,:),'.');
getframe;
pause(N);
end
Note that imshow might have its own getframe effect so that you'll see the image flicker before plotting the points -- if that happens just switch from imshow to image.

How do I reach first and second plots from bode()

I know how to create the Bode plots with bode() function. If I want to overlap two or more systems frequency responses, I use
bode(sys1,sys2,...)
or
hold on
When I want to reach the plot in order to put a legend with text(), for instance, is easy to reach the second plot. Something like the figure pointer always returns to the second plot (phase graph).
i.e., if try these lines:
G = tf([1],[1 6]); figure(1); bode(G); text(10,-20,'text');
G = tf([1],[1 6]); figure(2); bode(G); text(10,-20,'text');
when I return to the first figure, with figure(1), and try
figure(1); text(10,-20,'text')
legend is displayed in the second plot (Phase plot)
I try these other lines:
P = bodeoptions; % Set phase visiblity to off
P.PhaseVisible = 'off';
G = tf([1],[1 6]);
figure(1); bode(G,P); text(10,-20,'text');
figure(1); text(10,-20,'text');
As you can see, even I turn off the phase plot visiblity, the legend is not displayed.
Essentialy, my question is, how do I reach first and second plots, one by one? I tried with subplot(), but it is pretty clear this is not the way Matlab traces these plots.
Thanks in advance.
It all comes to getting into upper plot, since after bodeplot command the lower one is active. Intuitively one would want to call subplot(2,1,1), but this just creates new blank plot on top of if. Therefore we should do something like this:
% First, define arbitrary transfer function G(s), domain ww
% and function we want to plot on magnitude plot.
s = tf('s');
G = 50 / ( s*(1.6*s+1)*(0.23*s+1) );
ww = logspace(0,3,5000);
y = 10.^(-2*log10(ww)+log10(150));
hand = figure; % create a handle to new figure
h = bodeplot(G,ww);
hold on;
children = get(hand, 'Children') % use this handle to obtain list of figure's children
% We see that children has 3 objects:
% 1) Context Menu 2) Axis object to Phase Plot 3) Axis object to Magnitude Plot
magChild = children(3); % Pick a handle to axes of magnitude in bode diagram.
% magChild = childern(2) % This way you can add data to Phase Plot.
axes(magChild) % Make those axes current
loglog(ww,y,'r');
legend('transfer function','added curve')
you can get magnitude and phase data separately for each system using:
[mag,phase] = bode(sys,w)
now you can use subplot or plot to plot the diagram you want.
The only solution I was able to perform is taking into account axis position. It is not very clean but it works.
Here is the code to select mag plot:
ejes=findobj(get(gcf,'children'),'Type','axes','visible','on');
posicion=get(ejes,'pos');
tam=length(posicion);
for ii=1:tam
a=posicion{ii}(2);
vectorPos(ii)=a;
end
[valorMax,ind]=max(vectorPos); % min for choosing the phase plot
axes(ejes(ind))