I have a piece of code that is 300 lines long. There is 3 different instances of imshow throughout the code that displays figures as the code is run..
The GUI I am creating will be very simple. Currently I have a push button that initiates the m file.
I am trying to get the images to be displayed within the GUI that I am creating and not in separate Figure windows.
I have being looking at tutorials online but cant get a quick fix for my problem, they all get a bit convoluted and I cant figure out what exactly to do.
I have 3 axis inserted onto the GUI, In the "view callbacks" for each axis I can createfcn, deletefcn and buttonDownFcn. When I createFcn it gives me a hint to "place code in OpeningFcn to populate axes1" in the auto generated code.
I have tried to do this but I am not able to find the correct place to write the code.
Can somebody tell me if I am going in the correct direction or if I have it wrong.
Thanks
In order to display these images, you need to declare the parent in imshow. The parent is what you want to act as the canvas for your image, and in your case will be an axes.
I created a very simple gui with three axes and a push button. MATLAB named my axes axes1, axes2 and axes3. Guide saves the handles to these axes so that you can interact with them throughout your gui code. For example, you mentioned the opening function... here is mine with a call to imshow (the only lines I added were the last three ones):
% --- Executes just before myGUI is made visible.
function myGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for myGUI
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes myGUI wait for user response (see UIRESUME)
% uiwait(handles.figure1);
imshow('myImage1.png', 'Parent', handles.axes1)
imshow('myImage2.png', 'Parent', handles.axes2)
imshow('myImage3.png', 'Parent', handles.axes3)
Notice that I can grab the handles of my axes and then declare them to be the parents for the results of my imshow call.
If you're not sure what the names of your handles are, you can check in the GUI editor by right clicking, looking at the property inspector, and the tag property.
If you want to perform a similar operation for when you click on your pushbutton, right click on the button in the editor, and click on View Callbacks -> Callback, and you can add your imshow code there.
Good luck.
If I understand correctly you just want your images to appear in the axes instead of a figure. Try setting the focus to the axes itself before showing the image.
axes(1);%you may need to change the one to your axes handle.
imagesc(imageToBeDisplayed);
axes(2);
imagesc(secondImage);
axes(3);
imagesc(thirdImage);
This way before you call imagesc you make sure your program knows where to send the image. Otherwise it may just create a figure.
Related
I am creating a GUI in Matlab's Guide which should display a video and a plot saved in a .fig file. I am currently trying to open the plot in an axes element and while I know axes cannot be a container, the possibility of saving the plot in a another object and feeding that object to axes seems like a solution, but I don't know how to do that due to limited Matlab knowledge. Here is the only code I have for the button at the moment which allows me to open a file from my local directory.
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
axes(handles.axes1);
[file,path] = uigetfile('*.fig');
[file,path] = uigetfile('*.fig'); only gets the path and name of the file that was selected, it doesn't load the file. To load the file you want to use,
hfig = openfig(fullfile(path,file));
However, since you don't really want to see the figure you most likely want to use the optional input
hfig = openfig(fullfile(path,file),'invisible');
to load the figure but make it invisible.
Then you'll need to move the image from the axes in hfig to the axes in your UI. This can be achieved in multiple ways, one of which is the use of copyobj.
I have a very simple GUI made in guide where i have a plot function initiated by a pushbutton which plots a scatter plot in axes (called Method1axes1):
handles.plot = scatter(X,Y, 'parent', handles.Method1axes1);
Now I want the user to be able to click the axes (plot) to get en new larger figure. I tried the below code which is working if i DON'T plot in the axes first. As soon as I run the plot function the scatterplot appears in Method1axes1 but I can no longer click the figure.
% --- Executes on mouse press over axes background.
function Method1axes1_ButtonDownFcn(hObject, eventdata, handles)
figure
scatter(X,Y);
What am I doing wrong?
This is a kind of special case for MATLAB, and it is not extremely well documented.
There are 2 things you need to consider:
1) The most obvious part. When you plot something in your axes, the plot is on the foreground. So when you click on your axes, the top plot intercept that click and tries to process it. You need to disable the mouse click capture from the plot/scatter/image objects you have in your axes. For that, you have to set the HitTest property of your scatter object to 'off'. (recent MATLAB version have changed the name of this property, it is now called PickableParts).
2) Much less obvious and documented. It used to be in the doc for the axes ButtonDownFcn callback but it is not explained anymore (although the behaviour persist). This is what I could find on old forums:
When you call PLOT, if the axes NextPlot property is set to 'replace'
(which it is by default) most of the properties of the axes (including
ButtonDownFcn) are reset to their default values.
Change the axes NextPlot property to 'replacechildren' to avoid this,
or set the ButtonDownFcn after calling PLOT, or use the low-level LINE
function instead of the higher-level PLOT function.
This is also discussed and explained here: Why does the ButtonDownFcn callback of my axes object stop working after plotting something?
For your case, I tried set(axe_handle,'NextPlot','replacechildren') and it works ok to let the mouse click reach the ButtonDownFcn, but unfortunately it creates havoc with the axes limits and LimitModes ... so I opted for the second solution, which is to redefine the callback for ButtonDownFcn after every plot in the axes.
So in summary, your code for the pushbutton1_Callback should be:
function pushbutton1_Callback(hObject, eventdata, handles)
% Whatever stuff you do before plotting
% ...
% Plot your data
handles.plot = scatter(X,Y, 'parent', handles.Method1axes1);
% Disable mouse click events for the "scatterplot" object
set(handles.plot,'HitTest','off') ;
% re-set the "ButtonDownFcn" callback
set(handles.Method1axes1,'ButtonDownFcn',#(s,e) Method1axes1_ButtonDownFcn(s,e,handles) )
And for your axes mouse click event, you might as well keep the handle of the new generated objects:
function Method1axes1_ButtonDownFcn(hObject, eventdata, handles)
handles.newfig = figure ;
handles.axes1copy = copyobj( handles.Method1axes1 , handles.newfig ) ;
Note that instead of plotting a new set, I simply use the copyobj function, very handy when you need to reproduce a plot.
Illustration:
If you want to set the figure/graph to enlarge and shrink on mouse
scroll/click, then just set the zoom property of the required axes in
OpeningFcn within the m file.
For example within the OpeningFcn in the GUI's m file, put the below code. Please ensure that you put the below code within the OpeningFcn function.
h1 = zoom(handles.Method1axes1);
h1.Enable = 'on';
Now, on each mouse scroll/click, you would be able to zoom in/out the graphs.
A sample screenshot of openingFcn for a GUI named ZoomAxesDemo is given below.
I am creating a GUI with MATLAB's GUIDE. Say, the GUI consists of an axis called axis1
and a slider called slider1. Further say I wanted to plot something (e.g. a box) into axis1 and change the box's height with the slider.
I tried doing this by adding a listener to the slider like so:
hListener = addlistener(handles.slider1,'Value','PostSet',#(src,evnt)boxHeightChange(src,evnt, handles.figure1));
in the GUI's opening function. I further defined:
function boxHeightChange(src, event, figname)
handles = guidata(figname);
% delete "old" box
delete(handles.plottedHandle);
% bring axis in focus
axes(handles.axes1);
% plot the new box (with changed size)
hold on; boxHandle = plotTheBox(event.AffectedObject.Value); hold off
handles.plottedHandle = boxHandle;
% update saved values
guidata(figname, handles);
end
This works, but always opens a new figure to plot the resizable box into instead of drawing into handles.axes1. I do not understand why, since I call axes(handles.axes1); and hold on;
Any idea that might explain the behavior?
I will post a solution to my own question.
Apparently the Callback of a listener is not declared as a "GUI Callback" which is why the GUI can not be accessed from within boxHeightChange if the GUI option "command-line accessibility" is not set to "On".
That means: In GUIDE go to Tools -> GUI options and set "Command-line accessibility" to "On".
Most plotting functions let you pass a name value pair 'Parent', ah where ah specifies the axes to plot on. I think this is the best way to handle your problem. Your actual plotting command seems to be wrapped in the plotTheBox function, so you will have to pass the axes handle in somehow.
Your plot command will look something like this:
plot(a,'Parent',handles.axes1)
You solved the problem a different way on your own, but I think you should do it my way because it's more explicit and it's less likely to lead to unforeseen problems.
I'm working on a GUI (created with guide in Matlab) with two axes and two pushbuttons. When the user presses pushbutton1 I want to display an image on axes1 and when the user presses pushbutton2 I want to display an image on axis2.
This is my code:
function pushbutton1_Callback(hObject, eventdata, handles)
axes(handles.axes1);
imagesc(table(:,:,1));colormap(gray),axis('square');
guidata(hObject,handles);
function pushbutton2_Callback(hObject, eventdata, handles)
axes(handles.axes2);
imagesc(table(:,:,1));colormap(gray),axis('square');
guidata(hObject,handles);
This code works fine only when the user presses the buttons for the first time. When he does it again, the program crashes and I get the following error: "Reference to non-existent field 'axes1'".
When I display all handles, I see that the handle "axes1" is missing indeed.
I don't get this error when I change the NextPlot property of my axes to "new". However, in that case I can't display images at all. I mean I don't get errors, but I one forth of the image (top right corner) is grey and the rest is white. The plotrange in both dimensions is (0,1), instead of (0,2000). It seems to me that this is only one pixel of my image.
What am I doing wrong?
I had a similar problem. I used a timer object and passed the different axes in a handle object which worked. My application was getting data from multiple cameras in realtime.
With Guide I made a Matlab Gui that have 10 Axes in which i want to display images, in all of them at once, after i press a Button.
I made a separate .m file with function Load_Write_Img_Results(img_index) that i call from the Button Callback which have the following code:
for i = 1 : 10
handles_imgOut = findobj('Tag', ['imgOut' num2str(i)]);
set(handles_imgOut, 'HandleVisibility', 'ON');
axes(handles_imgOut);
image(imgs_data{img_index(i)});
...
end
Every time when i run the main Gui and press the button for the first time, images are displayed in all axes, so everything works ok.
The problem appear when i press the button for the second time and i get this error:
Error using axes
Invalid object handle
on this line:
axes(handles_imgOut);
When debugging, i saw that after handles_imgOut = findobj('Tag', ['imgOut' num2str(i)]); the handles_imgOut is not getting any value and is empty, so it's obvious that error.
Is there any chance i can't get handles for axes at the second press of the button?
Also, i want to know how can i solve this warning from Matlab:
Calling AXES(h) in a loop can be slow. Consider moving the call to AXES outside the loop.
Thanks in advance, any suggestions are welcome!
[SOLUTION]:
for i = 1 : 10
handles_imgOut = findobj('Tag', ['imgOut' num2str(i)]);
set(handles_imgOut, 'HandleVisibility', 'ON');
axes(handles_imgOut);
image(imgs_data{img_index(i)});
set(gca, 'Tag', ['imgOut' num2str(i)]); //! renew the tag
...
end
I'm fairly new to GUIDE and I've encountered similar problems, with the graph not being updated more than once / axes not found.
In the end, I used the following approach, which I hope can be useful to you too:
% I get my axes directly from the handles object, instead of using findObj:
graph1 = handles.axes1;
graph2 = handles.axes2;
% clear axes
cla(graph1);
cla(graph2);
% showTrial is my function that draws the graphs -
%notice that I used handles to store other variables as well (.data, .trials)
showTrial(handles.data, handles.trials(1), graph1, graph2)
To sum it up:
don't use findObj, get your axes from handles (it should automatically contain them as imgOut1,imgOut2, etc.)
pass the axes to your drawing function or pass directly the handles variable e.g. Load_Write_Img_Results(img_index, handles)
The fact that it works on the first button press, but not thereafter hints that
image(imgs_data{img_index(i)});
opens new axes instead of drawing into the existing ones. Since the new axes are not initialized with your tags, findobj will not find them. Either
(1) make sure to hold the original axes by placing a hold on command right after their creation,
or
(2) renew the tag right after the image command by
set(gca, 'Tag', ['imgOut' num2str(i)]);