Problem plotting function in GUI

Hello everyone, this is the first time I post here so if I sound like a newbie is because I am. I have a problem when trying to plot a function in GUI so I decided to do some tests in order to figure it out. I'm creating a non-linear equation solver using Newton-Raphson Method and this is how the UI looks (is in Spanish but is quite intuitive):
Funcion = The function the user wants to solve. Stored in the variable 'funcion' and then I use the inline() function in order to get a function that I can use in order to compute values (stored in the variable f). When he clicks on "Click aqui para mostrar la derivada", the program derivates the function the user wants to solve in order to use it in the formula. Valor inicial = Initial value. "Elija el metodo" = The user can choose one of two methods, fixed number of iterations or tolerance (hope this is clear). "Calcular" = The method executes and finds the value wanted.
I haven't implemented the table yet so I see the answer in the command window. Until this point, everything works smoothly, the root is stored in the variable 'x1'. The problem begins when I click the push button called "Graficar respuesta". What it does is to plot the function and a circle around the point 'x1' which represents one root of the function, at least that's what is supposed to do. The code is:
% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
global x1;
global funcion;
global f;
if x1==0
x1=x1+1;
elseif x1<0
x1=-x1;
end
% axes(handles.axes2);
%Imagen
figure (1);
x=-5*x1:0.001:5*x1;
plot(x,funcion,'Color','red'), title('Grafica de la funcion'), xlabel('Eje X'), ylabel('Eje Y'), grid;
hold on;
scatter(x1,f(x1));
But I get the next error:
Error using plot
Error in color/linetype argument.
Error in newton>pushbutton3_Callback (line
196)
plot(x,funcion,'Color','red'), title('Grafica
de la funcion'), xlabel('Eje X'), ylabel('Eje
Y'), grid;
Error in gui_mainfcn (line 95)
feval(varargin{:});
Error in newton (line 18)
gui_mainfcn(gui_State, varargin{:});
Error in
matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)newton('pushbutton3_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating UIControl Callback.
What am I doing wrong? I would really appreciate any help, please. Thanks in advance.

6 个评论

Diego - is funcion a handle to a function or an array of values? If the former, where do you evaluate it? Please show more of your code.
Also, consider alternatives to global variables. Use the handles structure to manage some user-defined data.
For an actual solution to this problem: use 'r' instead of 'red'.
I agree with Geoff on both counts: use guidata instead of globals, and where do you process funcion to a vector that doesn't depend on x but has the same number of elements? Because that's likely to be the next error from that line of code.
Thanks to both of you for your comments! @Geoff Hayes funcion is (I think, I'm not 100% sure because I'm new to Matlab) an array. The code that implements it is:
function funcion_Callback(hObject, eventdata, handles)
global f;
global df;
global funcion;
syms x;
funcion=get(handles.funcion,'string');
f=inline(funcion,'x');
derivada=diff(funcion,x);
set(handles.derivada,'string',char(derivada));
df=inline(derivada,'x');
As for the global variables, I don't feel too comfortable using handles. For now, I rather just see the project working and as soon as it is, I'll start using handles and improving the code. Note: This is not a college project, is just something I'm doing for fun and I might as well share the whole thing here.
@Rik Wisselink I did what you suggested but it's still not working, after changing 'red' for 'r' I get the error:
Error using plot
Error in color/linetype argument.
Error in newton>pushbutton3_Callback (line
196)
plot(x,funcion,'Color','r'), title('Grafica
de la funcion'), xlabel('Eje X'), ylabel('Eje
Y'), grid;
Error in gui_mainfcn (line 95)
feval(varargin{:});
Error in newton (line 18)
gui_mainfcn(gui_State, varargin{:});
Error in
matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)newton('pushbutton3_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating UIControl Callback.
As for "and where do you process funcion to a vector that doesn't depend on x but has the same number of elements" I think that what you want to know is if 'funcion' is a vector or a function per se in which I can compute values, right? Please, take a look at the first chunk of code I posted in this comment, I think that should sort things out.
Again, thank you both!
Edit 1: What I want to get is something like this:
The line represents the function given by the user and the dot represents the root of that function close to the initial value. The code that implements this image is this (this code is not inside the project):
x=-20:20;
fun=3*x-10;
y=@(x) 3*x-10; %otra version de inline
x1=fzero(y,1);
%Imagen
figure (1);
plot(x,fun), title('Grafica de la funcion'), xlabel('Eje X'), ylabel('Eje Y'), grid;
hold on;
scatter(x1,y(x1))
"I'm new to Matlab"
That is a good reason to avoid global variables: it is easier to learn good habits from the start than unlearn bad habits later.
"As for the global variables, I don't feel too comfortable using handles."
In GUI's handles is just a structure. It has fields, just like every other structure. Get data out, put data in, store it using guidata. Not complex, and much better than using global variables!
You are totally right. I should learn good practices from the beginning. Could you give me some site where I could learn all about that with examples, please? Thanks in advance!
Avoid using global variables, evalin, and assignin. For callback functions use guidata (for GUIDE) or nested functions (if you are writing your own code). For non-GUI code pass variables as input/output arguments.
You will find plenty of simple examples on this forum, e.g.:
Using guidata is very simple:
function foobar(hObject, eventdata, handles)
...
... handles.X ... % access field X
handles.Y = ... % define field Y
...
guidata(hObject,handles) % save any new data

请先登录,再进行评论。

回答(1 个)

Using the handles struct is very easy. It may seem hard to learn good practices, but it is much harder to unlearn bad practices. The code below works on my system (R2018a). You should really pay attention to the m-lint warnings. Replacing an old function like inline with anonymous functions is a good place to start. In your call to that figure 1, I would add a clf(1), especially since you have hold turned on.
function funcion_Callback(hObject, ~, handles)
syms x;
funcion=get(handles.funcion,'string');
f=str2func(['@(x)' funcion]);
df=symfun(diff(f,x),x)
set(handles.derivada,'string',char(df));
handles.funcion=funcion;
handles.df=df;
handles.f=f;
guidata(hObject,handles)
function pushbutton3_Callback(hObject, ~, handles)
x1=handles.x1;%global x1;
%funcion=handles.funcion;%global funcion;
f=handles.f;%global f;
if x1==0
x1=x1+1;
elseif x1<0
x1=-x1;
end
% axes(handles.axes2);
%Imagen
figure (1);
x=-5*x1:0.001:5*x1;
plot(x,f(x),'Color','red'), title('Grafica de la funcion'), xlabel('Eje X'), ylabel('Eje Y'), grid;
hold on;
scatter(x1,f(x1));

6 个评论

Thank you for your answer! I have a couple of errors and a few questions... 1. What's the difference between:
function funcion_Callback(hObject, ~, handles)
and
function funcion_Callback(hObject, eventdata, handles)
When I press the button 'Calcular', it shows an error:
Reference to non-existent field 'a'.
Error in newton>calcular_Callback (line 89)
a=handles.a;
Error in gui_mainfcn (line 95)
feval(varargin{:});
Error in newton (line 18)
gui_mainfcn(gui_State, varargin{:});
Error in
matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)newton('calcular_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating UIControl Callback.
And then when I press the 'pushbutton3' which is used to plot the function, I get the next error:
Reference to non-existent field 'x1'.
Error in newton>pushbutton3_Callback (line 178)
x1=handles.x1;
Error in gui_mainfcn (line 95)
feval(varargin{:});
Error in newton (line 18)
gui_mainfcn(gui_State, varargin{:});
Error in
matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)newton('pushbutton3_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating UIControl Callback.
This is the whole code:
function varargout = newton(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @newton_OpeningFcn, ...
'gui_OutputFcn', @newton_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 newton is made visible.
function newton_OpeningFcn(hObject, eventdata, handles, varargin)
I=imread('C:\Users\Diego\Desktop\Proyecto final\newton.png'); %Se agrega la imagen de la funcion recursiva
axes(handles.figuraformula);
imshow(I);
% This function has no output args, see OutputFcn.
% Choose default command line output for newton
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% --- Outputs from this function are returned to the command line.
function varargout = newton_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
% --------------------------------------------------------------------
function Volver_Callback(hObject, eventdata, handles)
close newton
E_N_L
function funcion_Callback(hObject, ~, handles)
syms x;
funcion=get(handles.funcion,'string'); %Obtiene la expresion ingresada por el usuario
f=str2func(['@(x)' funcion]); %Crea una funcion utilizando la expresion (string)
df=symfun(diff(f,x),x); %Deriva y crea la funcion en un solo paso
set(handles.derivada,'string',char(df)); %Muestra el valor de la expresion derivada
handles.funcion=funcion;
handles.df=df;
handles.f=f;
guidata(hObject,handles)
% Código funcional de funcion_Callback
% % % function funcion_Callback(hObject, eventdata, handles)
% % % global f;
% % % global df;
% % % global funcion;
% % % syms x;
% % % funcion=get(handles.funcion,'string'); %Obtiene la expresion ingresada por el usuario
% % % f=inline(funcion,'x'); %Crea una funcion utilizando la expresion
% % % derivada=diff(funcion,x); %Halla la derivada utilizando la expresion
% % % set(handles.derivada,'string',char(derivada)); %Muestra el valor de la expresion derivada
% % % df=inline(derivada,'x'); %Crea una funcion utilizando la expresion de la derivada
% --- Executes during object creation, after setting all properties.
function funcion_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function x0_Callback(hObject, eventdata, handles)
x0=str2double(get(hObject,'string'));
handles.x0=x0;
% --- Executes during object creation, after setting all properties.
function x0_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
% --- Executes on button press in calcular.
function calcular_Callback(hObject, eventdata, handles)
%Declaracion de variable globales y locales
f=handles.f;
df=handles.df;
x0=handles.x0;
a=handles.a;
limite=handles.limite;
% ayuda=x0;
% evaluado=f(x0);
error=0;
i=0;
%%%%%%%
fprintf('\n \titer. \tx \t\tf(x) \t error(porcentaje)\n');
x1=x0-(f(x0)/df(x0)); %Calcula el siguiente valor
%Llenado de un array para usarlo en la tabla
tabla = [0 0 0 0];
% tabla(1,1:end) = [i x0 f(x0) error];
switch (a)
case 2
%Este while sirve para repetir los calculos una cantidad fija de veces
while(i<limite)
%Llenado de la tabla:
i=i+1;
tabla(i,1:end) = [i x0 f(x0) error];
error=abs((x0-x1)/x0)*100;
x0=x1;
x1=x0-(f(x0)/df(x0)); %Calcula el siguiente valor hasta que cumpla la condicion
end
case 3
%Este while sirve para repetir los calculos hasta una tolerancia
%especificada
while (abs((x0-x1)/x0) > limite);
%Llenado de la tabla:
i=i+1;
tabla(i,1:end) = [i x0 f(x0) error];
error=abs((x0-x1)/x0)*100;
x0=x1;
x1=x0-(f(x0)/df(x0)); %Calcula el siguiente valor hasta que cumpla la condicion
end
end
x1=handles.x1;
%Llenado de la tabla en el GUIDE:
format long g;
set(handles.uitable1,'data',tabla);
fprintf('\n La aproximación de la raíz es: %3.15f \n\n',x1);
x0=ayuda; %Devuelve el valor inicial dado por el usuario a la variable x0
%para que el usuario no tenga que editar ese valor en un
%proximo uso con el mismo valor inicial
% --- Executes on selection change in selector.
function selector_Callback(hObject, ~, handles)
contenido=get(hObject,'String'); % Contenido actua como una matriz cuyos elementos son las distintas opciones
a=get(hObject,'Value'); % Obtiene el valor 1 o 2 dependiendo de si se selecciona la opcion 1 o 2
handles.a=a;
switch (a)
case 1
set(handles.limite,'String','Elija');
case 2
set(handles.limite,'String','Iteraciones');
case 3
set(handles.limite,'String','Tolerancia');
otherwise
set(handles.limite,'String','Elija');
end
% set(handles.limite,'String',texto); Aplica si se usa la variable texto
% --- Executes during object creation, after setting all properties.
function selector_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function limite_Callback(hObject, eventdata, handles)
limite=str2double(get(hObject,'string'));
handles.limite=limite;
% --- Executes during object creation, after setting all properties.
function limite_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
% --- Executes on button press in ayuda.
function ayuda_Callback(hObject, eventdata, handles)
HelpNewton;
% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, ~, handles)
x1=handles.x1;
funcion=handles.funcion;
f=handles.f;
if x1==0
x1=x1+1;
elseif x1<0
x1=-x1;
end
% axes(handles.axes2);
%Imagen
figure (1);
x=-5*x1:0.001:5*x1;
plot(x,f(x),'Color','r'), title('Grafica de la funcion'), xlabel('Eje X'), ylabel('Eje Y'), grid;
hold on;
scatter(x1,f(x1));
Thank you very much!!!!!
About the tilde syntax: it is used to ignore an unused input, and as you don't use the eventdata in your callback, you can ignore it. This will remove the warning in the mlint (the orange underlining and the orange indicator in the scroll bar). Clearing all warnings will help you keep a clean code.
About the errors you are getting: you need to make sure all variables are in the handles struct when you want to use them. You can think about it the same way as with globals: you need to set them, otherwise they'll be empty.
I don't have the time to carefully look at your code right now, probably Tuesday I'll have more time, so you should try to fix it yourself.
I was able to solve those errors, everything is working but the plotting button. Sometimes when I press the button "Calcular", Matlab doesn't do anything, doesn't show something in the command window nor in the table I've already implemented on the GUI (it does work sometimes so Idk what the problem is) for about 2 minutes and only after that time it starts working and shows the correct answer. Then, when I want to plot the function and the point which represents the root, I get an error (it only shows when I input functions with the form: x^3 and I think the problem is that the function lacks a dot: x.^3) and I searched a bit on google and it says this. Also, when I press this button, Matlab takes WAY to long to do something, it just stays there. And sometimes it shows the next error:
Error using symengine Not a square matrix.
And when I press Ctrl+C in order to cancel it, I get the next error:
Operation terminated by user during sym/privBinaryOp (line 973)
In + (line 7)
X = privBinaryOp(A, B, 'symobj::zip', '_plus');
In : (line 43)
c = a + (0:n)*d;
In newton>pushbutton3_Callback (line 185)
x=-5*x1:0.001:5*x1;
In gui_mainfcn (line 95)
feval(varargin{:});
In newton (line 18)
gui_mainfcn(gui_State, varargin{:});
In
matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)newton('pushbutton3_Callback',hObject,eventdata,guidata(hObject))
Interrupt while evaluating UIControl Callback.
The code is:
x1=handles.x1;%global x1;
%funcion=handles.funcion;%global funcion;
f=handles.f;%global f;
if x1==0
x1=x1+1;
elseif x1<0
x1=-x1;
end
% axes(handles.axes2);
%Imagen
figure (1);
x=-5*x1:0.001:5*x1;
plot(x,f(x),'Color','red'), title('Grafica de la funcion'), xlabel('Eje X'), ylabel('Eje Y'), grid;
hold on;
scatter(x1,f(x1));
Any idea on how to fix this, please? Thanks in advance!
It looks like at some point x1 is a sym instead of a double. You should use the debugger to step through your code so you can see where the data type is changed.
Thanks for your comment! I debugged the code and convert x1 to a double using double(x1) and creating a new variable in order to use it with this new value but I get the next error:
Error using ^
One argument must be a square matrix and the other must be a scalar. Use
POWER (.^) for elementwise power.
Error in newton>@(x)x^3+10
Error in newton>pushbutton3_Callback (line 187)
plot(x,f(x),'Color','red'), title('Grafica de la funcion'), xlabel('Eje X'),
ylabel('Eje Y'), grid;
Error in gui_mainfcn (line 95)
feval(varargin{:});
Error in newton (line 18)
gui_mainfcn(gui_State, varargin{:});
Error in
matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)newton('pushbutton3_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating UIControl Callback.
Now the question is, how can I go around this? Because the user inputs x^3+10 but the code needs it to be like this: x.^3+10
Any ideas? Thanks in advance!
Edit 1: It only happens when I use exponents because when I plug a linear function, the program works flawlessly. Except when I plug in a trigonometric function, then it takes way to long... (I'm not sure how long because it has been running for more than 5 minutes and nothing has appeared).
Edit 2: I was able to find a workaround to the trigonometric function's error and it was using the matlabFunction like this:
df1=handles.df;
df=matlabFunction(df1);
Now it's working properly.
The only problem I have is when using functions like x^3 because, in order to plot it, the code needs it in the form x.^3.
Any help would be much appreciated.
You could replace
plot(x,f(x),'Color','red')
by
plot(x,arrayfun(f,x),'Color','red')
%untested, you might need to add 'UniformOutput',0 to arrayfun
That way the function is applied to each element separately, which makes it slower, but will prevent odd errors in cases of powers, multiplications, and divisions.

请先登录,再进行评论。

类别

标签

Community Treasure Hunt

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

Start Hunting!

Translated by