Clickable Plot Where non-clicked lines go transparent?

I have some plots that I want to be able to click on one or more lines and have all the other lines go semi-transparent while the clicked lines are brought to the front. I also want these lines to be able to be deselected so that I can go back to none of them being transparent
Dumbed down version of my code so far:
figure(1)
clf
p = panel();% create panel on the figure
p.pack(2, groupCount);% setup two rows and however many columns there are groups
for i = 1:length(data)
p(1, groupIdx(i)).select();%select the correct plot
plot(data(i).x1data, data(i).y1data, 'tag',sprintf(data(i).id)); %plot each line and give it a tag
p(2, groupIdx(i)).select();%select the correct plot
H1(i) = plot(data(i).x2data, data(i).y2data, 'tag',sprintf(data(i).id)); %plot each line and give it a tag
set(H1(i), 'ButtonDownFcn', {@LineSelected, H1(i)}); %make the line bold and at the front when it is clicked (from mathworks answer)
end
function LineSelected(ObjectH, EventData, H)
set(ObjectH, 'LineWidth', 2.5); %make bold
set(H(H ~= ObjectH), 'LineWidth', 0.5);
uistack(ObjectH, 'top'); %bring it to the front
end
This lets me select one or more lines, and when I select them they are brought to the front and made bold, but since my plots are all kind of on top of each other it gets hard to see the data, especially bold. And on top of that, once a line is clicked it cannot be deselected, so it is bold until I re-run the script. So instead of being bold I want everything else to just go transparent, but I also want to be able to deselect the lines if needed.

Answers (1)

Jan
Jan on 29 Apr 2021
Edited: Jan on 29 Apr 2021
To avoid setting the bolder linewidth, simply omit the change of the linewidth:
function LineSelected(ObjectH, EventData, H)
uistack(ObjectH, 'top'); %bring it to the front
end
Unfortunately there is no Alpha property for lines. So you either have to emulate the line objects by using patch objects, or you need another method to increase the visibility of the selected line: maybe some markers or by using dots for the other lines?
How do you select a line, which is covered by other initially?
What about using the 3rd dimension, to distribute the lines horizontally for a better overview:
function SelectorExample
X = rand(10, 100); % Ugly test data
FigH = figure;
Axes1H = subplot(1,2,1, ...
'Parent', FigH, 'NextPlot', 'add');
title(Axes1H, 'Data')
Axes2H = subplot(1,2,2, ...
'Parent', FigH, 'NextPlot', 'add');
title(Axes2H, 'For selection');
view(Axes2H, 3);
UD.Line1H = plot(Axes1H, X);
UD.Line2H = plot3(1:100, repmat(1:10, 100, 1), X, ...
'Parent', Axes2H);
set([UD.Line1H; UD.Line2H], 'ButtonDownFcn', {@SelectLine, FigH});
UD.Selected = [];
FigH.UserData = UD;
end
function SelectLine(LineH, EventData, FigH)
UD = FigH.UserData;
Index = find(LineH == UD.Line1H);
if isempty(Index)
Index = find(LineH == UD.Line2H);
end
if isequal(Index, UD.Selected) % Unselect:
UD.Selected = [];
UD.Line2H(Index).LineWidth = 0.5;
else
UD.Selected = Index;
set(UD.Line2H, 'LineWidth', 0.5);
set(UD.Line2H(Index), 'LineWidth', 2.5);
uistack(UD.Line2H(Index), 'top');
uistack(UD.Line1H(Index), 'top');
% Some blinking?!
for k = 1:5
set(UD.Line1H(Index), 'LineWidth', 3.5);
pause(0.1);
set(UD.Line1H(Index), 'LineWidth', 0.5);
pause(0.1);
end
end
FigH.UserData = UD;
end
You need to enable the 3D rotation in the right axes to get a proper view direction for an easier selection. Afterwards you have to deselect the rotation mode to be able to select the lines. This switching can be avoided, but this code is only a demonstration.
The code lets the line in the left diagram blink. Maybe this helps to see it. The main problem remains, that diagrams with a lot of equal curves are more or less impossible to undestand. Even transparency would not be a great help.

3 Comments

