I have been able to put together the following code to find a time stamp every time space bar is pressed. However, I can't figure out a way to save the S.tm to the work space. Here is the code:
function main
S.tm = [];
S.cnt = 0;
S.fh = figure('KeyPressFcn',#youPressedSomething,...
'menu','none',...
'pos',[400 400 320 50]);
S.th = uicontrol('Style','text','Position',[10 10 300 30],...
'String','You have not hit space yet');
function youPressedSomething(varargin)
if strcmp(varargin{2}.Character,' ')
S.tm = [S.tm now]
S.cnt = S.cnt + 1;
set(S.th,'str',sprintf('You hit space %i!',S.cnt));
end
end
end
There are two main options here. You could use assignin within your function to save the data to the main workspace.
function main
S.tm = [];
S.cnt = 0;
S.fh = figure('KeyPressFcn',#youPressedSomething,...
'menu','none',...
'pos',[400 400 320 50]);
S.th = uicontrol('Style','text','Position',[10 10 300 30],...
'String','You have not hit space yet');
function youPressedSomething(varargin)
if strcmp(varargin{2}.Character,' ')
S.tm = [S.tm now]
S.cnt = S.cnt + 1;
set(S.th,'str',sprintf('You hit space %i!',S.cnt));
%// Save as "timestamps" in the base workspace
assignin('base', 'timestamps', S.tm);
end
end
end
Or a better approach would be to use waitfor to block execution of the function until the figure is closed. Then you can return S.tm just like a normal output argument
function timestamps = main()
S.tm = [];
S.cnt = 0;
S.fh = figure('KeyPressFcn',#youPressedSomething,...
'menu','none',...
'pos',[400 400 320 50]);
S.th = uicontrol('Style','text','Position',[10 10 300 30],...
'String','You have not hit space yet');
%// Wait until the figure is closed
waitfor(S.fh);
%// Save S.tm as timestamps and return
timestamps = S.tm;
function youPressedSomething(varargin)
if strcmp(varargin{2}.Character,' ')
S.tm = [S.tm now]
S.cnt = S.cnt + 1;
set(S.th,'str',sprintf('You hit space %i!',S.cnt));
%// Save as "timestamps" in the base workspace
assignin('base', 'timestamps', S.tm);
end
end
end
You can try to edit your code this way:
function[S.fh]=main()
%% Your Code
function yPS(varargin)
if...
%% Your Code
end
set(S.fh,'UserData',S.tm);
end %yPS
end %main
This should return figure handle to the workspace and keep it in memory as well. Then whenever the yPS function is called it uses shared handle S.fh to the figure and (re)sets UsedData property which is dedicated to contain, well, user data.
To use the function call it Foo=main.
get(Foo.fh,'UserData')
ans =
[]
Hit spacebar several times
>> get(AA.fh,'userdata')
ans =
1.0e+005 *
7.3645
7.3645
7.3645
Related
I have a relatively big file and I would like to make an interactive plot using GUIDE which plots a segment of the file and upon scrollEvent the window gets updated. (the data is appropriately replotted).
To this end a buffer of size 4 times that of the window is fetched, and when the window's center reaches 75% of the buffer, the buffer is refetched so that the window is at the center of the new buffer.
The problem with this is that when using fread it of course blocks until done.(which is visually disturbing)
What I tried is to create a separate readData function which gets called with f = parfeval(gcp(),#readData,1,datafile) and on [~,buffer]=fetchNext(f) the buffer is persisted on handles.datafile.
Problem: Even though in my example (see below) readData only gets called once, every subsequent plotting is incredibly slow (10x the runtime of when not using parfeval).
Example:
./test.dat was generated by dd if=/dev/urandom of=test.dat bs=100000 count=1024
**This is the synchronous code to get the asynchronous one, comment out the parfeval and fetchNext function definitions shadowing the parallel ones.
function test()
f = figure('Toolbar','none','Menubar','none');
ax = axes(f);
data = struct( 'file','./test.dat',...
'buffer',[],...
'window',[0,100000]);
p = gcp();
data.fileReader = parfeval(p,#readData,1,data);
handles = struct('axes',ax,'figure',f,'data',data);
guidata(f,handles);
set(f,'WindowScrollWheelFcn',#scrollHandler);
end
function f = parfeval(~,fun,~,in1)
f = struct('output',fun(in1));
end
function [id,out] = fetchNext(f,varargin)
id = 1;
out = f.output;
end
function buffer = readData(data)
file = fopen(data.file,'r');
buffer = fread(file,[128,400000],'int16');
fclose(file);
end
function scrollHandler(hObject, eventdata, ~)
handles = guidata(hObject);
ax = handles.axes;
C = get (ax, 'CurrentPoint');
XLim = get(ax, 'XLim');
YLim = get(ax, 'YLim');
if XLim(1)<=C(1,1) && XLim(2)>=C(1,1) && ...
YLim(1)<=C(1,2) && YLim(2)>=C(1,2)
tic;
window = handles.data.window;
if isstruct(handles.data.fileReader) || handles.data.fileReader ~= -1
fprintf('Reading from file\n');
[~,handles.data.buffer] = fetchNext(handles.data.fileReader);
handles.data.fileReader = -1;
end
if eventdata.VerticalScrollCount > 0 && window(2) < 399000
window = window + 1000;
else
if window(1) > 1000
window = window - 1000;
end
end
handles.data.window = window;
guidata(hObject, handles);
plot(ax,handles.data.buffer(65,window(1)+1:window(2)));
toc
end
end
This is indeed very mysterious. The problem seems to be some sort of interaction with guidata and the parallel.FevalFuture returned by parfeval. As a workaround, you can simply avoid overwriting that element of the struct. In other words, remove the line
handles.data.fileReader = -1;
You'll also need to check handles.data.fileReader.Read to make sure you don't attempt to call fetchNext again on an already-completed future.
I have one .m file per plot and want to see in my draft printouts, which file was used to create it.
This should be done with a function which can be placed in my .m file and
commented out, for the final version.
% addWatermarkFilename() %
So far I found mfilename(), but it could not get the name of the calling function. I am looking also for a good way to put the text in the picture without changing the size.
Solution:
I combined the suggestions by Luis Mendo and NKN to:
function [ output_args ] = watermarkfilename( )
% WATERMARKFILENAME prints the filename of the calling script in the
% current plot
s = dbstack;
fnames = s(2).name;
TH = text(0,0,fnames,'Interpreter','none');
TH.Color = [0.7 0.7 0.7];
TH.FontSize = 14;
TH.Rotation = 45;
uistack(TH,'bottom');
end
I suggest instead of commenting out a function from the code, use a proper flag. For instance the code can be something like this:
clc,clear,close all
addWaterMark = true; % if true you will get the filename in the title
fname = mfilename; % get file name mfilename('fullpath') for the full-path
t=-2*pi:0.1:2*pi;
y = sin(t);
plot(t,y); grid on;
xlabel('t');ylabel('y');
if addWaterMark
title(['filename: ' fname '.m']);
else
title('plot no.1');
end
A little bit playing with the text function, you can make a proper watermark. something like this:
clc,clear,close all
addWaterMark = true;
fname = mfilename;
fnames = [fname '.m'];
t=-2*pi:0.1:2*pi;
y = sin(t);
plot(t,y); grid on;
xlabel('t');ylabel('y');
if addWaterMark
title(['filename: ' fnames]);
t = text(-3,-0.4,fnames);
t.Color = [0.7 0.7 0.7];
t.FontSize = 40;
t.Rotation = 45;
else
title('plot no.1');
end
Note: Obviously the code between the if and else can be stored as a function that receives the string (char) from the fnames variable and a handle for the figure.
If you want to get the name of the function or script that called the current function or script, use dbstack as follows:
s = dbstack; % get struct with function call stack information
callerName = s(2).name; % get name of second function in the stack
The first entry in s refers to the current function; the second refers to the one that called it.
I have a matlab file that I can't post here (3000 lines) which contains a lot of functions which are used from a GUI.
I am working with matlab file that contains the 3000 lines which has so many functions for design GUI
when I am using Function A that function which are related to uses the several other functions and make it as for loop that run many time function A (1600-2000) times of iterations through taking a long time.
when I reached at 400-500 Matlab gives me
error : "Error while evaluation UIcontrol callback"
I must to kill the existing process and then exit Matlab and run again from the previous iteration which give the error. So my problem is not based on the function call but it may comes based on memory or may be temporary memory.
Does it possible to increase the temporary memory uses by Matlab ?
I increase the preference "Java heat memory" at maximum but this preference change nothing to my problem.
Is there any way to solve this issue ?
A part of the script :
function CalculateManyOffset % It's Function A on this topic
mainfig = FigHandle;
parameters = get(mainfig,'UserData');
dbstop if error
NumberofProfiles = str2double(get(parameters.NumberofProfilesBox,'string'));
step = str2double(get(parameters.DistBetweenProfilesBox,'string'));
Alphabet=('A':'Z').';
[I,J] = meshgrid(1:26,1:26);
namered = [Alphabet(I(:)), Alphabet(J(:))];
namered = strvcat(namered)';
nameblue = [Alphabet(I(:)), Alphabet(J(:))];
nameblue = strvcat(nameblue)';
apostrophe = '''';
SaveNameDisplacementFile = [get(parameters.SaveNamebox,'string'),'.txt'];
a=0;
icounter = 0;
StartBlue = str2double(get(parameters.bluelinebox,'String'));
EndBlue = StartBlue + NumberofProfiles;
StartRed = str2double(get(parameters.redlinebox,'String'));
EndRed = StartRed + NumberofProfiles-15;
for i = StartBlue:step:EndBlue;
icounter = icounter +1;
jcounter = 0;
for j=StartRed:step:EndRed;
jcounter = jcounter +1;
opthorz = [];
maxGOF = [];
a=[a(1)+1 length(StartRed:step:EndRed)*length(StartBlue:step:EndBlue)]
%
if a(1) >= 0 && a(1) <= 20000
BlueLineDist = 1*i;
parameters.bluelinedist = i;
RedLineDist = 1*j;
parameters.redlinedist = j;
parameters.i = icounter;
parameters.j = jcounter;
set(mainfig,'UserData',parameters,'HandleVisibility','callback'); % To update variable parameters for the function which use them (downside : BlueLine, RedLine, GetBlueProfile, GetRedProfile, CalculateOffset)
BlueLine;
RedLine;
GetBlueProfile;
GetRedProfile;
CalculateOffset;
% Now, reload variable parameters with new value calculate on previous functions
mainfig = FigHandle;
parameters = get(mainfig,'UserData');
opthorz = parameters.opthorz;
name = [num2str(namered(:,jcounter)'),num2str(nameblue(:,icounter)'),apostrophe];
namefid2 = [num2str(namered(:,jcounter)'),' - ',num2str(nameblue(:,icounter)'),apostrophe];
Distance = [num2str(RedLineDist),' - ',num2str(BlueLineDist)];
maxGOF = parameters.maxGOF;
% Create file with all displacements
if a(1) == 1;
fid2 = fopen(SaveNameDisplacementFile,'w');
fprintf(fid2,['Profile red - blue\t','Distance (m) between profile red - blue with fault\t','Optimal Displacement\t','Goodness of Fit\t','20%% from Goodness of Fit\t','Minimal Displacement\t','Maximal Displacement \n']);
fprintf(fid2,[namefid2,'\t',Distance,'\t',num2str(opthorz),'\t',num2str(maxGOF),'\t',num2str(parameters.ErrorGOF),'\t',num2str(parameters.ErrorDisp(1,1)),'\t',num2str(parameters.ErrorDisp(1,2)),'\n']);
elseif a(1) ~= b(end);
fid2 = fopen(SaveNameDisplacementFile,'a');
fprintf(fid2,[namefid2,'\t',Distance,'\t',num2str(opthorz),'\t',num2str(maxGOF),'\t',num2str(parameters.ErrorGOF),'\t',num2str(parameters.ErrorDisp(1,1)),'\t',num2str(parameters.ErrorDisp(1,2)),'\n']);
else
fid2 = fopen(SaveNameDisplacementFile,'a');
fprintf(fid2,[namefid2,'\t',Distance,'\t',num2str(opthorz),'\t',num2str(maxGOF),'\t',num2str(parameters.ErrorGOF),'\t',num2str(parameters.ErrorDisp(1,1)),'\t',num2str(parameters.ErrorDisp(1,2))]);
fclose(fid2);
end
end
end
end
I am setting the handles in the opening function:
function Select_A_B_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
handles.string = '';
new_count = 1;
set(handles.counter,'String',num2str(new_count));
if isempty(varargin)
varargin{1} = 1;
varargin{2} = 1;
end
A = {'Apple';'Orange';'Bag';'Cowboy'};
handles.pushbutton1text = A;
new_count = str2double(handles.counter.String);
handles.pushbutton1 = handles.pushbutton1text(new_count);
guidata(hObject, handles);
Then I am trying to change the handles to pushbutton1 when the pushbutton tagged as 'Next' is pushed:
function next_Callback(hObject, eventdata, handles)
current_count = str2double(get(handles.counter, 'String'));
new_count = current_count+1;
set(handles.counter,'String',new_count);
set(handles.pushbutton1,'String',get(handles.counter,'string');
guidata(hObject, handles);
I get the following error when I try to set the handles to pushbutton1:
Error using set
Conversion to double from cell is not possible.
I have tried several ways to fix the error, but no success yet. What am I doing wrong?
Here is a programmatic GUI which does what you want and is, in my opinion, much simpler to understand/debug. You can easily implement this using GUIDE; everything that comes before the pushbutton's callback can be put into the GUI Opening_Fcn.
I added comments in the code; if something is unclear please tell me.
function DisplayFruits
clear
clc
hFig = figure('Position',[200 200 300 300]);
handles.A = {'Apple';'Orange';'Bag';'Cowboy'};
handles.counter = 1;
%// Counter text
handles.CounterTitle = uicontrol('Style','text','Position',[50 200 60 20],'String','Counter');
handles.CounterBox = uicontrol('Style','text','Position',[130 200 60 20],'String','1');
%// Content of A
handles.TextTitle = uicontrol('Style','text','Position',[50 170 60 20],'String','Content');
handles.TextBox = uicontrol('Style','text','Position',[130 170 60 20],'String',handles.A{handles.counter});
%// Pushbutton to increment counter/content
handles.PushButton = uicontrol('Style','push','Position',[130 100 80 40],'String','Update counter','Callback',#(s,e) UpdateCallback);
guidata(hFig,handles);
%// Pushbutton callback
function UpdateCallback
%// Update counter
handles.counter = handles.counter + 1;
%// If maximum value possible, set back to 1.
if handles.counter == numel(handles.A)+1;
handles.counter = 1;
end
%// Update text boxes
set(handles.CounterBox,'String',num2str(handles.counter));
set(handles.TextBox,'String',handles.A{handles.counter});
guidata(hFig,handles);
end
end
Sample screenshot of the GUI:
As the user presses the button, the counter is incremented and the "content box" is updated.
Hope this helps!
As a side note, I think the error you got above was due to this command:
handles.pushbutton1 = handles.pushbutton1text(new_count);
here you assigned a string to the pushbutton but later you try to modify its String property and Matlab does not like it.
I have the following code, pasted below. I would like to change it to only average the 10 most recently filtered images and not the entire group of filtered images. The line I think I need to change is: Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;, but how do I do it?
j=1;
K = 1:3600;
window = zeros(1,10);
Yout = zeros(10,column,row);
figure;
y = 0; %# Preallocate memory for output
%Load one image
for i = 1:length(K)
disp(i)
str = int2str(i);
str1 = strcat(str,'.mat');
load(str1);
D{i}(:,:) = A(:,:);
%Go through the columns and rows
for p = 1:column
for q = 1:row
if(mean2(D{i}(p,q))==0)
x = 0;
else
if(i == 1)
meanvalue = mean2(D{i}(p,q));
end
%Calculate the temporal mean value based on previous ones.
meanvalue = (meanvalue+D{i}(p,q))/2;
x = double(D{i}(p,q)/meanvalue);
end
%Filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
end
end
end
% for k = 2:10
% subplot(5,2,k)
% subimage(Yout(k)*5000, [0 100]);
% colormap jet
% end
% pause(0.01);
end
disp('Done Loading...')
The best way to do this (in my opinion) would be to use a circular-buffer to store your images. In a circular-, or ring-buffer, the oldest data element in the array is overwritten by the newest element pushed in to the array. The basics of making such a structure are described in the short Mathworks video Implementing a simple circular buffer.
For each iteration of you main loop that deals with a single image, just load a new image into the circular-buffer and then use MATLAB's built in mean function to take the average efficiently.
If you need to apply a window function to the data, then make a temporary copy of the frames multiplied by the window function and take the average of the copy at each iteration of the loop.
The line
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
calculates a kind of Moving Average for each of the 10 bands over all your images.
This line calculates a moving average of meanvalue over your images:
meanvalue=(meanvalue+D{i}(p,q))/2;
For both you will want to add a buffer structure that keeps only the last 10 images.
To simplify it, you can also just keep all in memory. Here is an example for Yout:
Change this line: (Add one dimension)
Yout = zeros(3600,10,column,row);
And change this:
for q = 1:row
[...]
%filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(i,k,p,q) = y.^2;
end
YoutAvg = zeros(10,column,row);
start = max(0, i-10+1);
for avgImg = start:i
YoutAvg(k,p,q) = (YoutAvg(k,p,q) + Yout(avgImg,k,p,q))/2;
end
end
Then to display use
subimage(Yout(k)*5000, [0 100]);
You would do sth. similar for meanvalue