Dynamic plot in each iteration in MATLAB - matlab

In the following code, plot(plot_x,plot_y,'-k'); in current iteration shows the previous iterations plots.
But I want to show only the current iteration plot, i.e., previous plot should be disappeared. However, plot(N_x,N_y,'Ob','MarkerSize',10); should be there always. What kind of modification should I do?
N = 50;
L = 20;
itr = 5;
N_x = (rand(N,1)-0.5)*L;
N_y = (rand(N,1)-0.5)*L;
plot(N_x,N_y,'Ob','MarkerSize',10);
grid on;
hold on;
axis([-0.5*L 0.5*L -0.5*L 0.5*L]);
for n = 1:itr
out = randperm(N,5);
plot_x = N_x(out);
plot_y = N_y(out);
plot(plot_x,plot_y,'-k');
hold on;
pause(1);
end

You can update the XData and YData properties of a single line instead of creating a new one.
I've added comments to the below code to explain the edits
N = 50;
L = 20;
itr = 5;
N_x = (rand(N,1)-0.5)*L;
N_y = (rand(N,1)-0.5)*L;
plot(N_x,N_y,'Ob','MarkerSize',10);
grid on;
hold on;
axis([-0.5*L 0.5*L -0.5*L 0.5*L]);
p = plot(NaN, NaN, '-k'); % Create a dummy line to populate in the loop
for n = 1:itr
out = randperm(N,5);
plot_x = N_x(out);
plot_y = N_y(out);
set( p, 'XData', plot_x, 'YData', plot_y ); % Update the line data
drawnow(); % flush the plot buffer to force graphics update
pause(1);
end

In the plot loop, ask the plot function returnig the handle of the line, then, after the pause statement delete the line by calling the delete function.
for n = 1:itr
out = randperm(N,5);
plot_x = N_x(out);
plot_y = N_y(out);
%
% Get the handle of the line
%
hp=plot(plot_x,plot_y,'-k');
hold on;
pause(1);
%
% Delete the line
%
delete(hp)
end

Related

Real time NI-DAQ data plot in Matlab

I'm trying to get a real time plot of data I'm acquiring with a NI USB-6008. I tried doing the same with arduino and got a plot exactly as I wanted (see here https://i.stack.imgur.com/08kzU.jpg), and the x-axis would move in real-time, but I couldn't define the sampling rate. With NI I was able to define the sampling rate I wanted but I can't display the data in a continuous, real-time plot, I can only see 1 sec at a time and I need to be able to have access to all the data acquired since I want to measure a real-time EEG. I'm a new matlab user, so please consider no previous knowledge.
This is the code I've got so far:
clear
close all
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
dq.ScansAvailableFcn = #(src,evt) plotDataAvailable(src, evt);
dq.ScansAvailableFcnCount = 100;
start(dq, "Duration", seconds(5))
while dq.Running
pause(0.5);
end
time = 0;
data = 0;
n = ceil(dq.Rate/10);
%Set up Plot
figure(1)
plotGraph = plot(time,data);
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10); ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
h = animatedline;
function plotDataAvailable(src, ~)
while ishandle(plotGraph) % Loop when Plot is Active will run until plot is closed
data = read(dq,n);
t = datetime('now');
% Add points to animation
addpoints(h,datenum(t),data)
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
end
This was my previous arduino code that showed me the plot I needed (with the wrong sampling rate):
clear
clc
%User Defined Properties
a = arduino('com4','uno'); % Define the Arduino Communication port
plotTitle = 'Arduino Data Log'; % Plot title
%Define Function Variables
time = 0;
data = 0;
%Set up Plot
figure(1)
plotGraph = plot(time,data,'-r' );
title(plotTitle,'FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10); ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
ax.YLim = [0 5]; % Sets y-min and y-max
while ishandle(plotGraph) % Loop when Plot is Active will run until plot is closed
startIteration = tic;
voltagem = readVoltage(a,'A0')
t = datetime('now');
% Add points to animation
addpoints(h,datenum(t),voltagem)
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
I've tried using this while loop on my NI data but it doesn't work.
I would really appreciate your help.
You've got the order of the operations wrong. What your code is doing at the moment is:
initialize the data acquisition
read the data from the hardware while trying to add data to lines that don't exist
initialize the animated lines.
Furthermore, in your addpoints call you're trying to plot t, which is a scalar, and data, which is an array.
What you should do instead is:
clear
close all
% Set up the plot
figure(1)
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10)
ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
% Set up the data acquisition
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
dq.ScansAvailableFcn = {#plotDataAvailable, h, ax}; % pass also the handle to the line and to the axes
dq.ScansAvailableFcnCount = 100;
% Now you start the data acquisition
start(dq, "Duration", seconds(5))
function plotDataAvailable(src, evt, h, ax)
data = read(dq, n);
% maybe your time array should look something like this?
t = datetime(now) - seconds((length(data)-1:-1:0)./src.Rate);
% Add points to animated line
addpoints(h, datenum(t), data)
% Update axes
% ax.XLim = datenum([t-seconds(15) t]); % this line is useless, why would you have a 15s window when your data acquisition is only 5s long?
datetick('x','keeplimits')
drawnow
end
I can't try this at the moment, so it might not work exactly.
So I think I finally got it, because I got the plot like I wanted, with the x-axis moving with real-time. However I still get an error saying "Unrecognized table variable name 'Dev1_ai0'" event tho I checked that's the name of the row that I want. Anyways, this is what my code looks now.
clear
close all
time = 0;
data = 0;
% Set up the plot
figure(1)
plotGraph = plot(time,data,'-r' );
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10)
ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
% Set up the data acquisition
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
% Start the data acquisition
start(dq, "Duration", seconds(10))
n = ceil(dq.Rate/10);
while ishandle(plotGraph)
data = read(dq, n);
voltage = data.Dev1_ai0;
t = datetime('now');
for i = 1:100
% Add points to animated line
if isvalid(h)
addpoints(h, datenum(t), voltage(i))
end
end
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
disp('Plot Closed')

