I'd like to save matrices which are input via GUI pushbuttons in a 3D matrix. for example: I click button 1 a 2-2 matrix is put in the first slice of the 3D matrix. I than click button 3 and a different 2-2 matrix is put in the second slice. SO on and so on. I hope this is clear enough. The problem I have is that I'm not an experienced programmer. I currently initialize a zeros matrix as follows in the opening func:
storageMatrix = ones(2,2,100);
setappdata(0, 'storageMatrix', storageMatrix);
I have put a function updateStorageMatrix in the main script like this, mind you this isn't finished yet.
function updateStorageMatrix
storageMatrix = getappdata(0, 'storageMatrix');
and than when I look at my code of pushbutton 1 for example it looks like this:
% --- Executes on button press in Add_Straightduct.
function Add_Straightduct_Callback(hObject, eventdata, handles)
%prompt command for k number and length
prompt = {'k0:','Length:'};
dlg_title = 'Straight Duct specs';
num_lines = 1;
SDelements = {'0','0'};
Straightduct = inputdlg(prompt,dlg_title,num_lines,SDelements)
%insert values in function
sizeStorageMatrix = size(getappdata(0,'storageMatrix')); %get size of the storage matrix
dimT = sizeStorageMatrix(1,3); %take the number of matrices
if dimT==1
straightDuct = straight_duct(str2num(SDelements{1}), str2num(SDelements{2}), Mach_Frange(1,1))
setappdata(handles.updateStorageMatrix,'storageMatrix', storageMatrix(1:2, 1:2, 1))=straight_duct(str2num(SDelements{1}), str2num(answer{2}), Mach_Frange(1,1))
dimT+1
else
setappdata(0,'storageMatrix', storageMatrix(1:2, 1:2, dimT+1))=straight_duct(str2num(SDelements{1}), str2num(answer{2}), Mach_Frange(1,1))
dimT+1
end
the straight_duct() is a function I used in the script when calculating the mufflers, I have several of those functions, I am not sure if that's the way to work when using GUI. I just hope you get the idea of what I'm trying to achieve and help me on my way. So I can actually make a UI for my script :)
This assumes you've initialized the storageMatrix elsewhere in the GUI like this...
handles.storageMatrix = zeros(2,2,100);
guidata(hObject,handles); % Must call this to save handles so other callbacks can access the new element "storageMatrix"
Then in your first button's callback...
% --- Executes on button press in Add_Straightduct.
function Add_Straightduct_Callback(hObject, eventdata, handles)
.
. % Whatever initializations you need to do
.
localStorageMatrix = handles.storageMatrix; %load the storageMatrix being used by other callbacks/functions
.
. % Whatever you need to do to generate the new 2x2 matrix "slice"
.
localStorageMatrix(:,:,end+1) = newSlice; % appends the new slice to the end of the, indexing using colons assumes newSlice is of the same first and second dimension as other slices in localStorageMatrix
handles.storageMatrix = localStorageMatrix; % overwrite the storageMatrix in handles with the contents of the new localStorageMatrix
guidata(hObject,handles); % save the handles struct again now that you've changed it
Alternatively, you could have just used the handles.storageMatrix throughout, without including a localStorageMatrix but I've included it for emphasis.
Related
I have code that uses Wolff's Algorithm to simulate the XY Model in MATLAB and I want to implement a pcolor/color map to demonstrate each spin according to their angles across the system. But I want it to be live and changing as the angles change.
Any idea how to do this?
This is an example of how I want it to look https://i.stack.imgur.com/aSp7s.png
If you save each snapshot of the lattice in a cell array A{t}, you can use the following function to view and save it as a video (if fileName is not empty, the function saves an mp4 video).
Another option is to adapt the function view_lattice to run your simulation (which, honestly, I wouldn't recommend, for performance issues). I will mark where you should edit for doing a "live" simulation
This is at least MATLAB R2019b (although it may be compatible with earlier versions, but no guarantee).
File view_lattice.m
function view_lattice(A,fileName)
% for a 'live' simulation, you will have to remove A from the input
% parameters and add the ones you need for the XY Wolff algorithm,
% which will be used to calculate each configuration A in the time loop below
% you will also need to remove the assert statements for 'live' simulation
%
% otherwise, you save snapshots from your simulation
% and use this function as is
%
% A -> A{k}[m,n] snapshot k containing the angles of spins in lattice site at row m and col n
% fileName -> if contains string, then records a video with the snapshots and name it with this string
assert(iscell(A) && all(cellfun(#(a)isnumeric(a) && ismatrix(a),A)),'A must be cell of numeric matrices');
assert(ischar(fileName),'fileName must be either an empty char or contain a file name');
recordVideo = ~isempty(fileName);
if recordVideo
vw = setup_video(fileName);
else
vw = [];
end
% setting some default axis properties to speed-up plotting
set(0,'DefaultAxesPlotBoxAspectRatio',[1 1 1],'DefaultAxesDataAspectRatioMode','manual','DefaultAxesDataAspectRatio',[1,1,1],'DefaultAxesNextPlot','replace');
fh = figure;
ax=axes;
for t = 1:numel(A) % for 'live' simulation, this loop should be the time loop
% here you calculate the new configuration A
% and call the function below with A instead of A{t}
vw = record_frame(vw,fh,ax,A{t},t,recordVideo);
end
% any video to close?
if recordVideo
vw.close();
end
end
function vw = record_frame(vw,fh,ax,A,t,recordVideo)
imagesc(ax,A);
title(ax,sprintf('snapshot %g',t)); % if you want, y
axis(ax,'square');
daspect(ax,[1,1,1]);
pause(0.01);
if recordVideo
vframe = getframe(fh);
vw.writeVideo(vframe);
end
end
function vw = setup_video(fileName)
vid_id = num2str(rand,'%.16g');
vid_id = vid_id(3:6);
vid_id = [fileName,'_',vid_id];
% Initialize video
vw = VideoWriter([vid_id,'.mp4'], 'MPEG-4'); %open video file
vw.Quality = 100;
vw.FrameRate = 16;
vw.open();
end
Test script: test.m
clearvars
close all
A = cell(1,30);
for t = 1:numel(A)
% creating a sequence of random snapshots only for illustration
A{t} = rand(20,20);
end
% viewing the animation and saving it as a video with name test
view_lattice(A,'test');
Output
I'm building a MATLAB GUI using GUIDE for processing medical images (brain tumor segmentation on MRI scans). As a preprocessing step, the program coregisters different scans, which looks like this:
I now want to display crosshairs on both images as a visual check of the coregistration. The crosshairs should be linked to one another, such that they point to the same pixel in both images. Moreover, it should move when hovering over (or clicking on) one of the images. This is what I want to achieve:
Does a build-in MATLAB function exist that can achieve this? Or, if I have to write it myself, how would one tackle this problem?
I'll use a Toy GUI in order to show how it works :
Let's first try to make it work for the first image only. What you want to achieve is :
When the user clicks on the figure, we want to have access to the location of the mouse click.
Then we want to check if the click was located inside the first image
If it is, we want to update the position of the crossbar, which will be represented by two lines overlayed on the image and crossing at the selected point.
Step 0 : Initial settings
You want to make sure of some details first :
Make sure you add a call to hold on after both your imshow calls, otherwise the crossbars will delete your image instead of overlaying on it.
Step 1 : Getting the position of the mouse click
In your GUI opening function (here it will be SuperDuperGUI_OpeningFcn), you want to add a call to :
set(gcf, 'WindowButtonDownFcn', #getMousePositionOnImage);
This will trigger the function getMousePositionOnImage everytime the user clicks inside your GUI.
Then, you want to add and implement the function getMousePositionOnImage :
function getMousePositionOnImage(src, event)
% Fetch the current handles structure
handles = guidata(src);
% Get the coordinate IN THE AXES UNITS OF AXES1 (Here I chose to define them
% as pixels) of the point where the user clicked
cursorPoint = get(handles.axes1, 'CurrentPoint')
Step 2 : Check if the mouse click is inside the first image
Still in the getMousePositionOnImage function :
% Get the Position of the first image (We're only interested by the width
% and height of the axes1 object)
Img1Pos=get(handles.axes1,'Position')
% Check if inside
if(cursorPoint(1,1)<Img1Pos(3)&&cursorPoint(1,2)<Img1Pos(4)&&cursorPoint(1,1)>=0&&cursorPoint(1,2)>=0)
% Do stuff
end
Step 3 : If the click was inside the first image, update the position of the crossbar
% Check if inside
if(cursorPoint(1,1)<Img1Pos(3)&&cursorPoint(1,2)<Img1Pos(4)&&cursorPoint(1,1)>=0&&cursorPoint(1,2)>=0)
Lines=findobj('Type','line','Parent',handles.axes1);
if isempty(Lines)
% If Lines is empty, we need to create the line objects
line([0 Img1Pos(3)],[cursorPoint(1,2) cursorPoint(1,2)],'Color','g','Parent',handles.axes1);
line([cursorPoint(1,1) cursorPoint(1,1)],[0 Img1Pos(4)],'Color','g','Parent',handles.axes1);
else
% If not, we just update the fields XData and YData of both Lines
Lines(1).XData=[0 Img1Pos(3)]; % Unnecessary but I'll leave it there for clarity
Lines(1).YData=[cursorPoint(1,2) cursorPoint(1,2)];
Lines(2).XData=[cursorPoint(1,1) cursorPoint(1,1)];
Lines(2).YData=[0 Img1Pos(4)]; % Unnecessary but I'll leave it there for clarity
end
end
Result :
Now I'll let you do the last part, which involves linking the two crossbars. Instead of only checking if the click was on first image, you'll check both separately. Then, if it is in one of the image, you'll update both crossbar to the position of the click in the right axes object
Edit
The code below is inspired by the answer of BillBokeey, for which I'm very grateful.
First, do steps 0 and 1 of BillBokeey's solution. Then I put this function in my code:
function getMousePositionOnImage(src, event)
% Fetch the current handles structure
handles = guidata(src);
% Get the coordinate IN THE AXES UNITS OF AXES1 (Here I chose to define them
% as pixels) of the point where the user clicked
cursorPoint1 = get(handles.axes2, 'CurrentPoint');
cursorPoint2 = get(handles.axes3, 'CurrentPoint');
% Get the Position of the first image (We're only interested by the width
% and height of the axes1 object)
Img1Pos = getpixelposition(handles.axes2);
Img2Pos = getpixelposition(handles.axes3);
XLim1 = get(handles.axes2, 'XLim');
YLim1 = get(handles.axes2, 'YLim');
XLim2 = get(handles.axes3, 'XLim');
YLim2 = get(handles.axes3, 'YLim');
% Check if inside
if (cursorPoint1(1)<XLim1(2) && cursorPoint1(2)<YLim1(2) && cursorPoint1(1)>=XLim1(1) && cursorPoint1(1)>=YLim1(1))
Lines1=findobj('Type','line','Parent',handles.axes2);
Lines2=findobj('Type','line','Parent',handles.axes3);
if isempty(Lines1)
% If Lines is empty, we need to create the line objects
line(XLim1,[cursorPoint1(1,2) cursorPoint1(1,2)],'Color','g','Parent',handles.axes2);
line([cursorPoint1(1,1) cursorPoint1(1,1)],YLim1,'Color','g','Parent',handles.axes2);
line(XLim2,[cursorPoint1(1,2) cursorPoint1(1,2)],'Color','g','Parent',handles.axes3);
line([cursorPoint1(1,1) cursorPoint1(1,1)],YLim2,'Color','g','Parent',handles.axes3);
else
% If not, we just update the fields XData and YData of both Lines
Lines1(1).XData=XLim1; % Unnecessary but I'll leave it there for clarity
Lines1(1).YData=[cursorPoint1(1,2) cursorPoint1(1,2)];
Lines1(2).XData=[cursorPoint1(1,1) cursorPoint1(1,1)];
Lines1(2).YData=YLim1; % Unnecessary but I'll leave it there for clarity
Lines2(1).XData=XLim2; % Unnecessary but I'll leave it there for clarity
Lines2(1).YData=[cursorPoint1(1,2) cursorPoint1(1,2)];
Lines2(2).XData=[cursorPoint1(1,1) cursorPoint1(1,1)];
Lines2(2).YData=YLim2; % Unnecessary but I'll leave it there for clarity
end
elseif (cursorPoint2(1)<XLim2(2) && cursorPoint2(2)<YLim2(2) && cursorPoint2(1)>=XLim2(1) && cursorPoint2(1)>=YLim2(1))
Lines1=findobj('Type','line','Parent',handles.axes2);
Lines2=findobj('Type','line','Parent',handles.axes3);
if isempty(Lines2)
% If Lines is empty, we need to create the line objects
line(XLim1,[cursorPoint2(1,2) cursorPoint2(1,2)],'Color','g','Parent',handles.axes2);
line([cursorPoint2(1,1) cursorPoint2(1,1)],YLim1,'Color','g','Parent',handles.axes2);
line(XLim2,[cursorPoint2(1,2) cursorPoint2(1,2)],'Color','g','Parent',handles.axes3);
line([cursorPoint2(1,1) cursorPoint2(1,1)],YLim2,'Color','g','Parent',handles.axes3);
else
% If not, we just update the fields XData and YData of both Lines
Lines1(1).XData=XLim1; % Unnecessary but I'll leave it there for clarity
Lines1(1).YData=[cursorPoint2(1,2) cursorPoint2(1,2)];
Lines1(2).XData=[cursorPoint2(1,1) cursorPoint2(1,1)];
Lines1(2).YData=YLim1; % Unnecessary but I'll leave it there for clarity
Lines2(1).XData=XLim2; % Unnecessary but I'll leave it there for clarity
Lines2(1).YData=[cursorPoint2(1,2) cursorPoint2(1,2)];
Lines2(2).XData=[cursorPoint2(1,1) cursorPoint2(1,1)];
Lines2(2).YData=YLim2; % Unnecessary but I'll leave it there for clarity
end
end
I am working in image processing task using matlab,I have made a slider inside a dialog to apply and update gaussian blur filter on an image which is shown in axes
but it can not apply it,it shows that error
Error in ==> MatlabTestProject>name at 392
axes(handles.axes4);
??? Error while evaluating uicontrol Callback
this is my code
function mygui()
out = dialog('WindowStyle', 'normal', 'Name', 'My Dialog','Resize','off');
hSlider = uicontrol('Style','slider','Min',3,'Max',15,'Value',3,'Callback',#gaussian_blur);
%hListener = addlistener(hSlider,'Value','PostSet',#(s,e) disp('hi'));
function gaussian_blur(s,e,handles)
global imag;
slider_value = get(s,'Value');
slider_value=round(slider_value);
%display(slider_value);
%disp('hello')
%create filter
%sliderValueTxt=num2str(slider_value);
%set(handles.kSizeValueText ,'String',sliderValueTxt);
h = fspecial('gaussian', slider_value,0.5);
imag=imfilter(imag,h,'conv');
axes(handles.axes4);
imshow(imag)
% --------------------------------------------------------------------
function gaussianBlur_Callback(hObject, eventdata, handles)
% hObject handle to gaussianBlur (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
gaussian_dialog_Gui();
You're actually really close! All you need to do is include handles as an argument to the function gaussian_blur when defining the slider's listener object callback.
i.e replace this line: (it looks like a test line though)
hListener = addlistener(hSlider,'Value','PostSet',#(s,e) disp('hi'));
with something like this:
hListener = addlistener(hslider,'Value','PostSet',#(s,e) gaussian_blur(handles));
Just to be sure it works I created a test GUI programmatically using an axes and a slider and it works very well! Actually I changed a bit the filter to see an effect on my test image, but it should work as well in your case:
function GaussianSlider()
clear
clc
close all
handles.Image = imread('peppers.png');
handles.fig = figure('Position',[500 500 600 600],'Units','pixels');
handles.axes1 = axes('Units','pixels','Position',[50 100 400 400]);
handles.slider = uicontrol('Style','slider','Position',[50 50 400 20],'Min',3,'Max',15,'Value',3);%// I commented this for the purpose of demonstration. 'Callback',#gaussian_blur(handles));
%// That's the important part: add 'handles' as input argument to
%// gaussian_blur.
handles.Listener = addlistener(handles.slider,'Value','PostSet',#(s,e) gaussian_blur(handles));
imshow(handles.Image,'Parent',handles.axes1);
guidata(handles.fig);
function gaussian_blur(handles)
slider_value = round(get(handles.slider,'Value'));
%// I modified a bit the filter to see the effect
h = fspecial('gaussian',slider_value,slider_value);
handles.Image=imfilter(handles.Image,h,'conv');
axes(handles.axes1);
imshow(handles.Image)
end
end
If we look at 2 screenshots (i.e. 2 different slider positions):
and after moving the slider:
That's it! Hope that helps! If something is unclear please tell me.
Oh and in case you do not know: The actual callback of a slider is only executed when you release the button or press either arrow. As long as you hold the slider and move it, it's only the listener's callback that will be executed.
I would like to know if some of you know of a way to automatically title plots with the name of the object plotted
so that for intance when I plot supermatrix(5:10,:,2:3)
the title (or the legend ..) on the plot says "supermatrix(5:10,:,2:3)"
thanks
Is this for debugging purposes? If not then I suggest you tell us your overall motivation because someone might be able to suggest a more robust method, but this might get you started:
vname = #(x)inputname(1); %//from here: https://www.mathworks.com/matlabcentral/newsreader/view_thread/251347
plot(supermatrix(5:10,:,2:3))
title(vname(supermatrix))
Although to be honest I cannot imagine why this would ever be useful
I think this does what you want and remains pretty flexible:
function h = plotwithtitle( plotstring, varargin )
argstoplot = evalin('caller', ['{', plotstring, '}']);
h = plot( argstoplot{:}, varargin{:} );
title(plotstring);
end
The following examples all work for me:
supermatrix=rand(10,10);
x=1:10;
y=rand(1,10);
plotwithtitle('supermatrix');
plotwithtitle('supermatrix(5:10,:)');
plotwithtitle('x, y');
plotwithtitle('x, y', '--r');
plotwithtitle('1:10', 'r');
plotwithtitle('rand(1,10)');
I've modified the function dfig originally created by F.Moisy for creating docked figures in order to have the command used for plotting show up in the figure name.
The idea is to read the last command in the command history and use that to generate the figure title.
function hh = dfig(varargin)
%DFIG Create docked figure window
% DFIG, by itself, creates a new docked figure window, and returns its
% handle.
%
% DFIG(H) makes H the current figure and docks it. If Figure H does not
% exist, and H is an integer, a new figure is created with handle H.
%
% DFIG(H, name, value,...) reads additional name-value pairs. See
% doc(figure) for available otions.
%
% DFIG will parse the command line input and use the text following dfig
% as figure name. E.g. calling dfig,plot(x(1:3),y(2:2:end)) results in
% the name "plot(x(1:3),y(2:2:end))"
% F. Moisy, moisy_at_fast.u-psud.fr
% Revision: 1.00, Date: 2007/09/11
% Modified (a lot) by Jonas
if nargin==0
h=figure; % create a new figure
else
% call figure with varargin
figure(varargin{:})
h = gcf;
end
if ~any(strcmp('name',varargin(1:2:end)))
% if no name has been supplied: try to use function call
javaHistory=com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory;
if ~isempty(javaHistory)
lastCommand = javaHistory(end).toCharArray';
funCall = regexp(lastCommand,'dfig\s*[,;]\s*(.*)$','tokens','once');
else
funCall = [];
end
if ~isempty(funCall)
if isnumeric(h)
set(h,'Name',[num2str(h),': ',funCall{1}],'NumberTitle','off')
else % HG2
h.Name = sprintf('%i: %s',h.Number,funCall{1});
h.NumberTitle = 'off';
end
end
end
set(h,'WindowStyle','docked'); % dock the figure
if nargout~=0 % returns the handle if requested
hh=h;
end
I want to create a GUI with two push buttons. One represents the Next and another is back. These two buttons should switch the index of for loop. For example, when I press the next button it should go to next iteration (i+1) and by pressing back, it goes to (i-1).. I really appreciate for any answer.
You won't be able to change the loops index from a GUI.
The better approach would be to use a while loop, wait for one of the pushbuttons and get the new index from the figure:
hFig = figure(..) % create your figure somewhere here
setappdata(hFig, 'loopIndex', 0); % assuming you start at 0
while 1:
uiwait(hFig); % this will wait for anyone to call uiresume(hFig)
loopIndex = getappdata(hFig, 'loopIndex');
% do whatever you're doing with the index
% ...
% ...
% stop loop at some point:
if <end-condition>: % pseudo-code, obviously
break
And a pushbutton callback like:
function button_callback(hObject, evt, handles):
hFig = ancestor(hObject, 'figure');
% increment the loop index:
setappdata(hFig, 'loopIndex', 1+getappdata(hFig, 'loopIndex'))
% proceed with the loop code
uiresume(hFig);