Problems including a new KeyPressFcn to call a function in axdrag file

Hi all,
I am using this file (axdrag) with my plot. I included new lines to call a function when the key 'g' is pressed but it does not work. There is not error, so the coding is correct, but somewhat these new lines are not doing the task in the plot.
Here is part of the code of axdrag
function axdrag(action)
if nargin < 1
action = 'initialize';
end
% Use these variables to change the zoom and pan amounts
zoomFactor = 0.9;
panFactor = 0.02;
%Code continues
switch action
case 'initialize'
set(gca,'ButtonDownFcn','axdrag start')
set(gcf,'KeyPressFcn','axdrag keypress')
set(gcf,'DoubleBuffer','on')
case 'start'
set(gcbf,'Units','pixel');
set(gca,'Units','pixel');
set(gcbf,'WindowButtonMotionFcn','axdrag move')
set(gcbf,'WindowButtonUpFcn','axdrag stop')
currentPoint = get(gcbf,'CurrentPoint');
x0 = currentPoint;
axdrag move
case 'move'
currentPoint = get(gcbf,'CurrentPoint');
dx = currentPoint - x0;
x0 = currentPoint;
ap = get(gca,'Position');
xLim = get(gca,'XLim');
yLim = get(gca,'YLim');
set(gca,'XLim',xLim-(diff(xLim)*dx(1)/ap(3)), ...
'YLim',yLim-(diff(yLim)*dx(2)/ap(4)));
case 'stop'
set(gcbf,'WindowButtonMotionFcn','')
set(gcbf,'WindowButtonUpFcn','')
set(gcbf,'Units','normalized');
set(gca,'Units','normalized');
case 'keypress'
currChar = get(gcbf,'CurrentCharacter');
if isempty(currChar)
return
end
if currChar=='a'
axis auto
elseif currChar=='e'
axis equal
% Code continues
end
end
end
Then, I included this line, but it is doing nothing
elseif currChar=='g'
myginput(1)
I expected to enable the selection of one point in my plot. But as I said, nothing is running.
Also, I tried with this (simpler task), but again, it does not work.
elseif currChar=='g'
zoom on
The way I call the function in the Command Window:
plot(x,y)
axdrag
How can I call a function that works in the plot by pressing a key?
Thanks,
Jose

7 Comments

elseif currChar=='g'
grid
Are these lines still present in your updated file? If so, and your code comes after, then pressing g will only call grid.
I have no idea why, but now it is working.Tommy, I have checked what you pointed out several times to make sure that 'g' was call only once.
Anyways, as I said, now it works. Sorry for the inconvenience.
Hi, I got a problem related with this function.
So, in short, I am looking for a way to use this file axdrag in my code. I plot a signal, with spikes, and I want to be able to pan/zoom the plot, and ultimately select points (ginput) around the plot. Then, the code takes this points, creates a column vector and analize the data of the spike
This is an example of my code. In general speaking,
function plot_v1
S=load('F310120.mat');
x=S.T;
y=S.I;
plot(x,y,'b') %plot the data
[px_1]=axdrag2; %it goes to axdrag to pan,zoom the plot and ginput (px_1)
b=(px_1)+3;%takes the output of ginput (px_1) and do some stuff
c=table(b)
end
Here is the axdrag code simplified.
function [px_1]=axdrag2(action)
% Copyright 2018, The MathWorks, Inc.
% Ned Gulley
persistent x0 dx
if nargin < 1
action = 'initialize';
end
% Use these variables to change the zoom and pan amounts
zoomFactor = 0.9;
panFactor = 0.02;
% Get rid of the help window if it's being displayed
helpTextAxis = findobj(gcbf,'Type','axes','Tag','axdraghelpaxis');
if isempty(helpTextAxis)
helpWasOff = 1;
else
helpWasOff = 0;
delete(helpTextAxis);
end
switch action
case 'initialize'
set(gca,'ButtonDownFcn','axdrag start')
set(gcf,'KeyPressFcn','axdrag keypress')
set(gcf,'DoubleBuffer','on')
case 'start'
set(gcbf,'Units','pixel');
set(gca,'Units','pixel');
set(gcbf,'WindowButtonMotionFcn','axdrag move')
set(gcbf,'WindowButtonUpFcn','axdrag stop')
currentPoint = get(gcbf,'CurrentPoint');
x0 = currentPoint;
axdrag move
case 'move'
currentPoint = get(gcbf,'CurrentPoint');
dx = currentPoint - x0;
x0 = currentPoint;
ap = get(gca,'Position');
xLim = get(gca,'XLim');
yLim = get(gca,'YLim');
set(gca,'XLim',xLim-(diff(xLim)*dx(1)/ap(3)), ...
'YLim',yLim-(diff(yLim)*dx(2)/ap(4)));
case 'stop'
set(gcbf,'WindowButtonMotionFcn','')
set(gcbf,'WindowButtonUpFcn','')
set(gcbf,'Units','normalized');
set(gca,'Units','normalized');
case 'keypress'
currChar = get(gcbf,'CurrentCharacter');
if isempty(currChar)
return
end
if currChar=='a'
zoom on
elseif currChar=='g'
[px_1,~] = myginput(1,'crosshair');
end
end
end
But I got this error.
Output argument "px_1" (and maybe others) not assigned during call to "plot_v1>axdrag2".
Error in plot_v1 (line 11)
[px_1]=axdrag2;
The fuctions are separated (no nested functions) in the same script. I am able to run the function axdrag without the switch statement (if statement, for example), but this is a completely non sense because I want this statement to run different function by pressing keys.
How can I run this axdrag in my code, and use variables of this function in another funtion?
When you first call your function:
[px_1]=axdrag2;
you are calling it with no arguments. So, inside your function, this if statement evaluates to true:
if nargin < 1
action = 'initialize';
end
and the following code runs in the switch case statement:
set(gca,'ButtonDownFcn','axdrag start')
set(gcf,'KeyPressFcn','axdrag keypress')
set(gcf,'DoubleBuffer','on')
Then the function exits, and as px_1 is never defined, you get an error.
This function, axdrag, is designed so that when you next click on the axes or press a key, the function is called again, this time with a specific argument. When you press the 'g' key, the figure's KeyPressFcn is called. The KeyPressFcn is 'axdrag keypress', a.k.a. axdrag('keypress'). There are two problems:
  1. Will your program know what axdrag is? It won't if axdrag is not on the path somewhere, and if it is on the path, well, now the original axdrag is being used, not your updated axdrag2. You would have to change all of those 'axdrag arg1' strings to 'axdrag2 arg1'.
  2. The idea of passing a variable out of the KeyPressFcn does not really make sense.
