I'm processing vast amount of data (>>100k lines) with variable step.
I would like to create figure and plot the processed data as they are counted (for termination of the running script when something goes wrong, or for impressing the "customers" with the fancy progress "animation").
Suppose we have `sourcefile.txt' with one column of positive numbers X(n) on row n and:
There is plenty of lines with X(n+1) < X(n),
X(n+N) > X(n); where N goes from thousands for small n to tens for large n.
I've thought of:
fID=fopen('sourcefile.txt');
figure;axes; % create figure
act='0';threshold=0;N=0;DATA=0;ii=0;
while ischar(act) % loop until end of file.
ii=ii+1;N=0;
while temp<threshold&&ischar(act) % loop until threshold is overflown (next step) or end-of-file is reached.
act=fgetl(fID);
temp=temp+str2double(act);
N=N+1;
end
line('xdata',ii,'ydata',temp/N,'Marker','o') % New point should appear
threshold=threshold+0.5; % Continue with new stopping rule.
end
The problem is that the loops are entered and processed and then figure is created. How can I force MATLAB to create a figure and then to calculate/update plotted data?
Try inserting drawnow after you draw the line using line. This will flush the graphics buffer and update your figure immediately. If you don't do this, your figure will appear blank until the loop finishes, and then the figure will appear with your objects that you added to the figure.
So to be specific with what I talked about:
fID=fopen('sourcefile.txt');
figure;axes; % create figure
act='0';threshold=0;N=0;DATA=0;ii=0;
while ischar(act) % loop until end of file.
ii=ii+1;N=0;
while temp<threshold&&ischar(act) % loop until threshold is overflown (next step) or end-of-file is reached.
act=fgetl(fID);
temp=temp+str2double(act);
N=N+1;
end
line('xdata',ii,'ydata',temp/N,'Marker','o') % New point should appear
%%%%%%%%%%%%// Change here
drawnow;
threshold=threshold+0.5; % Continue with new stopping rule.
end
Therefore, once you draw a line, the figure should immediately update itself and so for each iteration, the figure should update with a new line object.
Related
I have a loop that I am trying to create another loop around, but I'm not sure what the syntax should be. Here is my code:
for (?)
for i=1:6
r(i)=normrnd(0,0.1*sy);
y_new=A+B*x+r;
end
% estimate new A and B
[mm,nn]=size(x); DoF=mm-2;
x_mean=mean(x);
y_mean=mean(y_new);
xp=(x-x_mean);
yp=(y_new-y_mean);
num=sum(xp.*yp);
dem=sum(xp.*xp);
B_new=num/dem;
A_new=y_mean-B_new*x_mean;
end
I'm not sure what to put in the for loop to make it repeat 100X. I assume I need "for i=1:100" but then I'm not sure where in the loop to put set my x(i) to get the intended result. I'm not even sure if I nested the first loop in there correctly. I am trying to create a set of 6 new y values using normrnd and then run a linear regression to generate a new A and B (slope and intercept), and then I want to repeat that entire process 100X.
Unless you have a specific reason not to vectorize your normrnd() calls, you only need one level of fors:
%sy,A,B,x initialized elsewhere
for i=1:100
r=normrnd(0,0.1*sy,[6 1]);
y_new=A+B*x+r;
clear r;
% estimate new A and B
[mm,nn]=size(x);
DoF=mm-2;
x_mean=mean(x);
y_mean=mean(y_new);
xp=(x-x_mean);
yp=(y_new-y_mean);
num=sum(xp.*yp);
dem=sum(xp.*xp);
B_new=num/dem;
A_new=y_mean-B_new*x_mean;
%set B=B_new and A=A_new for the next iteration maybe?
end
clear i;
I am experimenting with MATLAB SPDM. However, I have the following problem to solve:
I am running a quite long algorithm and I would like to save the progress along the way in case the power gets cut, someone unplugs the power plug or memory error.
The loop has 144 iterations that take each around 30 minutes to complete => 72h. A lot of problems can occur in that interval.
Of course, I have the distributed computing toolbox on my machine. The computer has 4 physical cores. I run MATLAB R2016a.
I do not really want to use a parfor loop because I concatenate results and have dependency across iterations. I think SPMD is the best choice for what I want to do.
I'll try to describe what I want as best as I can:
I want to be able to save at a set iteration of the loop the results so far, and I want to save the results by worker.
Below is a Minimum (non)-Working Example. The last four lines should be put in a different .m file. This function, called within a parfor loop, allows to save intermediate iterations. It is working properly in other routines that I use. The error is at line 45 (output_save). Somehow, I would like to "pull" the composite object into a "regular" object (cell/structure).
My hunch is that I do not quite understand how Composite objects work and especially how they can be saved into "regular" objects (cells, structures, etc).
% SPMD MWE
% Clear necessary things
clear output output2 output_temp iter kk
% Useful thing that will be used later on
Rorder=perms(1:4);
% Stem of the file to save the data to
stem='MWE_MATLAB_spmd';
% Create empty cells where the results of the kk loop will be stored
output1{1,1}=[];
output2{1,2}=[];
% Start the parpool
poolobj=gcp;
% Define which worker/lab will do which iteration
iterperworker=ceil(size(Rorder,1)/poolobj.NumWorkers);
for i=1:poolobj.NumWorkers
if i<poolobj.NumWorkers
itertodo{1,i}=1+(iterperworker)*(i-1):iterperworker*i;
else
itertodo{1,i}=1+(iterperworker)*(i-1):size(Rorder,1);
end
end
%Start the spmd
% try
spmd
iter=1;
for kk=itertodo{1,labindex}
% Print which iteration is done at the moment
fprintf('\n');
fprintf('Ordering %d/%d \r',kk,size(Rorder,1));
for j=1:size(Rorder,2)
output_temp(1,j)=Rorder(kk,j).^j; % just to populate a structure
end
output.output1{1,1}=cat(2,output.output1{1,1},output_temp); % Concatenate the results
output.output2{1,2}=cat(2,output.output1{1,2},0.5*output_temp); % Concatenate the results
labindex_save=labindex;
if mod(iter,2)==0
output2.output=output; % manually put output in a structure
dosave(stem,labindex_save,output2); % Calls the function that allows me to save in parallel computing
end
iter=iter+1;
end
end
% catch me
% end
% Function to paste in another m-file
% function dosave(stem,i,vars)
% save(sprintf([stem '%d.mat'],i),'-struct','vars')
% end
A Composite is created only outside an spmd block. In particular, variables that you define inside an spmd block exist as a Composite outside that block. When the same variable is used back inside an spmd block, it is transformed back into the original value. Like so:
spmd
x = labindex;
end
isa(x, 'Composite') % true
spmd
isa(x, 'Composite') % false
isequal(x, labindex) % true
end
So, you should not be transforming output using {:} indexing - it is not a Composite. I think you should simply be able to use
dosave(stem, labindex, output);
I have a MATLAB GUI that calls an external function to make a plot (make_ethogram_plot).
The idea would be to have an external figure that is constantly updated with the output value from the figure. Every time the data gets updated it should replot the values, it updates at ~10 Hz. I chose gramm (https://github.com/piermorel/gramm/tree/master/%40gramm) because it is really easy to make a raster plot.
This is the function that gets called. I am having issues to
1) Make it only update in the parent figure with specific name, instead of plotting in the GUI(which is the active figure).
2) Make it not crash. It would open many figures or open or close the same figure at 10 Hz until crashing.
In this configuration, it gives error because it doesn't find g after the first plot. Making g , f, and p1 globals makes it crash (opens every time it gets called)
function make_ethogram_plot(datastructure)
% if the figure doesn't exists create it
if(isempty(findobj(0, 'Name', 'My_gramm_ethogram')))
f=figure('Name', 'My_gramm_ethogram');
p1 = uipanel('Parent',f,'BackgroundColor',[1 1 1],'BorderType','none');
g = gramm('x', datastructure.final_data.frameID, 'color', categorical(datastructure.final_data.behavior));
g.geom_raster();
g.set_parent(p1);
g.draw()
else
% defining f,p1, g here (or having them global) works but crashes
% due to refresh rate
g.update()
end
end
I wrote this code to try to replicate your problem:
function animate_random_data
N = 10000;
data = [cumsum(rand(N,1)),randn(N,1)];
for ii=0:1000
% Plot the data
make_ethogram_plot(data);
drawnow
% Compute new data
data(:,1) = cumsum(rand(N,1));
data(:,2) = randn(N,1);
end
function make_ethogram_plot(data)
fig = findobj(0, 'Name', 'My_gramm_ethogram');
if(isempty(fig))
% If the figure doesn't exists create it
fig = figure('Name', 'My_gramm_ethogram');
ax = axes(fig);
plot(ax,data(:,1),data(:,2));
drawnow
set(ax,'xlimmode','manual','ylimmode','manual');
else
% If it does, update it
line = findobj(fig,'type','line');
set(line,'xdata',data(:,1));
set(line,'ydata',data(:,2));
end
Here, I followed your concept of looking for a named figure window, and creating one if it didn't exist. However, if it does exist, I simply replace the XData and YData property of the line that is already there. This is the fastest way of animating a graph, much faster than deleting the existing plot and creating a new one. After plotting, I use drawnow to update the display. I set XLimMode and YLimMode to manual to prevent re-computation of axes limits and consequent re-drawing of the axes.
The function took 17 seconds to draw all 1000 frames, meaning it's drawing about 60 frames a second. It does not (and should not) crash MATLAB.
You can limit the display rate to 20 frames/sec with drawnow limitrate. It will skip updating the display if the frames come too fast.
I don't know what the gramm/update method does, the class is too complicated to quickly see what is going on, but I dare presume it deletes the axes and creates a new plot from scratch. Not that this should crash MATLAB, it might be worth while to submit a bug report. However, you would probably want to update the figure in the more efficient way, following the method I demonstrated above.
Note that this method can be used to update any of the graphical elements in a plot. For example, I have used this method to animate images.
I want to create a frontend where the user can browse pictures forward by pressing Enter.
Pseudo-Code
hFig=figure
nFrames=5;
k=1;
while k < nFrames
u=signal(1*k,100*k,'data.wav'); % 100 length
subplot(2,2,1);
plot(u);
subplot(2,2,2);
plot(sin(u));
subplot(2,2,3);
plot(cos(u));
subplot(2,2,4);
plot(tan(u));
% not necessary but for heading of overal figure
fprintf('Press Enter for next slice\n');
str=sprintf('Slice %d', k);
mtit(hFig, str);
k=k+1;
keyboard
end
function u=signal(a,b,file)
[fs,smplrt]=audioread(file);
u=fs(a:b,1);
end
where
something is wrong in updating the data because pressing CMD+Enter increases k by one but does not update the data. Sometimes (rarely), the data is once the next iteration.
something is wrong with while's condition because k can be bigger than nFrames. keyboard just keep asking for more inputs.
My mistake earlier in Error-Checking
I had earlier a problem where the closure of the window lead to the crash of the application. I include this here because I mentioned a problem about it in the comment of one answer. I avoid the problem now by
hFig=figure;
n=5;
k=1;
while k<nFrames
% for the case, the user closes the window but starts new iteration
if(not(ishandle(hFig)))
hFig=figure;
end
...
end
which creates a new Figure if the earlier was closed by the user.
I tried unsuccessfully putting hFig=figure; inside the while loop's if clause earlier to avoid repetition in the code.
Please, let me know if you know why you cannot have the handle hFig in the while loop's if clause.
How can you loop subplots with updated outputs in Matlab?
To stop the script waiting for an input from the user you should use input instead of keyboard.
Actually keyboard makes your script entering in a debug mode. It stops the executino of the script as (like a breakpoint) allowing the user to, for example, check the value of a variable.
You can modify your scripr as follows (modification are at the end of your script, identified by "UPDATED SECTION):
hFig=figure
nFrames=5;
k=1;
while k < nFrames
u=signal(1*k,100*k,'handel.wav'); % 100 length
subplot(2,2,1);
plot(u);
subplot(2,2,2);
plot(sin(u));
subplot(2,2,3);
plot(cos(u));
subplot(2,2,4);
plot(tan(u));
% not necessary but for heading of overal figure
%
% UPDATED SECTION
%
% Use the string "Press Enter for next slice\n" as the prompt for the
% call to "input"
%
% fprintf('Press Enter for next slice\n');
% str=sprintf('Slice %f', k);
% Use %d instead of "%f" to print integer data
str=sprintf('Slice %d', k);
mtit(hFig, str);
k=k+1;
% Use "input" instead of "keyboard"
% keyboard
input('Press Enter for next slice\n')
end
Hope this helps.
Qapla'
I'm trying to write a small function which should read a matrix of doubles, make a plot for all columns separately (and display the last row as line, as this is the mean) and save the plot.
All commands work when I tried them on the command line, but when I run them as a script it doesn't work. The plots are not entered in the figure (only ticks and labels are redrawn). When I copy the single commands in debug mode to the command line it works.
So what am I doing wrong here?
I'm loading a matrix 'corr' prior to this loop..
for i=1:30; % number of components
corr_fig(i)=figure;
hold;
plot(corr(1:length(sub),i));
line ([0 (length(sub))],[(corr(length(sub)+1)) (corr(length(sub)+1))], 'Color','m')
set(gca,'XTick',[1:(length(sub))])
set(gca,'XTickLabel',{sub{1:length(sub)}})
title(['Correlations for',num2str(i)])
saveas(corr_fig(i),['corrs_for_',num2str(i)],'fig');
hold off;
close all;
end
Throw in a 'drawnow' command in the loop. This flushes out the plotting buffer and forces MATLAB to create the figure, rather than trying to skip that step due to what the compiler sees happening in the loop.
For example, this:
for k = 1:100;
figure()
plot(rand(100, 1), rand(100, 1))
close all
end
draws nothing (never shows a figure window), but this:
for k = 1:100;
figure()
plot(rand(100, 1), rand(100, 1))
drawnow
close all
end
does what you would expect.
Thanks for all the answers! Figured it out on my own in the end. The code is fine, well mostly. I haven't assigned a proper variable name to the matrix I handed to the function and was not calling this name in the loop corectly (MAT.corr would have been it..) Now it's working.. Stupid me! Thanks nevertheless!