make an interactive graphic?

Hey everyone !
I'm a french student (so sorry if my english is not perfect) and i am currently working on a GUI matlab.
I would like to create a matrice where I can click on some "boxes".
I already create a matrice (the photo is linked to the topic), and on this matrice I would like to click on one of the nine boxes and something will happen (like the boxe change of color).
I hope it was quite clear and understandable ! (if not you can ask me for some questions).
Thanks you very much in advance for your answer !

 Respuesta aceptada

Steven Lord
Steven Lord el 26 de Jul. de 2021

0 votos

Before plotting the ButtonDownFcn works well but after plotting nothing happen.
So you did something like this?
ax = axes;
ax.ButtonDownFcn = @(varargin) disp('hi');
% Click on the axes, see that 'hi' is displayed
plot(ax, 1:10, 1:10);
% Click on the axes, nothing is displayed
If so that's correct. From the description of the NextPlot property for axes, "Properties to reset when adding a new plot to the axes, specified as one of these values:" The default behavior is "'replace' — Delete existing plots and reset axes properties, except Position and Units, to their default values before displaying the new plot."
You could use hold on before the plot call to not reset the axes ButtonDownFcn property or you could set the ButtonDownFcn of the axes after calling plot not before. Alternately depending on what you're plotting you may be able to call a lower-level plotting function (line instead of plot.)
But without turning the HitTest property for the line created by either plot or line to 'off' clicking exactly ON the line (or I think within a pixel or three of it) won't trigger the ButtonDownFcn function even if it is set.
Though with that picture, do you need to click on an axes? I'd consider making a 3-by-3 grid of buttons and giving each button an appropriate callback.

7 comentarios

dsq dq
dsq dq el 26 de Jul. de 2021
Well this is not a picture. Here you will find a summary of what I did :
handles.taille_matrice = 5;
handles.taille_matrice = handles.taille_matrice + 1 ;
X = zeros(handles.taille_matrice,handles.taille_matrice);
C = zeros(handles.taille_matrice,handles.taille_matrice);
for x = 1.0: 1: handles.taille_matrice
for y = 1.0: 1: handles.taille_matrice
X (x,y) = y;
if (x ==handles.taille_matrice)
C(x,y) = 2;
elseif(y==handles.taille_matrice)
C(x,y) = 2;
else
C(x,y) = 1;
end
end
end
Y = X';
mymap = [0 0 0; 1 1 1];
s = pcolor(X,Y,C);
s.EdgeColor = [1 0.7 0.3];
colormap(mymap);
function axes2_ButtonDownFcn(hObject, eventdata, handles)
CP = get(handles.axes2,'CurrentPoint')
As you can see I am not plotting anything (don't really how it is happening but it's working ^^'). I don't really see how can I call the ButtonDownFcn after the graph gets plot because it's here at the start.
pcolor creates a surface object. The same thing regarding the NextPlot property probably applies here as well, but the more important thing is that it looks like you set the axes callback in the GUIDE editor, but you don't set it after the plotting has been completed.
Also, the axes doesn't have a CurrentPoint property, the figure has one.
handles.taille_matrice = 5;
handles.taille_matrice = handles.taille_matrice + 1 ;
X = zeros(handles.taille_matrice,handles.taille_matrice);
C = zeros(handles.taille_matrice,handles.taille_matrice);
for x = 1.0: 1: handles.taille_matrice
for y = 1.0: 1: handles.taille_matrice
X (x,y) = y;
if (x ==handles.taille_matrice)
C(x,y) = 2;
elseif(y==handles.taille_matrice)
C(x,y) = 2;
else
C(x,y) = 1;
end
end
end
Y = X';
mymap = [0 0 0; 1 1 1];
s = pcolor(X,Y,C);
s.EdgeColor = [1 0.7 0.3];
colormap(mymap);
%-- not required in your code
handles.axes2=gca;
%--
set([s handles.axes2],...
'ButtonDownFcn',@(h,e)axes2_ButtonDownFcn(h,e,guidata(h)))
function axes2_ButtonDownFcn(hObject, eventdata, handles)
CP = get(handles.figure,'CurrentPoint')
end
dsq dq
dsq dq el 26 de Jul. de 2021
Ok I see my error now. I'm quite new on Matlab. Thanks you so much it's working now ! :)
The pcolor call resets the axes properties as you can see from this example.
ax = axes('ButtonDownFcn', @(varargin) disp('hi'));
ax.ButtonDownFcn % ButtonDownFcn is set prior to pcolor call
ans = function_handle with value:
@(varargin)disp('hi')
pcolor(magic(3)) % This resets the axes properties
ax.ButtonDownFcn % ButtonDownFcn has been reset to default
ans = 0×0 empty char array
For pcolor you'd definitely want to set its HitTest property to 'off' if you want to be able to click on the axes rather than the pcolor plot. Or you could set the ButtonDownFcn for the pcolor plot directly.
p = pcolor(magic(3));
p.ButtonDownFcn = @(varargin) disp('hi');
Rik
Rik el 26 de Jul. de 2021
Since you're new on Matlab: I suggest you don't use GUIDE. It will be deprecated soon and it isn't a good help in the first place. For general advice and examples for how to create a GUI (and avoid using GUIDE), have look at this thread.
dsq dq
dsq dq el 26 de Jul. de 2021
Yes it seems it's not the best but I don't really have the choice, my professor ask me to use it ...
I just have one another question and everything should be fine ! I have declared variables in a callback function and I would like to use again those variables but matlab write an error like "Unknown variable" (I don't remember the exact sentence. Should I use pointer or is there a way to celare variables to not be local to a function ?
Rik
Rik el 26 de Jul. de 2021
Can you ask your professor why they're teaching bad tools? There could be a reason, but I don't really see the point.
As for your question: every function is a separate function with its own variables. If you want to share variables between different functions of a GUI you should store them in fields of the guidata struct. There are ways to have variables be available in multiple functions, but you should not be using them as long as you have alternatives.

Iniciar sesión para comentar.

Más respuestas (1)

Rik
Rik el 26 de Jul. de 2021
Editada: Rik el 26 de Jul. de 2021

0 votos

You can use the ButtonDownFcn property to trigger a function when the user clicks on an axes object.
You can use the CurrentPoint property of the figure to retrieve the position of the cursor. This is reported in the units defined in the Unit property of the figure. You then need to convert those to the units of your image.
For general advice and examples for how to create a GUI (and avoid using GUIDE), have look at this thread.
Edit:
The code below doesn't work in the online editor (as that doesn't support interactivity), but you should not have any issues otherwise.
%get an example image
figure,IM=repelem(get(image,'CData'),10,10);close
%create figure with image
h.f=figure('Units','Normalized');
h.ax=axes('Parent',h.f);
h.im=imshow(IM,[],'Parent',h.ax);
%set callbacks
h.ax.ButtonDownFcn=@Callback;
h.im.ButtonDownFcn=@Callback;
%store in guidata
guidata(h.f,h)
function Callback(hObject,eventdata)
%load the guidata handles struct
h=guidata(hObject);
clc,get(h.f,'CurrentPoint')
end

