Matlab - Vertical moving lines in Axes GUIDE - matlab

I would like to add two vertical moving lines to the graph and depending on their position it would change the values in the boxes Start and End.
I would also like to do the other way around: by changing the values in the boxes Start and End it would move the vertical lines to the assigned positions.
I have this inside the pushbutton1_Callback
hold on;
plot(x,y);
SP = 20;
line([SP,SP],get(handles.axes1,'Xlim'),'Color','red');
I suppose I would have to create callback events for mouseButtonDown and mouseButtonUp, but I am very new to Matlab and don't know what to put in those callbacks

The way around:
by typing values in edit boxes Start and End you can plot verticle lines. In each of these edit boxes (my case edit1 and edit2) callbacks write
EDIT: now old lines are deleted
function edit1_Callback(hObject, eventdata, handles)
start=str2num(get(hObject, 'string'));
if isfield(handles,'startLine'); delete(handles.startLine); end
handles.startLine=line([start,start],ylim,'Color',[.8 .8 .8]);
guidata(hObject, handles);
function edit2_Callback(hObject, eventdata, handles)
LineEnd=str2num(get(hObject, 'string'));
if isfield(handles,'LineEnd'); delete(handles.LineEnd); end
handles.LineEnd=line([LineEnd,LineEnd],ylim,'Color',[.8 .8 .8]);
guidata(hObject, handles);

Related

How to make ginput confine to current axes for selecting a seed point

