Change plot in single axes on click (GUIDE)

Hi, I have a function that generates multiple plots (15 or so). I am able to display all of them (their titles) in a listbox. What I would like to do is to display the plot upon clicking on a proper title in a listbox.
\\This is part of a previous callback
set(handles.figures_list_tag,'string',fieldnames(handles.allfigures));
handles.fieldnames=fieldnames(handles.allfigures);
guidata(hObject,handles)
% --- Executes on selection change in figures_list_tag.
function figures_list_tag_Callback(hObject, eventdata, handles)
selected_figure_index=get(hObject,'Value');
figure_array=cellstr(get(hObject,'String'));
selected_figure=getfield(handles.allfigures,handles.fieldnames{selected_figure_index});
handles.figure_tag;
cla;
hold on
set(handles.figure_tag,'CurrentAxes',findobj(handles.allfigures,selected_figure))
guidata(hObject,handles)
Anyhow, this doesn't work, but just to give you an idea what I have so far. Any advice how to do this? Thanks in advance!

6 commentaires

Geoff Hayes
Geoff Hayes le 18 Juin 2018
luiv1616 - how do you expect to show the plot in the axes? Have you already plotted it but have chosen to hide the plot until you need to show it? Please clarify...
luiv1616
luiv1616 le 18 Juin 2018
Dear Geoff, the plots are generated but only the last is shown (function creates 15 functions so after you run it you only see the last figure), I would like to access any of those 15 by clicking on that specific figure in listbox. The code I've given fills the listbox with names of plots, however I don't know how to display it upon clicking on it's appropriate name. Bottom line, plots do exists I just don't have access to them in GUI. Also, just to clarify, I have a figure box in GUI, one figure box to be precise, that is where I want to display specific plots generated by the function. Thanks and I hope it is clear(er) now.
Geoff Hayes
Geoff Hayes le 18 Juin 2018
luiv1616 - so you have 15 functions that have been plotted on 15 figures and you can grab a list of the names of each figure which you show in your GUI. Your GUI also has an axes which you wish to "copy" or "show" the plot from figure x. For example, if the user selects the second figure from the list, then you want to copy the plot from the second figure to your GUI axes. is that correct?
If the above is correct, can you clarify why you want to do this. Why plot the 15 functions on 15 figures? Why not just plot them within the axes and hide or show them as needed?
luiv1616
luiv1616 le 19 Juin 2018
Yes, that is correct. How would you do that? I guess tuning the visibility is the easier way, but I don't know how access specific plot from the listbox.
Whenever you call plot, it returns a handle to the plot graphics object. i.e.
hPlot = plot(handles.axes1, x, y);
You can then show or hide the plot with the handle
set(hPlot, 'Visible', 'off');
or
set(hPlot, 'Visible', 'on');
So draw all of your 15 functions to the axes of your GUI. You should be able to set the default visibility state to off for each one. And you can save all of these 15 graphic object handles to the handles structure of your GUI so that you can later access them. For example,
hPlot1 = plot(handles.axes1, x, y, 'Visible', 'off');
hPlot2 = ....
handles.plotHandles = [hPlot1 hPlot2 ...];
guidata(handles);
luiv1616
luiv1616 le 20 Juin 2018
Thanks Geoff, the problem is that I don't know how to access them, when I click on specific plot (in a listbox) it is not diplayed on the axes in GUI.

Connectez-vous pour commenter.

 Réponse acceptée

