How to use myupdatefcn inside an 'if' loop

9 views (last 30 days)
Kris Adamatzky
Kris Adamatzky on 17 Apr 2016
Answered: Samayochita on 26 Feb 2025
It's difficult for me to word this question, but I will try my best.
Currently, I have a scatterplot of 100 songs, a data point for each song.
The songs are plotted using an if loop and colour-coded to particular genres and the name of the songs is displayed next to the data point:
FigA = figure
% Here you can choose which principal components you would like to plot
princ_compx = 1
princ_compy = 2
% Plotting the different colours for 10 different genres
% 'c' specifies colours (colour RGB triplets as rows of the matrix)
% 'cir' specifies circle size
c = [1 0 0;0 0 0;1 1 0;0 1 0;0 1 1;0 0 1;1 0 1;.5 .5 .5;1 .2 .5;.2 1 .5;.5 1 .2]
cir = 45
global songname
global bb
global song_data
for bb = 1:index
songname = getfield(songs(bb),'name');
if bb >= 1 & bb <=10
scatter(coeff(bb,princ_compx),coeff(bb,princ_compy),cir,c(1,:),'filled')
datacursormode on
dcm_obj = datacursormode(FigA);
set(dcm_obj,'UpdateFcn',@myupdatefcn)
elseif bb >= 91 & bb <=100
scatter(coeff(bb,princ_compx),coeff(bb,princ_compy),cir,c(10,:),'filled')
text(coeff(bb,princ_compx),coeff(bb,princ_compy),songname);
hold on
end
end
My goal is to make each data point interactive, so when you click it, it displays the song name related to that data point. This is to replace the already labelled names. However, I am finding it difficult to make my data point function decipher between the song names associated to the data points. Currently, when I click on a data point it simply displays the last song in the 'if' loop.
Here is my 'myupdatefcn':
function txt = myupdatefcn(~,event_obj)
%Customizes text of data tips
global songname
global bb
%Makes the data point pop-up say the Song name
pos = get(event_obj,'Position');
position = pos
txt = {['File name:', songname]};
Is there a way to make the data point function decipher between each individual song instead of simply using the last output of 'bb' (which is assigned in the songname variable)
I hope my explanation made at least some sense,
Kris

Answers (1)

Samayochita
Samayochita on 26 Feb 2025
Hi Kris Adamatzky,
I understand that you are trying to represent 100 songs as scatter plot points where each point is labelled. Clicking a data point should replace the existing label with a new label with the song name. Currently, when you click on a data point you are only able to display the last song.
I believe the issue because you are using a global variable ‘songname’ which is updated on each loop iteration. When the ‘myupdatefcn’ function is called, it only has access to the last assigned value of ‘songname’, causing all points to show the same (last) song name.
To resolve this issue, instead of using a global variable you can store the song names inside the ‘UserData’ property of each scatter point then dynamically retrieve the song name inside ‘myupdatefcn’.
Furthermore, you can use ‘datacursormode’ (https://www.mathworks.com/help/matlab/ref/matlab.graphics.shape.internal.datacursormanager.html) in this solution because it allows interactively creating and editing data tips in the scatter plot.
The relevant code sections are given below for your reference:
% Define a structure for song names
songs = struct();
for i = 1:index
songs(i).name = sprintf('Song %d', i);
end
% Enable data cursor mode
datacursormode on;
dcm_obj = datacursormode(FigA);
set(dcm_obj, 'UpdateFcn', @myupdatefcn);
% Store text labels globally
global textHandles;
textHandles = gobjects(index, 1);
Inside the for loop, you should plot the scatter points and store song name in ‘UserData’ as follows:
h = scatter(coeff(bb, princ_compx), coeff(bb, princ_compy), cir, c(color_idx, :), 'filled');
h.UserData = struct('name', songname, 'index', bb, 'pos', [coeff(bb, princ_compx), coeff(bb, princ_compy)]); % Store song name and position
% Create labels (always visible)
textHandles(bb) = text(coeff(bb, princ_compx), coeff(bb, princ_compy), songname, ...
'FontSize', 10, 'Color', 'k', 'FontWeight', 'normal', 'Tag', ['text' num2str(bb)]);
Moreover, you can update your myupdatefcn as follows:
function txt = myupdatefcn(~, event_obj)
global textHandles;
% Retrieve the clicked data point
clicked_point = get(event_obj, 'Target');
songData = clicked_point.UserData; % Retrieve stored song name and index
songname = songData.name;
songIndex = songData.index;
% Reset all labels to normal state
set(textHandles, 'Color', 'k', 'FontWeight', 'normal');
% Hide the previous label when a data point is clicked (set the color to none)
set(textHandles(songIndex), 'Color', 'none');
% Return the song name for tooltip
txt = {['Song name: ', songname]};
end
I hope this was helpful.

Community Treasure Hunt

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

Start Hunting!