How to get value from datacursor in GUI Matlab - matlab

How can i get the value of cursor position from datacursor? here's my code
filename = handles.loadDataName;
x=importdata(filename,' ',indexend);
fid = fopen(filename,'r');
A = textscan(fid,'%f%f','Delimiter',' ','headerLines',indexstart);
data = cat(2,A{:});
time = data(:,1);
c1 = data(:,2);
plot(handles.axes_grafik,time,c1)
grid on;
dcm = datacursormode(gcf);
datacursormode on;
set(dcm, 'updatefcn', #myfunction)
function output_txt = myfunction( ~,event_obj)
dataIndex = get(event_obj,'DataIndex');
pos = get(event_obj,'Position');
output_txt = {[ 'Time: ',num2str(pos(1),5)] .....,
['Amplitude: ',num2str(pos(2),5)]};
When i tried to modified function output_txt to get pos(1) and Pos(2) into global variable, i got an error on figure which says 'error in custom datatip string function'
I want to retrieve pos(1) and Pos(2) to display it in editbox. Is there any way to do this? Thanks

[x,y] = ginput
this command will let u click on ur figure as many times as u want until you hit enter then return the xy coords.

Related

How to cut part of the data out of a plot in Matlab

I just wanted to cut part of my data out in MATLAB, for example:
If I click on two points on the axis, it will cut the elements after the I click on with respect to the x-axis. I will post my code and a pic for further details
Thank you in advance
load sample.mat
X = sample.current;
X1 = sample.voltage;
Ts = 0.01;
Fs = 1/Ts;
Fm = Fs/2;
Fc = 2;
N =10;
d = fdesign.lowpass('N,Fc',N,Fc,Fs);
designmethods(d);
Hd = design(d);
%fvtool(Hd)
%X is a variable form csv
%X1 is a variable from csv
output = filter(Hd,X);
output1 = filter(Hd,X1);
figure;
plot(X,X1,'-g');
hold on
plot(output, output1,'r');
hold off
legend('raw signal','filtered signal')
grid on
x = output, output1;
y = output1;
figure
subplot(2,1,1)
plot(x,y,'r');
title('Original plot');
uiwait(msgbox('Select an x-value from which to crop','modal'));
[x_user ~] = ginput(1); % Let the user select an x-value from which to crop.
x(x>x_user) = [];
subplot(2,1,2);
plot(x,y,'r');
title('New plot with cropped values');
xlim([min(x(:)) max(x(:))]);
enter image description here
*Posting this as an answer to format code.
If its only one graphic you can just select the points that you want to delete using the "Brush/Select Data" (icon of a brush with a red square located at the menubar of the figure) selecting the data you want to be gone and then pressing the delete key.
If you want to do it with code you can try to find the index of the point where the signal starts to decrease over the X using something like:
% Find the index where X starts to decrease
maxIndex = find(data.x == max(data.x));
% In case of multiple indexs, ensure we get the first one
maxIndex = maxIndex(1);
% Copy data to new vector
saveData.x = data.x(1:maxIndex);
saveData.y = data.y(1:maxIndex);
If you want to use the users' click position you can use find to locate the index of the first element after the click:
% Get the coords of the first click
userFirstClick = ginput(1);
% Get the X component of the coords
xCoordInit = userFirstClick(1);
% Locate the index of the first element that is greater than
% the xCoord
firstXIndex = find(data.x >= xCoordInit);
% In case of multiple indexs, ensure we get the first one
firstXIndex = firstXIndex(1);
% Do the same to get the final index
userSecondClick = ginput(1);
xCoordFinal = userSecondClick(1);
finalXIndex = find(data.x > xCoordFinal);
finalXIndex = finalXIndex(1)-1;
% -1 because data.x(finalXIndex) is already greater than xCoordFinal
% Copy data to the new vector
saveData.x = data.x(firstXIndex:finalXIndex);
saveData.y = data.y(firstXIndex:finalXIndex);
Then just plot saveData.
Edit
There was a typo on my previous code, here you have a fully functional example where you just need to click over the two points where you want to crop.
function cropSine()
% create a period of a Sine to initialize our data
data.x = -pi*3:0.01:pi*3;
data.y = sin(data.x);
% we make it loop back just as in your picture
data.x = [data.x,data.x(end:-1:1)];
data.y = [data.y, -data.y*0.5+5];
% create a figure to show the signal we have just created
figure
% create the axes where the data will be displayed
mainAx = axes();
% Draw our fancy sine!
plot(data.x, data.y, 'b-', 'Parent', mainAx);
% Request the initial position to crop
userFirstClick = ginput(1);
% Get the index of the nearest point
initIndex = getNearest(userFirstClick, data);
% Do the same to get the final index
userSecondClick = ginput(1);
% Get the index of the nearest point
finalIndex = getNearest(userSecondClick, data);
% check if its a valid point
if isempty(initIndex) || isempty(finalIndex)
disp('No points in data vector!');
return;
end
% Ensure that final index is greater than first index
if initIndex > finalIndex
tempVal = initIndex;
initIndex = finalIndex;
finalIndex = tempVal;
end
% Copy the data that we want to save into a new variable
saveData.x = data.x(initIndex:finalIndex);
saveData.y = data.y(initIndex:finalIndex);
% Plot the cropped data in red!
hold(mainAx, 'on');
plot(saveData.x, saveData.y, 'r-', 'Parent', mainAx);
hold(mainAx, 'off');
end
function nearestIndex = getNearest(clickPos, vector)
nearestIndex = [];
numPoints = length(vector.x);
if numPoints == 0
return;
end
nearestIndex = 1;
minDist = calcDist(vector.x(1), vector.y(1), clickPos(1), clickPos(2));
for pointID = 1:numPoints
dist = calcDist(vector.x(pointID), vector.y(pointID), clickPos(1), clickPos(2));
if dist < minDist
nearestIndex = pointID;
minDist = dist;
end
end
end
function dist = calcDist(p1x, p1y, p2x, p2y)
dist = sqrt(power(p1x-p2x,2)+power(p1y-p2y,2));
end

Getting clicked point coordinates in 3D figure Matlab

I have a 3D figure in Matlab, let's assume it's sphere. What I need, is to get the X, Y, Z values of the point on surface, that I click with the mouse.
r = 10;
[X,Y,Z] = sphere(50);
X2 = X * r;
Y2 = Y * r;
Z2 = Z * r;
figure();
props.FaceColor = 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
sphere = surf(X2,Y2,Z2,props);
axis equal
hold on
clicked_point = [?,?,?];
So in this example I want the clicked_point to be equal to [-3.445,-7.32,5.878].
I've tried with such solution:
clear all;
close all;
r = 10;
[X,Y,Z] = sphere(50);
X2 = X * r;
Y2 = Y * r;
Z2 = Z * r;
fig = figure();
props.FaceColor = 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
sphere = surf(X2,Y2,Z2,props);
axis equal
dcm_obj = datacursormode(fig);
set(dcm_obj,'DisplayStyle','datatip',...
'SnapToDataVertex','off','Enable','on')
c_info = getCursorInfo(dcm_obj);
while length(c_info) < 1
datacursormode on
c_info = getCursorInfo(dcm_obj);
end
But after that I can't even click on the sphere to display any data on figure. How can I get X, Y, Z in script? If not, how can I detect that the mouse click has already occured in Matlab?
It is not clear whether you want the clicked_point variable to reside in the base workspace or if that is going to be part of a GUI.
I'll give you a solution for the base workspace.
The trick is to just add the bit of code you need to the UpdateFcn of the datacursormode object.
Save a function getClickedPoint.m somewhere visible on your MATLAB path:
function output_txt = getClickedPoint(obj,event_obj)
% Display the position of the data cursor
% obj Currently not used (empty)
% event_obj Handle to event object
% output_txt Data cursor text string (string or cell array of strings).
pos = get(event_obj,'Position');
output_txt = {['X: ',num2str(pos(1),4)],...
['Y: ',num2str(pos(2),4)]};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = ['Z: ',num2str(pos(3),4)];
end
assignin('base','clicked_point',pos)
All this code is actually a copy of the default function used by data cursors. The only modifications are:
I changed the name (obviously you want it to be unique)
I added the last line of code
This last line of code use assignin to transfer the position of the cursor into a variable (named clicked_point) in the base workspace.
Armed with that, keep your code which generate the sphere (although I recommend you change the name of the surface object to something else than sphere as this is a built in MATLAB function), and we just have to modify the datacursormode object to instruct it to use our getClickedPoint function:
[X,Y,Z] = sphere(50);
r = 10 ; X2 = X * r; Y2 = Y * r; Z2 = Z * r;
fig = figure ;
hs = surf(X2,Y2,Z2,'FaceColor','texture','EdgeColor','none','FaceLighting','phong');
axis equal
%% Assign custom update function to dcm
dcm_obj = datacursormode(fig);
set(dcm_obj,'SnapToDataVertex','off','Enable','on','UpdateFcn',#getClickedPoint)
Now the first time you click on the sphere, the variable clicked_point will be created in the workspace with the coordinates of the point. And every time you click again on the sphere the variable will be updated:
If this is to be applied with a GUI, use the same technique but instead of assignin, I would recommend to use the setappdata function. (you can read Share Data Among Callbacks to have details about how this works.)

Limited number of datacursormode on a scatter plot - Matlab

I have an ellipse plot (scatter) and I wish to have only two datacursormode and than get their respective X and Y coordinates. The code attached plot the ellipse and mark a point but how can I limit it and get the coordinates?
Code:
clc;
clear;
a=3;
b=7;
x0=0;
y0=0;
t=-pi:0.01:pi;
x=x0+a*cos(t);
y=y0+b*sin(t);
sz = 5;
scatter(x,y,sz)
dcm_obj = datacursormode;
set(dcm_obj,'UpdateFcn',#myupdatefcn)
function txt = myupdatefcn(empt,event_obj)
pos1 = get(event_obj,'Position');
txt = {['X position ',num2str(pos1(1))],...
['Y position: ',num2str(pos1(2))]};
end
You can use a while loop for selecting two points, and use nested functions for sharing variables.
Using nested functions is a possible solution for passing the selected coordinates and a counter out to a parent function.
You can limit the number of selected (marked) points to two, using a while loop.
Placing a pause inside the while is important for responsiveness.
Here is a working code sample:
function ellip()
%Parent function (use a function instead of a script,
%allows sharing variables with internal function).
clc;
%clear;
a=3;
b=7;
x0=0;
y0=0;
t=-pi:0.01:pi;
x=x0+a*cos(t);
y=y0+b*sin(t);
sz = 5;
h = figure; %Open new figure, and keep the handle.
scatter(x,y,sz);
dcm_obj = datacursormode;
dcm_obj.Enable = 'on';
set(dcm_obj,'UpdateFcn',#myupdatefcn)
%pos_x, pos_y and pos_counter are known both in scope of myupdatefcn and in ellip
pos_x = zeros(1,2);
pos_y = zeros(1,2);
pos_counter = 0;
%Loop until two points are selected
while (pos_counter < 2) && isvalid(h)
pause(0.01);
end
if isvalid(h)
close(h); %Close the figure;
%Display position of the two selected coordinates.
fprintf('pos1 = (%f, %f), pos2 = (%f, %f)\n', pos_x(1), pos_y(1), pos_x(2), pos_y(2));
end
dcm_obj.delete() %Delete the object (cleanup)
%myupdatefcn is a nested function, inside ellip function
function txt = myupdatefcn(empt, event_obj)
pos1 = get(event_obj,'Position');
txt = {['X position ',num2str(pos1(1))],...
['Y position: ',num2str(pos1(2))]};
disp(txt);
pos_counter = pos_counter + 1; %Increase counter.
pos_x(pos_counter) = pos1(1); %Store position
pos_y(pos_counter) = pos1(2);
end
end
I hope that I got it right, it is difficult understanding what you are asking...
Update to comment:
Creating the scatter plot outside the function is simple.
Saving the 4 positions is simple - the function can return the points.
I couldn't find an elegant way for leaving the tool-tip information on the plot.
The problem is that calling createDatatip triggers the event and executes myupdatefcn few more times.
You may take a look at Set data tips programmatically?
Updated code:
clc
clear
close all
a=3;
b=7;
x0=0;
y0=0;
t=-pi:0.01:pi;
x=x0+a*cos(t);
y=y0+b*sin(t);
sz = 5;
scatter(x,y,sz);
[pos_x, pos_y] = ellip();
%Display position of the two selected coordinates.
fprintf('pos1 = (%f, %f), pos2 = (%f, %f)\n', pos_x(1), pos_y(1), pos_x(2), pos_y(2));
function [pos_x, pos_y] = ellip()
%Parent function (use a function instead of a script,
%allows sharing variables with internal function).
dcm_obj = datacursormode;
dcm_obj.Enable = 'on';
set(dcm_obj,'UpdateFcn',#myupdatefcn)
h = dcm_obj.Figure; %Get hendle to the figure.
hScatter = findobj(h, 'Type', 'scatter'); %Handle to scatter plot
%pos_x, pos_y and pos_counter are known both in scope of myupdatefcn and in ellip
pos_x = zeros(1,2);
pos_y = zeros(1,2);
pos_counter = 0;
%Loop until two points are selected
while (pos_counter < 2) && isvalid(h)
pause(0.01);
end
% if isvalid(h)
% close(h); %Close the figure;
% end
%dcm_obj.delete() %Delete the object (cleanup)
if isvalid(h)
dcm_obj.Enable = 'off';
set(dcm_obj,'UpdateFcn',[]) %Replace the callback with an empty function instead of deleting the object
end
%myupdatefcn is a nested function, inside ellip function
function txt = myupdatefcn(empt, event_obj)
pos1 = get(event_obj,'Position');
txt = {['X position ',num2str(pos1(1))],...
['Y position: ',num2str(pos1(2))]};
if (pos_counter > 0) && (pos_x(pos_counter) == pos1(1)) && (pos_y(pos_counter) == pos1(2))
return %Return if pod1 is already selected.
end
disp(txt);
pos_counter = pos_counter + 1; %Increase counter.
pos_x(pos_counter) = pos1(1); %Store position
pos_y(pos_counter) = pos1(2);
%Try keeping the tool-tip data
hdtip = dcm_obj.createDatatip(hScatter);
set(hdtip, 'MarkerSize',5, 'MarkerFaceColor','none', 'MarkerEdgeColor','r', 'Marker','o', 'HitTest','off');
end
end

MATLAB custom datatip in images

Following the instructions on other pages, e.g.
http://blogs.mathworks.com/videos/2011/10/19/tutorial-how-to-make-a-custom-data-tip-in-matlab/
http://it.mathworks.com/help/matlab/ref/datacursormode.html
http://it.mathworks.com/matlabcentral/answers/68079-how-to-add-additional-info-to-the-data-cursor
i've written a custom callback function for the datatip to show me the index of the points on a x-y graph as well as their x and y coordinates:
function output_txt = customCallback_DataTip(obj,event_obj)
% Display the position of the data cursor
% obj Currently not used (empty)
% event_obj Handle to event object
% output_txt Data cursor text string (string or cell array of strings).
pos = get(event_obj,'Position');
output_txt = {['X: ',num2str(pos(1),4)],...
['Y: ',num2str(pos(2),4)]};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = ['Z: ',num2str(pos(3),4)];
else % 2D plot: write index of current point
i = find(event_obj.Target.XData == pos(1), 1);
output_txt{end+1} = ['i: ',num2str(i)];
end
This code starts from the default callback suggested by MATLAB, and adds a z-coordinate info whenever the plot is a 3D one. Since I very often need to know the array index of a point on a graph, the custom callback function is enabled automatically at MATLAB startup.
Now, whenever I plot an image (e.g. via imagesc) I would like to have the "normal" image datatip:
i.e. with Index/RGB information on it. How can I modify the callback function in order to obtain this behavior?
EDIT: i would like to modify my custom callback so that it automatically displays something similar to the default MATLAB default datatip when I'm using the datatip on an image.
To accomplish this, you can check the type of the event_obj.Target and respond accordingly.
get(event_obj.Target, 'type')
All images (whether imagesc, image, or imshow) will have a Type of image.
isImage = strcmpi(get(event_obj.Target, 'type'), 'image')
You can then extract the image data. If you have an indexed image, you can also get the colormap to determine all the other information to go into the datatip.
cdata = get(event_obj.Target, 'cdata');
cmap = colormap(ancestor(event_obj.Target, 'axes'));
Bringing this all together, I would modify your custom data tip callback to be something like this.
function output_txt = callback(obj, event_obj, clims)
% Get the cursor location
pos = get(event_obj, 'Position');
output_txt = {sprintf('[X,Y]: [%i, %i]', pos(1), pos(2))};
if strcmpi(get(event_obj.Target, 'type'), 'image')
% Get the image data
cdata = get(event_obj.Target, 'CData');
% Check to ensure pos is in range
if pos(1) < 1 || pos(1) > size(cdata, 2) || ...
pos(2) < 1 || pos(2) > size(cdata, 1)
rgb = {NaN, NaN, NaN};
newline = sprintf('[R,G,B]: [%0.4f %0.4f %0.4f]', rgb{:});
output_txt = cat(1, output_txt, newline);
return
end
% If the image is RGB
if size(cdata, 3) == 3
rgb = num2cell(cdata(pos(2), pos(1), :));
% If this is an indexed image
else
index = cdata(pos(2), pos(1));
% Figure out the colormap
hax = ancestor(event_obj.Target, 'axes');
cmap = colormap(hax);
% If the CData is scaled, we need to scale to the colormap
if strcmpi(get(event_obj.Target, 'CDataMapping'), 'scaled')
value = (index - clims(1)) * size(cmap, 1) / diff(clims);
else
value = index;
end
% Determine RGB value from colormap
rgb = num2cell(ind2rgb(round(value), cmap));
if round(index) == index
newline = sprintf('Index: %d', index);
else
newline = sprintf('Index: %.4f', index);
end
% Generate datatip text
output_txt = cat(1, output_txt, newline);
end
output_txt = cat(1, output_txt, ...
sprintf('[R,G,B]: [%0.4f %0.4f %0.4f]', rgb{:}));
% Otherwise we use your custom datatip for plots
else
index = find(event_obj.Target.XData == pos(1), 1);
pos = get(event_obj, 'Position');
output_txt = { sprintf('X: %0.4f', pos(1));
sprintf('Y: %0.4f', pos(2))};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = sprintf('Z: %0.4f', pos(3));
else % 2D plot: write index of current point
output_txt{end+1} = sprintf('i: %d', index);
end
end
end
If you notice, I'm passing in an additional variable (clims) to the callback function. This is because some versions won't actually allow me to query axes properties from within the datatip UpdateFcn. So this means that you will have to change your UpdateFcn anonymous function just a little bit.
h = datacursormode(fig);
set(h, 'Enable', 'on')
% Here I have to pass the `clims` because I can't fetch them inside
set(h, 'UpdateFcn', #(dt,e)callback(dt, e, caxis(ancestor(dt.Host, 'axes'))));
Using this, I was able to show the proper display for both plots and images (both indexed and RGB).

matlab: inputdlg dialog box comes with tick labels

I have a user input request box basically written as matlab suggests in http://www.mathworks.com/help/matlab/ref/inputdlg.html .
prompt = {'Enter spot number'};
dlg_title = 'Input';
num_lines = 1;
def = {'9'};
answer = inputdlg(prompt,dlg_title,num_lines,def);
handles.count = str2double(answer{1});
However, the dialog box comes with axis labels as the image shows in the link below:
http://imgur.com/yPUYTJb
Edit:
It turns out that the windowsbuttonmotion function is doing the thing. I evaluated it within the function, not by calling a second function. Like this:
function figure1_WindowButtonMotionFcn(hObject, eventdata, handles)
global loop_counter diameter
pos = get(gca, 'currentpoint'); % get mouse location on figure
x = pos(1,1); y = pos(1,2); % assign locations to x and y
set(handles.lbl_x, 'string', ['x loc:' num2str(x)]); % update text for x loc
set(handles.lbl_y, 'string', ['y loc:' num2str(y)]); % update text for y loc
const = diameter/2;
for i = 1:loop_counter
center(i,:) = getPosition(handles.trap(handles.unselected(i)))+const;
if(((x-center(i,1))^2+(y-center(i,2))^2)<= const^2)
setColor(handles.trap(handles.unselected(i)), 'red');
else
setColor(handles.trap(handles.unselected(i)), 'blue');
end
end
guidata(hObject, handles)
How can I get rid of them?
Thanks.