I am attaching a sample GUI codes, which has two axes with 2 images and when I use ginput to select seed point I am able to select on either axes, Is there anyway to limit the ginput to a specific axes
% --- Executes on button press in open.
function open_Callback(hObject, eventdata, handles)
% hObject handle to open (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global img1;
global img2;
img1 = imread('peppers.png');
img2 = imread('rice.png');
axes(handles.axes1);
imshow(img1,[]);
axes(handles.axes2);
imshow(img2,[]);
% --- Executes on button press in seedpointSelect.
function seedpointSelect_Callback(hObject, eventdata, handles)
% hObject handle to seedpointSelect (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global img1;
global img2;
global x;
global y;
axes(handles.axes1);
imshow(img1,[]);
[y,x] = ginput(handles.axes1);
y = round(y); x = round(x);
set(handles.xcord,'String',num2str(x));
set(handles.ycord,'String',num2str(y));
Any help on limiting ginput to a specific axes,
Thanks,
Gopi
In older versions of MATLAB you used to be able to change the HitTest property of the axes to ignore the click from ginput
set(handles.axes2, 'Hittest', 'off')
The better approach though is to use ButtonDownFcn as you have much more control over mouse events with an axes object.
From within your OpeningFcn
set(handles.axes1, 'ButtonDownFcn', #mouseCallback)
Then you'll need to create the callback function
function mouseCallback(src, evnt)
handles = guidata(src);
% Get the current point
xyz = get(src, 'CurrentPoint');
x = xyz(1,1);
y = xyz(1,2);
% Store x/y here or whatever you need to do
end
Don't use ginput, create a mouse click callback instead (ButtonDownFcn). You can set the callback to, for example, remove the callback function from the axis. In your main program, which sets the callback, you then waitfor that property to change. As soon as the user clicks, you get control back, and you can then read the location of the last mouse click (CurrentPoint). Note that the position you read out is in axis coordinates, not screen pixels. This is a good thing, it most likely corresponds to a pixel in the image displayed.

How to determine if mouse is over axes using MATLAB GUIDE

I know this question has been asked before, but I can't find any good answers. I keep stumbling upon WindowButtonMotionFcn, but I don't really understand how to use it. In my program I want to be able to click and store coordinates ONLY when the user is above a certain axes, so that the normal mouse appears for the rest of the GUI and they can play with other buttons. Thanks for any insight.
I would recommend not using WindowButtonMotionFcn and instead use the ButtonDownFcn of your axes object. This way MATLAB takes care of your hit detection for you.
For example:
function testcode()
h.myfig = figure;
h.myaxes = axes( ...
'Parent', h.myfig, ...
'Units', 'Normalized', ...
'Position', [0.5 0.1 0.4 0.8], ...
'ButtonDownFcn', #myclick ...
);
end
function myclick(~, eventdata)
fprintf('X: %f Y: %f Z: %f\n', eventdata.IntersectionPoint);
% Insert data capture & storage here
end
Prints your coordinate every time you click inside the axes but does nothing when you click anywhere else.
EDIT:
Since this is a GUIDE GUI the easiest approach is to utilize getappdata to pass data around the GUI. To start, you need to modify your GUI_OpeningFcn to something like the following:
function testgui_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for testgui
handles.output = hObject;
% Initialize axes click behavior and data storage
set(handles.axes1, 'ButtonDownFcn', {#clickdisplay, handles}); % Set the axes click handling to the clickdisplay function and pass the handles
mydata.clickcoordinates = []; % Initialize data array
setappdata(handles.figure1, 'mydata', mydata); % Save data array to main figure
% Update handles structure
guidata(hObject, handles);
And then add a click handling function elsewhere in your GUI:
function clickdisplay(~, eventdata, handles)
mydata = getappdata(handles.figure1, 'mydata'); % Pull data from main figure
mydata.clickcoordinates = vertcat(mydata.clickcoordinates, eventdata.IntersectionPoint); % Add coordinates onto the end of existing array
setappdata(handles.figure1, 'mydata', mydata); % Save data back to main figure
You can then pull the array into any other callback using the same getappdata call.

MATLAB GUIDE slider position and radio buttons

I am trying to write a script that utilizes GUIDE to visualize some results and I have stumbled to some problems. I am going to describe the task first (I will try to make it as general as possible so the question is not too long).
I have a script (main1.m) that graphs a plot and then I pick an area of the plot to analyze (I will call it point1 from now on) and produce several plots through GUIDE (guide_fun1.m). The function guide_fun1 contains 2 radio buttons (created as a group) and a slider on the x axis so the user can see the plot for a smaller range if they wish (the plots initially are from 0 to 1 on the x axis but if the user wants to see from 0 to 0.6 the slider enables them to do so).
I am showing the code main1.m (it is not in detail in order to make it short but to demonstrate what I am trying to achieve) and the guide_fun1.m below. As you see main1.m is interactive and the user can continuously click on several points of the plot until they type exit to finish the program. For every point (point1) they click, a GUIDE window with several options for graphs and plots shows up.
main1.m
%---------------
filename='file1.mat'
load(filename)
figure(1)
plot(data.x,data.y) %data from structure of the mat file
while 1%so that it continues asking for a region
figure(1)
'choose a point or press e to exit'
[x1,y1,key]=ginput(1) %point1(x1,y1)
[data1y,data2y,datax]=function1(x1,y1) %function1 is an outside function that does
%the analysis of the points x1,y1 that were picked from the user
guide_fun1(data1y,data2y,datax)
if (key == 'e')
display('End')
break;
else
display('click point')
end
end
The function that I have created using GUIDE is shown below
guide_fun1.m
%-------------
function varargout = guide_fun1(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', #guide_fun1_OpeningFcn, ...
'gui_OutputFcn', #guide_fun1_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before guide_fun1 is made visible.
function guide_fun1_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 guide_fun1 (see VARARGIN)
handles.data1y = varargin{1};
handles.data2y = varargin{2};
handles.datax = varargin{3};
% Choose default command line output for guide_fun1
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes guide_fun1 wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = guide_fun1_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes when selected object is changed in uipanel1.
function uipanel1_SelectionChangeFcn(hObject, eventdata, handles)
% hObject handle to the selected object in uipanel1
% eventdata structure with the following fields (see UIBUTTONGROUP)
% EventName: string 'SelectionChanged' (read only)
% OldValue: handle of the previously selected object or empty if none was selected
% NewValue: handle of the currently selected object
% handles structure with handles and user data (see GUIDATA)
switch get(eventdata.NewValue,'Tag') % Get Tag of selected object.
case 'radiobutton1'
% Code for when radiobutton1 is selected.
semilogy(handles.datax,handles.data1y,'-r','LineWidth',4);
axis([0 1 0. 1]);
case 'radiobutton2'
% Code for when radiobutton2 is selected.
semilogy(handles.datax,handles.data2y,'-g','LineWidth',4)
axis([0 1 0. 1]);
end
% --- Executes on slider movement.
function slider1_Callback(hObject, eventdata, handles)
% hObject handle to slider1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'Value') returns position of slider
% get(hObject,'Min') and get(hObject,'Max') to determine range of slider
xminval=0;%set min value for x axis
xmaxval=1;%set max value for x axis
xsld_step = [0.01 0.1];%slider step
axis([xminval xmaxval 0 1]);%set axis range for plot
set(hObject,'Min',xminval);
set(hObject,'Max',xmaxval);
set(hObject, 'SliderStep', xsld_step);
new_xmaxval=get(hObject,'Value')
%this is to avoid the error in case the user slides to zero
if new_xmaxval<0.01
'min value for x axis maximum range is 0.01'
new_xmaxval=0.01
end
axis([xminval new_xmaxval 0 1]);%set new axis range for plot
% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
% hObject handle to slider1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor',[.9 .9 .9]);
end
I have 3 issues that I would like to fix.
When the slider shows up, the slider position is at zero but since my initial plot is from 0 to 1 , I would like the slider position to be at 1. Is there any way to set the slider initial position?
When I move the slider position to another value, let's say at 0.4 and then I press the next radio button ('button 2') then my graph is shown with values from 0 to 1 on the x axis but the slider position remains where it was,at the 0.4 point, so it does not look right. I would like when I press 'button 2' either to have both my slider go back to value 1 and my graph to show the plot from 0 to 1 or if my slider remains in the previous position (0.4) to have my graph show the plot from 0 to 0.4 so both the slider and the graph agree. I understand that to do that I have to figure out a way to connect the slider with the radio buttons but I do not know how to do that.
When I click on the first point (point1) and the GUIDE window opens up there is no graph and none of the buttons are pressed (which is what I want). Then I push the button I want and slide the slider to the x axis range that I want to examine. But when I click another point that I want to examine (point1) in the figure(1) plot then the GUIDE window remains as is with the last button clicked and the slider where it was from the previous point and only when I click on 'radio button1' or 'radio button2' it updates to the graph of the new point1. I would like when I click on a new point1 the GUIDE window to become like the first time it opens, no plot shown and no buttons pressed (basically to reset from the previous loop).
I would appreciate any help on this, my knowledge of MATLAB is limited so any guidance on this would be really helpful.
I was able to solve some of the issues with your comments, but unfortunately not all.
I solved this by adding this command set(handles.slider1,'value',1) in guide_fun1_OpeningFcn and the slider goes to 1 every time it restarts, so it works
I changed in uipanel1_SelectionChangeFcn
case 'radiobutton1'
% Code for when radiobutton1 is selected.
semilogy(handles.datax,handles.data1y,'-r','LineWidth',4);
axis([0 1 0.1]);
set(handles.slider1,'value',1);%NEW LINE
so that every time I click on this button the slider goes to value 1 since my axis goes from 0 to 1 but it does not work, there is no error, it just does not update the slider when i click the first button.
3 . I am not sure how to do that. I thought every time the GUI reopens it should automatically reinitialize. Can you give me an example of what an initialization subroutine looks like?
It would be VERY helpful if you showed screenshots of your GUI.
As a starting point for your 3 issues, I would try the following:
Initial slider position. Set the slider value in guide_fun1_OpeningFcn, right before guidata(hObject, handles);
Updating slider position with button press. Set the slider value in the radio buttons' call backs as well as in uipanel1_SelectionChangeFcn. Don't forget to put guidata(hObject, handles); at the end of each callback or method that modifies handles. Although, the set shouldn't change handles, just a property of a handle graphics object.
Make an initialization subroutine and run it from guide_fun1_OpeningFcn or, if you handles the clicks with the GUI instead of ginput, the axes click/selection callback.
A more general observation is that you should not have to put your GUI in a while loop using ginput to get input data. You could handle the axes clicks from the GUI code.

Editing one function in GUIDE, changes all functions?

I am using Matlab's GUIDE for the first time, I am trying to edit one of the two push button functions (both open an image), but editing one changes all of them. Here is a bit of code:
% --- Executes on button press in Floating.
function Floating_Callback(hObject, eventdata, handles)
clc;
axes(handles.axes1);
[Float, PathName, FilterIndex] = uigetfile('*.bmp');
if(Float ~= 0)
Floating = fullfile(PathName, Float);
FloatArray = imread(Floating);
imshow(FloatArray);
axis on;
end
% Update handles structure
guidata(hObject, handles);
% hObject handle to Floating (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% --- Executes on button press in Reference.
function Reference_Callback(hObject, eventdata, handles)
clc;
axes(handles.axes2);
[Ref, PathName, FilterIndex] = uigetfile('*.bmp');
if(Ref ~= 0)
Reference = fullfile(PathName, Ref);
ReferenceArray = imread(Reference);
image(ReferenceArray);
end
% Update handles structure
guidata(hObject, handles);
For example,
image(ReferenceArray)
will open an image in RBG, but
imshow(FloatArray)
will open in grayscale (I also do not understand why that is). But my main concern is after opening up
imshow(FloatArray)
the other image will automatically turn grayscale. I am very confused... Also, as far as I know the images ARE already grayscale, at least they are when I open them in MS paint or ImageJ.
It would be better to explicitly specify the parent handle whenever you are doing GUI stuff. For example:
imshow(img, 'Parent',handles.ax1)
and
axis(handles.ax1, 'on')
As for images and colormaps, you should understand the type of images MATLAB supports (indexed vs. truecolor). Also note that a figure has only one colormap applied to all images, although there are techniques to overcome this.

Using a radio button panel to choose different graphing options

I am trying to create a GUI that will take several inputs and run them through several functions. I wish to use a radio button panel to switch between different graphs, but i just cant seem to get it working. Here is a sample of my code.
switch get(eventdata.NewValue,'Tag') % Get Tag of selected object
case 'button1'
status1 = str2double(get(handles.button1,'Value'));
if status1 == 1;
axes(handles.axes1)
grid on;
plot(x1,y1)
end
case 'button2'
status2 = str2double(get(handles.button2,'Value'));
if status2 == 1;
axes(handles.axes1)
grid on;
plot(x2,y2)
end
case 'button3'
status3 = str2double(get(handles.button3,'Value'));
if status3 ==1
plot(x3,y3)
end
otherwise
% Code for when there is no match.
end
It appears that you are trying to create a radio button panel in a way similar to this example tutorial on blinkdagger.com. Specifically, I believe you are trying to create a SelectionChangeFcn to define how the radio buttons modify your GUI. I would suggest the following:
First, instead of replotting a line every time a radio button is selected, I would suggest that you plot all of your lines when you create your GUI and then adjust the 'Visible' property of the lines to either 'on' or 'off' depending on which button is selected. When you make your GUI, you can add these lines somewhere in your code (after the axes is created and placed in the handles variable):
handles = guidata(hObject); % Retrieve handles structure for GUI
set(handles.axes1,'NextPlot','add'); % Set axes to allow multiple plots
lineHandles = [plot(handles.axes1,x1,y1,'Visible','off') ...
plot(handles.axes1,x2,y2,'Visible','off') ...
plot(handles.axes1,x3,y3,'Visible','off')];
handles.lineHandles = lineHandles; % Update handles structure
guidata(hObject,handles); % Save handles structure
This will plot three sets of lines on the same axes. These lines are initially not visible, and handles to each plotted line are collected in a vector variable lineHandles. The last two lines above add the line handles to the handles structure and update the GUI data (hObject should be a handle to the GUI figure window!).
Now, you can use the following for your SelectionChangeFcn:
handles = guidata(hObject); % Retrieve handles structure for GUI
buttonTags = {'button1' 'button2' 'button3'};
if ~isempty(eventdata.OldValue), % Check for an old selected object
oldTag = get(eventdata.OldValue,'Tag'), % Get Tag of old selected object
index = strcmp(oldTag,buttonTags); % Find index of match in buttonTags
set(handles.lineHandles(index),'Visible','off'); % Turn old line off
end
newTag = get(eventdata.NewValue,'Tag'), % Get Tag of new selected object
index = strcmp(newTag,buttonTags); % Find index of match in buttonTags
set(handles.lineHandles(index),'Visible','on'); % Turn new line on
guidata(hObject,handles); % Save handles structure
NOTE: If you ever want to change any of the three lines that are plotted, you can simply set the 'XData' and 'YData' properties of one of the line handles. As an example, this updates the first plotted line with new x and y data:
set(handles.lineHandles(1),'XData',xNew,'YData',yNew);
Unless you have a good reason to do otherwise, I think you should put the plotting code inside the callback for each radio button.
No need to do this big switchyard.
% --- Executes on button press in radiobutton1.
function radiobutton1_Callback(hObject, eventdata, handles)
% hObject handle to radiobutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hint: get(hObject,'Value') returns toggle state of radiobutton1
%%
%get the values of x y into this callback as you see fit
plot(x,y)
Also, the 'value' that comes out of the button it is already a double for radio buttons. No need to convert it as you are doing.