Note that the ability to zoom and pan are enabled by default now. If these are the only reasons you are using axdrag, I wouldn't use it.
How is your function, plot_v1(), supposed to wait until the user has pressed 'g' and then clicked in the axes before it analyzes the data? You'd either have to play around with blocking program execution or (really, the proper way to do this) set up your own KeyPressFcn to call myginput() in response to 'g' key presses and then perform the data analysis within the KeyPressFcn, or in some other function which gets called by the KeyPressFcn. In this case, plot_v1() will (probably) finish executing long before the user ever presses 'g'. Besides, the idea is to let the user press 'g' whenever they want - otherwise, you would just call ginput() right off the bat.
(edit) I would also post this and/or subsequent questions in a new post. If you comment a link here, I am more than happy to take a look!
So, I solve the problem: 4 different scripts, and global variables. Without global I couldn't pass out the variables. I tried to bridge axdrag, but imposible.
function plot_v1
global u v
S=load('F310120.mat');
u=S.T;
v=S.I;
plot(u,v,'b');
axdrag;
end
axdrag
function axdrag(action)
% Copyright 2018, The MathWorks, Inc.
% Ned Gulley
% global px_1 px_2
persistent x0 dx
if nargin < 1
action = 'initialize';
end
% Use these variables to change the zoom and pan amounts
zoomFactor = 0.9;
panFactor = 0.02;
% Get rid of the help window if it's being displayed
helpTextAxis = findobj(gcbf,'Type','axes','Tag','axdraghelpaxis');
if isempty(helpTextAxis)
helpWasOff = 1;
else
helpWasOff = 0;
delete(helpTextAxis);
end
switch action
case 'initialize'
set(gca,'ButtonDownFcn','axdrag start')
set(gcf,'KeyPressFcn','axdrag keypress')
set(gcf,'DoubleBuffer','on')
case 'start'
set(gcbf,'Units','pixel');
set(gca,'Units','pixel');
set(gcbf,'WindowButtonMotionFcn','axdrag move')
set(gcbf,'WindowButtonUpFcn','axdrag stop')
currentPoint = get(gcbf,'CurrentPoint');
x0 = currentPoint;
otherthing move
case 'move'
currentPoint = get(gcbf,'CurrentPoint');
dx = currentPoint - x0;
x0 = currentPoint;
ap = get(gca,'Position');
xLim = get(gca,'XLim');
yLim = get(gca,'YLim');
set(gca,'XLim',xLim-(diff(xLim)*dx(1)/ap(3)), ...
'YLim',yLim-(diff(yLim)*dx(2)/ap(4)));
case 'stop'
set(gcbf,'WindowButtonMotionFcn','')
set(gcbf,'WindowButtonUpFcn','')
set(gcbf,'Units','normalized');
set(gca,'Units','normalized');
case 'keypress'
currChar = get(gcbf,'CurrentCharacter');
if isempty(currChar)
return
end
if currChar=='a'
axis auto
elseif currChar=='e'
axis equal
elseif currChar=='g' || (currChar=='G')
if currChar == 'g'
first_ginput;
else
second_ginput
end
Last 2 scripts:
function first_ginput
global u h1
[px_1,~] = myginput(1,'crosshair');
h1=nearestpoint(px_1,u);
end
function second_ginput
global u v h1 h2
[px_2,~] = myginput(1,'crosshair');
h2=nearestpoint(px_2,u);
T=u(h1:h2);
I=v(h1:h2);
[~,b]=max(I);%Finds the row (b) when I is max (a)
Time=T(b);%Gives you the second when I is max
Amplitude=round((max(I)),8);%Max I (rounded) of the spike
halfMax = max(I)/2;
t=table(Time,Amplitude,halfMax);
writetable(t,'tableforme.xls','Sheet',1);
end
I tried to pass out the variable u and v using input arguments from the first script to the latest two scripts but I couldn´t do it. Global could be bad, but in my case is the best for this situation.
Thanks Tim for warning me that KeyPressFcn does not pass out variables. I did not know it.

Sign in to comment.

Answers (0)

Categories

Asked:

on 2 May 2020

Commented:

on 5 May 2020

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!