8 comentarios

dsq dq
dsq dq el 26 de Jul. de 2021
Thank you for your answer. It looks like what I need is the ButtonDownFcn. I tried it but when I click on my axes nothing happen, like I'm doing something wrong. Like is there a way to click on the graph ? Or just left-clicking on it should make something ?
Rik
Rik el 26 de Jul. de 2021
If you click on the axes (with either of the buttons), the ButtonDownFcn will run. You need to write a function that will do the rest of the work. Did you already set a ButtonDownFcn? Can you post that function here?
dsq dq
dsq dq el 26 de Jul. de 2021
I wrote this for a simple test :
function axes2_ButtonDownFcn(hObject, eventdata, handles)
disp('a');
and my axes is still the same that I linked on my first message (the huge black matrice with orange border).
I think it's supposed to write a in the chat but nothing is happening :( .
Steven Lord
Steven Lord el 26 de Jul. de 2021
Did you already have something plotted on the axes? If so did you click on the axes or on (or very near) the thing you plotted on the axes? The former should work, the latter not. If you want clicking on the thing you plotted to actually "count as" clicking on the axes, change the HitTest property of the thing you plotted to 'off'.
dsq dq
dsq dq el 26 de Jul. de 2021
Yes I noticed that i forgot it. I wrote this line but nothing happen. I have plotted a matrice and when I lick on it nothing happen in the buttondownfcn callback.
dsq dq
dsq dq el 26 de Jul. de 2021
It seems like I have a famous problem. Before plotting the ButtonDownFcn works well but after plotting nothing happen. I tried some solution but no one seems to work. If anybody know the magic solution, it would be a pleasure to have it ! :)
Rik
Rik el 26 de Jul. de 2021
A lot of the bigger graphics functions will wipe the previous settings. imshow is one them. You should either use the primitives (image/line/patch/etc), modify the properties of your objects, or reset things like callbacks after every call.
Steven Lord
Steven Lord el 26 de Jul. de 2021
A lot of the bigger graphics functions will wipe the previous settings.
That's the default behavior. You could use hold on to change the NextPlot property of the figure and axes to 'add' (which will leave children alone and not reset properties.) Or you could manually change the NextPlot properties to 'add' or 'replacechildren' neither of which will reset the axes properties.

Iniciar sesión para comentar.

Categorías

Más información sobre Creating, Deleting, and Querying Graphics Objects en Centro de ayuda y File Exchange.

Etiquetas

Preguntada:

el 26 de Jul. de 2021

Comentada:

el 26 de Jul. de 2021

Community Treasure Hunt

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

Start Hunting!

Translated by