Dictionary simulation in Octave/Matlab for Sparse recovery

I want to do a classification on RGB image using sparse recovery and for now, I want to create some dummy random samples. Thus, I have found the following code and since I am very new in the octave I do not understand the code properly.
Would be nice if someone can give a command for the sections after reshaping the image.
here is the code:
A = imread('demo2.jpg');
B = (A(301:800, 1:400,:));
figure(1)
image(B); axis on; axis equal
%3dim plot
D1 = B(1:50,1:50,:);
D2 = B(1:50,151:200,:);
D3 = B(151:200,351:400,:);
figure(2); %Pflanze
image(D1); axis on; axis equal
figure(3); %Haar
image(D2); axis off; axis equal
figure(4); %Haut
image(D3); axis off; axis equal
%sampling at random N per class
N = 50;
idx2d_D1 = ceil(rand(N,2)*50);
idx2d_D2 = ceil(rand(N,2)*50);
idx2d_D3 = ceil(rand(N,2)*50);
test_vec_D1 = zeros(N,3);
for k=1:N
test_vec_D1(k,1) = D1(idx2d_D1(k,1),idx2d_D1(k,2),1);
test_vec_D1(k,2) = D1(idx2d_D1(k,1),idx2d_D1(k,2),2);
test_vec_D1(k,3) = D1(idx2d_D1(k,1),idx2d_D1(k,2),3);
end
test_vec_D2 = zeros(N,3);
for k=1:N
test_vec_D2(k,1) = D2(idx2d_D2(k,1),idx2d_D2(k,2),1);
test_vec_D2(k,2) = D2(idx2d_D2(k,1),idx2d_D2(k,2),2);
test_vec_D2(k,3) = D2(idx2d_D2(k,1),idx2d_D2(k,2),3);
end
test_vec_D3 = zeros(N,3);
for k=1:N
test_vec_D3(k,1) = D3(idx2d_D3(k,1),idx2d_D3(k,2),1);
test_vec_D3(k,2) = D3(idx2d_D3(k,1),idx2d_D3(k,2),2);
test_vec_D3(k,3) = D3(idx2d_D3(k,1),idx2d_D3(k,2),3);
end
figure(5)
%pointset
X1 = [test_vec_D1'];
X2 = [test_vec_D2'];
X3 = [test_vec_D3'];
plot3(X1(1,:), X1(2,:), X1(3,:),'bo'); axis on; grid on; hold on
plot3(X2(1,:), X2(2,:), X2(3,:),'go');
plot3(X3(1,:), X3(2,:), X3(3,:),'ro'); hold off;
title('blau-Pflanze, grün-Haar, rot-Haut')
I made a drawing of the process and finally understood how does this code work.

How to manage the legend for many plots

How do I handle this issue
clear all; close all; clc;
r = 0:5;
zeta = 0:0.1:1;
for i = 1:size(zeta(:))
for j = 1:size(r(:))
X(i,j) = sqrt((1+(2*zeta(i)*r(j))^2)/((1-r(j)^2)^2+ (2*zeta(i)*r(j))^2));
end
plot(r,X);
xlabel('r = \omega/\omega_n');
ylabel('M = \frac{X}{Y}');
hold all
grid
[~,~,~,current_entries] = legend;
legend([current_entries {sprintf('\zeta = %i',zeta(i))}]);
end
figure
plot(r,X)
grid
The hold all command doesn't seem to be working properly. What can I do to fix this?
You will want to set the DisplayName property of the plot. Then when you create the legend, the labels will automatically be populated.
plot(r, X, 'DisplayName', 'name')
Also, the string that you were passing to sprintf for your legends needs to be escaped becuase sprintf thinks that \z is a control character.
plot(r, X, 'DisplayName', sprintf('\\zeta = %0.1f',zeta(k)))
Also, hold on is recommended over hold all. Also, it is best practice to specify the axes handle when calling hold to ensure that it is applied to the current axes.
hold(hax, 'on')
So if we incorporate these changes into your plotting code (along with #R.Falque's idea to use semilogy)
r = 0:0.001:5;
zeta = 0:0.1:1;
hax = axes();
colors = hsv(numel(zeta));
for k = 1:numel(zeta)
X = sqrt((1 + (2 * zeta(k) * r).^2) ./ ((1-r.^2).^2+ (2*zeta(k)*r).^2));
semilogy(r, X, ...
'DisplayName', sprintf('\\zeta = %0.1f',zeta(k)), ...
'Color', colors(k,:));
hold(hax, 'on')
end
grid(hax, 'on')
xlabel(hax, 'r = \omega/\omega_n', 'Interpreter', 'tex');
ylabel(hax, 'M = $\displaystyle\frac{X}{Y}$', 'Interpreter', 'latex');
L = legend('show');
You can also use cells array as follow:
clear all; close all; clc;
r = 0:0.001:5;
zeta = 0:0.1:1;
figure;
for i = 1:length(zeta)
for j = 1:length(r)
X(j) = sqrt((1+(2*zeta(i)*r(j))^2)/((1-r(j)^2)^2+ (2*zeta(i)*r(j))^2));
end
semilogy(r,X);
hold on
legend_string{i} = ['\zeta = ', num2str(zeta(i))];
end
hold off
grid
xlabel('r = \omega/\omega_n');
ylabel('M = $\frac{X}{Y}$','Interpreter', 'Latex');
legend(legend_string);
Note that you have an error in the X definition (corrected from X(i,j) to X(j)).

How should I update the data of a plot in Matlab? part - 2

This is a continuation from the question already posted here. I used the method that #Andrey suggested. But there seems to be a limitation. the set(handle, 'XData', x) command seems to work as long as x is a vector. what if x is a matrix?
Let me explain with an example.
Say we want to draw 3 rectangles whose vertices are given by the matrices x_vals (5,3 matrix) and y_vals (5,3 matrix). The command that will be used to plot is simply plot(x,y).
Now, we want to update the above plot. This time we want to draw 4 rectangles. whose vertices are present in the matrices x_new(5,4 matrix) and y_new (5,4 matrix) that we obtain after some calculations. Now using the command set(handle, 'XData', x, 'YData', y) after updating x and y with new values results in an error that states
Error using set
Value must be a column or row vector
Any way to solve this problem?
function [] = visualizeXYZ_struct_v3(super_struct, start_frame, end_frame)
% create first instance
no_objs = length(super_struct(1).result);
x = zeros(1,3000);
y = zeros(1,3000);
box_x = zeros(5, no_objs);
box_y = zeros(5, no_objs);
fp = 1;
% cascade values across structures in a frame so it can be plot at once;
for i = 1:1:no_objs
XYZ = super_struct(1).result(i).point_xyz;
[r,~] = size(XYZ);
x(fp:fp+r-1) = XYZ(:,1);
y(fp:fp+r-1) = XYZ(:,2);
% z(fp:fp+r-1) = xyz):,3);
fp = fp + r;
c = super_struct(1).result(i).box;
box_x(:,i) = c(:,1);
box_y(:,i) = c(:,2);
end
x(fp:end) = [];
y(fp:end) = [];
fig = figure('position', [50 50 1280 720]);
hScatter = scatter(x,y,1);
hold all
hPlot = plot(box_x,box_y,'r');
axis([-10000, 10000, -10000, 10000])
xlabel('X axis');
ylabel('Y axis');
hold off
grid off
title('Filtered Frame');
tic
for num = start_frame:1:end_frame
no_objs = length(super_struct(num).result);
x = zeros(1,3000);
y = zeros(1,3000);
box_x = zeros(5, no_objs);
box_y = zeros(5, no_objs);
fp = 1;
% cascade values accross structures in a frame so it can be plot at once;
for i = 1:1:no_objs
XYZ = super_struct(num).result(i).point_xyz;
[r,~] = size(XYZ);
x(fp:fp+r-1) = XYZ(:,1);
y(fp:fp+r-1) = XYZ(:,2);
fp = fp + r;
c = super_struct(num).result(i).box;
box_x(:,i) = c(:,1);
box_y(:,i) = c(:,2);
end
x(fp:end) = [];
y(fp:end) = [];
set(hScatter, 'XData', x, 'YData', y);
set(hPlot, 'XData', box_x, 'YData', box_y); % This is where the error occurs
end
toc
end
Each line on the plot has its own XData and YData properties, and each can be set to a vector individually. See the reference. I am not at a Matlab console right now, but as I recall...
kidnum = 1
h_axis = gca % current axis - lines are children of the axis
kids = get(h_axis,'Children')
for kid = kids
kid_type = get(kid,'type')
if kid_type == 'line'
set(kid,'XData',x_new(:,kidnum))
set(kid,'YData',y_new(:,kidnum))
kidnum = kidnum+1
end
end
Hope that helps! See also the overall reference to graphics objects and properties.
To add a series, say
hold on % so each "plot" won't touch the lines that are already there
plot(x_new(:,end), y_new(:,end)) % or whatever parameters you want to plot
After that, the new series will be a child of h_axis and can be modified.

Matlab vertical line keeps appearing while using hold on and area()

It is beginning to annoy me that I can't get rid of this vertical line that keeps appearing when I plot the area;
[x y] = ginputExtra(4)
x = 0.1947 0.6118 0.8329 0.4136
y = 0.5746 0.8173 0.4225 0.3553
area([x x(1)],[y y(1)])
[x y] = ginputExtra(4,true)
x = 0.5087 0.6881 0.4954 0.3204
y = 0.4961 0.2382 0.1566 0.3566
hold on;
area([x x(1)],[y y(1)],'FaceColor',[1 0 0])
Is there any way to avoid this line?
BTW: the ginputExtra method call I use..
function [x y] = ginputExtra(n,booText)
% INPUT
% n: Number of points to plot
% booText: Boolean (default false) command to display point number in
% the plot.
% Author: Lasse Nørfeldt (Norfeldt)
% Date: 2012-04-09
if nargin ==2
bText = booText;
else
bText = false;
end
H = gca;
set(H, 'YLimMode', 'manual'); set(H, 'XLimMode', 'manual');
set(H, 'YLim', get(H,'YLim')); set(H, 'XLim', get(H,'XLim'));
numPoints = n; xg = []; yg = [];
for i=1:numPoints
[xi yi] = ginput(1);
xg = [xg xi]; yg = [yg yi];
if i == 1
hold on;
plot(H, xg(i),yg(i),'ro');
if bText text(xg(i),yg(i),num2str(i),'FontSize',14); end
else
plot(xg([i-1:i]),yg([i-1:i]),'r');
if bText text(xg(i),yg(i),num2str(i),'FontSize',14); end
end
end
hold off;
x = xg; y = yg;
Your issue might be in plotting by area(), as it seems to be primarily for stacking several vecotrs. If you zoom out a bit and see a similar vertical line from the first point in the blue area, the area function is most likely the issue.
The function:
fill([x x(1)],[y y(1)],COLOR)
Might do the trick for you, as it plots a filled polygon.
/Thomas