Thanks for your response. That's an interesting idea.
Typically the curves we want to highlight are at least somewhat different from the other curves (even if it's just a signgle spike up), so they aren't too dificult to click on. If they are all on top of each other then that's a good sign that the product is performing well and we don't tend to want to highlight these to point them out.
We currently use JMP to plot/highlight these traces (see below) and extract metrics and associated info, but since my data sets are so large it can take upwards of an hour just for JMP to plot all of these. Essentially I'm trying to mimic what JMP does, but in MATLAB since it's so much faster.
I like the idea of having an easier time selecting them using the 3D plot, but since we usually only look at the odd ones that stick out, it's not necessary. I also like the flashing idea, but since we usually screenshot these and put them on an internal website for sharing, I don't think I can utilize the flashing.
I implemented this bit of code but 1) changing the other lines to very thin and dotted doesn't appear to do anything (unsure if I'm doing it wrong or if that's just how it looks since each line is ~50,000 data points and is really dense/noisy), and 2) if it did do something I still can't "unselect" the yellow line I have already selected.
function LineSelected(ObjectH, EventData, H)
%set(ObjectH, 'LineWidth', 2.5);
set(H(H ~= ObjectH), 'LineWidth', 1/72);%make everything else the minimum line width
set(H(H ~= ObjectH), 'LineSpec', ':');
uistack(ObjectH, 'top');
end
Edit: After looking at your code (I'm trying and struggling to understant what exactly everything does), it looks like you actually implemented an "unselect" feature. And while playing with the graph it creates it clearly can be unselected. I'll try to implement that portion of your code into mine if I can figure it out.
Okay, I gave it my best shot of copying what you did and altering it to fit my needs. The code is a ways above my competency level, though. And the fact that my plotting is in a for loop is really making me struggle.
figure(1)
clf
p = panel();% create panel on the figure
p.pack(2, groupCount);% setup two rows and however many columns there are groups
for i = 1:length(data)
p(1, groupIdx(i)).select();%select the correct plot
UD(i).Line1 = plot(data(i).x1data, data(i).y1data, 'tag',sprintf(data(i).id)); %plot each line and give it a tag
p(2, groupIdx(i)).select();%select the correct plot
UD(i).Line2 = plot(data(i).x2data, data(i).y2data, 'tag',sprintf(data(i).id)); %plot each line and give it a tag
set([UD(i).Line1; UD(i).Line2], 'ButtonDownFcn', {@SelectLine, Fig1});; %make the line bold and at the front when it is clicked (from mathworks answer)
UD(i).Selected = [];
end
FigH.UserData = UD;
function SelectLine(LineH, EventData, FigH)
UD = FigH.UserData;
for i=1:length(UD) %pretty sure this is wrong?
if ~isempty(find(LineH == UD(i).Line2))
Index=i; %find the index of the selected line
end
end
if isempty(Index)
for i=1:length(UD)
if ~isempty(find(LineH == UD(i).Line1))
Index=i; %find the index of the selected line
end
end
end
if isequal(Index, UD(Index).Line2) % Unselect:
UD(Index).Selected = [];
UD(Index).Line2.LineWidth = 0.5;
else
UD(Index).Selected = Index;
set(UD(:).Line2, 'LineWidth', 1/72);
set(UD(Index).Line2, 'LineWidth', 0.5);
set(UD(:).Line1, 'LineWidth', 1/72);
set(UD(Index).Line1, 'LineWidth', 0.5);
uistack(UD(Index).Line2, 'top');
uistack(UD(Index).Line1, 'top');
end
FigH.UserData = UD;
end
It, of course, errors out "Error while evaluating ButtonDownFcn" on this line:
set(UD(:).Line2, 'LineWidth', 1/72);
In your code "UD(:).Line2" is a comma separated list, but you need a vector. Simply include it in square brackets: [UD(:).Line2] .
The code gets much easier, if you store vectors in the scalar struct, instead of scalars as fields of a struct array:
UD(i).Line1
% ==>
UD.Line1(i)

Sign in to comment.

Categories

Asked:

on 28 Apr 2021

Edited:

Jan
on 30 Apr 2021

Community Treasure Hunt

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

Start Hunting!