Geoff Hayes
Geoff Hayes le 20 Juin 2018
luiv1616 - see the attached code for a quick example. In the GUI OpeningFcn, we create the plots and hide all but the first one
x = -2*pi:0.001:2*pi;
hold(handles.axes1, 'on');
h1 = plot(handles.axes1, x, sin(x), 'r', 'Visible', 'on');
h2 = plot(handles.axes1, x, cos(x), 'b', 'Visible', 'off');
h3 = plot(handles.axes1, x, tan(x), 'g', 'Visible', 'off');
We then update the list box with the plot names
listValues = {'sin', 'cos', 'tan'};
set(handles.listbox1, 'String', listValues');
and save the graphics objects handles to the handles struct
handles.plotHandles = [h1 h2 h3];
guidata(hObject, handles);
(The guidata call is important as it will save the updated handles struct with the new plotHandles member.)
In our list box callback, we just grab the index of the selected list item and set its corresponding graphics object visibility to ON (and turn all others to off)
selectedPlotIndex = get(hObject, 'Value');
set(handles.plotHandles(selectedPlotIndex), 'Visible', 'on');
for k=1:length(handles.plotHandles)
if k ~= selectedPlotIndex
set(handles.plotHandles(k), 'Visible', 'off');
end
end
Try the above and see what happens!

11 commentaires

luiv1616
luiv1616 le 21 Juin 2018
Modifié(e) : luiv1616 le 21 Juin 2018
Thanks Geoff, this does work. However, in my case I am not switching between single plots, I have different number of plots plotted, so I can't concatenate handles.plotHandles whenever I generate a specific figure (dimension mismatch). This is why I tried to go with struct, i.e. handles.plotHandles.hPlot1 (2,3, etc), but I can't access struct by indexing. Is there a way around this?
luiv1616 - so you have multiple plots that you want to hide or show for one "figure"? I'm not sure why it isn't working for your code (you would need to post it).
But if you have "sets" of plots, then why not just use a cell array to manage the arrays of plot handles for each "figure". So in the above code, you might do
plotHandles = cell(2,1);
h1 = plot(handles.axes1, x, sin(x), 'r', 'Visible', 'on');
h2 = plot(handles.axes1, x, cos(x), 'b', 'Visible', 'on');
h3 = plot(handles.axes1, x, tan(x), 'g', 'Visible', 'on');
plotHandles{1} = [h1 h2 h3];
h4 = plot(handles.axes1, x, sin(x), 'r', 'Visible', 'off');
h5 = plot(handles.axes1, x, cos(x), 'b', 'Visible', 'off');
plotHandles{2} = [h4 h5];
etc.
Then when you show or hide the plots, you would need to iterate over each array in the cell array.
luiv1616's answer moved here
Ok, so I plot a figure (kind of an opening figure, raw data or whatever) which is initialized immediately after I load the file, and this plot is 136x1 line array:
hPlot1=plot(handles.Axes1,x,data1,x,data2,'k'); %136x1 line array
I add it to handles.plotHandles:
handles.plotHandles=cat(2,handles.plotHandles,hPlot1);
Then in the next callback, suppose I average the data1 and data2 (after clicking some pushbutton) in certain way, now I have a new plot:
hPlot2=plot(handles.Axes1,x,avgdata1,x,avgdata2,'k') %This is no longer 136x1 but less
And if I want to add this to array of all plots I can't because of a dimension mismatch:
handles.plotHandles=cat(2,handles.plotHandles,hPlot2);
Error using cat
Dimensions of matrices being concatenated are not consistent.
Similarly, I could add some lines on the initial plot (hPlot1), for example vertical lines if I need to divide the plot in sections, but I still want the option to look at the initial plot without these lines, then I would have run into the same problem.
hPlot3=gca; %I use gca in order to avoid drawing the same plot over and over again I just draw division lines over it and save alltogether
hPlot3=hPlot3.Children; %this one could be 234x1 line array
handles.plotHandles=cat(2,handles.plotHandles,hPlot3);
Error using cat
Dimensions of matrices being concatenated are not consistent.
Rather than using cat, I would just use the [] brackets to create your array. So the first time that you initialize your plotHandles array it would be like
handles.plotHandles= hPlot1;
since you have just the one handle. Now when you want to add your second handle to the array, you would do
handles.plotHandles = [handles.plotHandles ; hPlot2];
which should create a column of handles. This will only work depending upon the dimensions of hPlot1 and hPlot2. Without having access to your data (or running your GUI) I don't know what they are. Typically these will both be scalars i.e. 1x1. But in some cases, depending upon the data that you are plotting, you may actually get two (or more) handles back to two (or more) graphics object. If the dimensions are different between hPlot1 and hPlot2, then you will not be able to concatenate them.
Please put breakpoints at the lines in your code where you update the handles.plotHandles with the second handle and then run your code. When the debugger "pauses" at this line, check the dimensions of handles.plotHandles and the dimensions of hPlot2. Are they compatible?
Ok, as I mentioned before these are Line arrays and their dimension don't agree.
K>> size(handles.plotHandles)
ans =
136 1
K>> size(hPlot2)
ans =
471 1
When I proceed with your suggestion (using [handles.plotHandles; hPlot2] instead of cat) I get a 607x1 line array, since he concatenates along a single column:
handles.plotHandles=[handles.plotHandles; hPlot2];
K>> size(handles.plotHandles)
ans =
607 1
K>> handles.plotHandles
ans =
607×1 Line array:
Line
Line
Line
Line
Line
... %and so on to 607
so you have have a function that generates multiple plots (15 or so) but each of these 15 plots can be made up of one or more (100+) individual plots. And presumably you want to keep each of these 15 plots separate. So use a cell array
% initialize as cell array
handles.plotHandles = {};
handles.plotHandles = [handles.plotHandles; hPlot1];
and then later
handles.plotHandles = [handles.plotHandles; hPlot2];
So handles.plotHandles should be (at this point) a cell array of two elements where each element is an array of one or more handles to graphics objects.
luiv1616
luiv1616 le 26 Juin 2018
The thing is that handles.plotHandles is not a cell array but a line array, containing all the lines from all the plots, so what happens is when you try to access plots by indexing you can access only one line. hPlot1 is not [1x1] cell array but [136x1] line array. Furthermore, since hPlot1, hplot2, ..., hPlotn differ in size it's not possible to concatenate them in a way that you can access by indexing.
Geoff Hayes
Geoff Hayes le 26 Juin 2018
handles.plotHandles is not a cell array but a line array... but it could be a cell array, correct? What is preventing it from being one?
luiv1616
luiv1616 le 26 Juin 2018
Modifié(e) : luiv1616 le 26 Juin 2018
It could be if you convert them with num2cell, but it still doesn't solve the issue since it converts line to cell as 1:1 (for 9x1 line array you get 9x1 cell array etc). Also, if I try to change visibility I get an error:
Error using set
Conversion to double from cell is not possible.
Is there a way to group these lines somehow and just pass that variable between callbacks?
Right now, I used set(hPlot1,'tag','PlotName1') and just concatenated all line arrays to single column of handles.plotHandles. I saved all the tags in character array which I can access by indexing. The problem now is that when I try to access selected figure with findobj MATLAB says it's empty:
K>> findobj(handles.plotHandles,'tag',handles.taglist(selected_figure_index))
ans =
0×0 empty GraphicsPlaceholder array.
but why do you need to convert the array of handles to a cell? Just store it as an array within the cell array.
handles.plotHandles = cell(2,1);
handles.plotHandles{1} = [1 2 3 4 5];
handles.plotHandles{2} = [5 6];
And in order to get the line array for the second plot (for example) you would just do
handles.plotHandles{2}
So we allow for line arrays of different dimensions to be stored within the cell array and we can access those line arrays when we need to.
luiv1616
luiv1616 le 29 Juin 2018
Thanks Geoff, this works!

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Creating, Deleting, and Querying Graphics Objects dans Centre d'aide et File Exchange

Produits

Version

R2016b

Community Treasure Hunt

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

Start Hunting!

Translated by