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.
Related
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 trying to create a Matlab GUI using GUIDE. I want to insert a picture with the picture shown only while I am pressing a button (Callback function) and show the default picture once the button is released. How can I implement this? I use axes to display the picture at the mentioned location
function mc_right_Callback(hObject, eventdata, handles)
% hObject handle to mc_right (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
matlabImage2 = imread('Coor2.png');
imshow(matlabImage2, 'Parent', handles.axes7);
%Vxm_Port_Send(handles.port_handle,sprintf('F,C,I3M-%d,R',handles.x_steps)); % Move along +x (right)
The problem is that MATLAB uicontrols don't allow you to create separate callback functions that execute on a button press or button release. For example, a push button will execute its Callback function on a button release. It also has a ButtonDownFcn function that will execute on a button press, but this callback is only active when the Enable property is set to 'off' or 'inactive', in which case the Callback function is disabled. In other words, you can't use the ButtonDownFcn and Callback together to get responses to both button presses and releases, respectively.
However...
The figure window does have a way to specify separate callback functions for button presses, button releases, and even mouse motion or scroll wheel activity. This is how I usually overcome shortcomings in uicontrol behavior: I define figure-level callbacks that execute when they are over certain parts of the window. Here's an example:
function press_release
% Load a sample image:
imgData = imread('peppers.png');
% Create the figure and graphics objects:
hFigure = figure('WindowButtonDownFcn', #press_fcn, ...
'WindowButtonUpFcn', #release_fcn);
hImage = image(imgData, 'Visible', 'off');
hButton = uicontrol(hFigure, 'Style', 'pushbutton', ...
'Position', [10 10 30 30], ...
'Enable', 'inactive');
function press_fcn(~, ~)
if isequal(hButton, get(hFigure, 'CurrentObject'))
set(hImage, 'Visible', 'on');
set(hButton, 'Value', 1);
end
end
function release_fcn(~, ~)
set(hImage, 'Visible', 'off');
set(hButton, 'Value', 0);
end
end
When you run the above, it will create a window with an axes and a small button in the lower left corner. The button has no callbacks defined. When you click the mouse anywhere but over the button nothing happens. However, when you click the mouse over the button (making it the CurrentObject for the figure) the image will become visible and the button will depress while you are holding the button down. Releasing the button makes the image invisible again and the button appears normal. Essentially, the button is just a dummy that does nothing at all except give the user the illusion that they are pressing it to make things happen. It's really the figure callbacks doing the work.
In Matlab GUI, I need a user mouse input as a rectangle that I have to plot on the axes1.
For this, I have code below:
axes(handles.axes1);
filename = 'A';
img = imread(filename);
imshow(img);
hold on;
rect_cord = getrect(handles.axes1);
rectangle('Curvature', [0 0],'Position', [rect_cord],'EdgeColor',[1 0 0]);
This code runs fine (takes user input and plots the rectangle). However, for some images I don't want to get the user input from mouse (using getrect). In this case, how to skip the getrect function and move on to next image?
I have a pushbutton ("next"), I want to show next image when push button is pressed instead of taking user input.
Thanks,
I will try to rephrase and modify a bit: you want to draw a rectangle only if one clicks on the axes or image.
Therefore:
First of all I would suggest to put the getrect-part into another function. This function should only be triggered if one clicks on the image. The so called "ButtownDownFcn" seems to be suitable for this job. When using GUIDE, you will find it double-clicking on the axes within the property-inspector that is popping up.
Then put the getrect-part into this function:
function axes1_ButtonDownFcn(hObject, eventdata, handles)
% hObject handle to axes1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
rect_cord = getrect(handles.axes1);
rectangle('Curvature', [0 0],'Position', [rect_cord],'EdgeColor',[1 0 0]);
Now I thought that this is all that has to be done. But testing this with a plot or image within the axes prooved me wrong :o
Sadly one has to redirect the children of the axes to this function, because by default, it is only assigned to the background of the axes (=the blank axes).
by searching the net, I found the following solution here:
Matlab in Chemical Engineering: Interacting with your graph through mouse clicks
It works like this:
when plotting the image, you have to add the line
% and we also have to attach the function to the children, in this
% case that is the line in the axes.
set(get(gca,'Children'),'ButtonDownFcn', #mouseclick_callback)
Hope that helps!
I am quite new to MATLAB GUI programming (using GUIDE sorry) and I have the following issue: The GUI displays on an axis an image sequence stored in a cell array. I have a couple of pushbuttons and a slider to scroll through the sequence. In order to get a 'continuous slider' I use a listener, which kind of works but creates some problems:
1) When I press the slider, a figure is created and the first frame of the sequence is displayed in it, but as I move the slider the sequence is displayed in the axis of my GUI (which is what I want) and the figure becomes empty. Can anybody tell me why this figure is created and how can I avoid it?
2) Once I press the slider button and thus use the listener, all handles inside the GUI are not functionnal as Matlab does not recognize them and I'm stuck with a functionnal slider/display but I can't use the pushbuttons.
Any ideas on why this happens? Here is the code I use in the Create Function of the slider:
function slider2_Frame_Video_Callback(hObject, eventdata, handles)
hListener = addlistener(hObject,'ContinuousValueChange',#(a,b) slider2_Frame_Video_Callback(hObject, eventdata, handles)); % a and b are dummy arguments
guidata(hObject,handles)
In the slider callback, the code looks like this (basically imshow in the current axis):
axes(hAxis)
imshow(Movie{frame},'parent',hAxis);
drawnow
% This does not work either as handles.edit_FrameNumber is not recognized by Matlab
set(handles.edit_FrameNumber, 'String', frame);
guidata(hObject,handles);
Any hints are welcome thanks!
I wonder if part of the problem is that a listener is being instantiated each time the user moves the slider since the listener code is within this callback AND that the callback being provided to the listener (seems like some kind of strange back-and-forth there). So every time the user releases the mouse button after a slide, a new listener is created. This may be causing some problems with the other buttons not being responsive.
Rather than instantiating the listener there, I would do this in the Opening_Fcn of your GUI:
% --- Executes just before frameSlider is made visible.
function frameSlider_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to frameSlider (see VARARGIN)
% Choose default command line output for frameSlider
handles.output = hObject;
if ~isfield(handles,'hListener')
handles.hListener = ...
addlistener(handles.slider1,'ContinuousValueChange',#respondToContSlideCallback);
end
% Update handles structure
guidata(hObject, handles);
My GUI is named frameSlider; yours will be something else. The above creates one listener with a callback to a function that you will need to define in the same *.m file, respondToContSlideCallback.
A sample body for the callback that is to respond to the continuous slide is
% --- Executes on slider movement.
function respondToContSlideCallback(hObject, eventdata)
% hObject handle to slider1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% Hints: get(hObject,'Value') returns position of slider
% get(hObject,'Min') and get(hObject,'Max') to determine range of slider
% first we need the handles structure which we can get from hObject
handles = guidata(hObject);
% test to display the current value along the slider
disp(['at slider coordinate ' num2str(get(hObject,'Value'))]);
If you run this code, the Command Window will display continuously the slider coordinate as you move the slider from end to end.
Your above code has a Movies cell array. How is that being accessed by your callback? Is it a global variable or ..? Where does hist come from? If Movies is the result of some other function call, then it can be saved to handles too (in whichever location it gets loaded from file). I suppose you will also have to map the slider control coordinates to the number of frames that you have (though maybe you have already done this?).
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.