带工具提示的 MATLAB 散点图显示其他类型的数据和带箭头的连接点

MATLAB scatter with tooltip showing other kinds of data and connecting points with arrowhead

我想在这里问两个问题。简而言之,

  1. 在 MATLAB 的散点图中,如何使用工具提示单击一个点而不是获取 x,y 数据,而是获取与 x,y 点关联的其他类型的数据?现在我有一个使用 gscatter 和来自文件交换的文件的解决方法(见下文)。但对于大型数据集来说,它会变得混乱。

  2. 如何用箭头连接两点?例如,在 MATLAB 绘制的 rlocus 图中,有一个漂亮的小箭头。在 MATLAB 中有针对任意绘图的本机方法吗?

考虑MATLAB中的数据集

clearvars
LionNames={'Tyrion','Jamie','Cersei'};
Data = rand(3,2,2);
LionsDay1=struct('Names',{},'Data',[]);
LionsDay2=struct('Names',{},'Data',[]);

for i =1:numel(LionNames)
    LionsDay1(i).Names=LionNames{i};
    LionsDay1(i).Data=Data(i,:,1);
    LionsDay2(i).Names=LionNames{i};
    LionsDay2(i).Data=Data(i,:,2);
end

WolfNames = {'Robert','Arya','Sansa','Jon'};
Data = rand(4,2,2);
WolvesDay1=struct('Names',{},'Data',[]);
WolvesDay2=struct('Names',{},'Data',[]);

for i =1:numel(WolfNames)
    WolvesDay1(i).Names=WolfNames{i};
    WolvesDay1(i).Data=Data(i,:,1);
    WolvesDay2(i).Names=WolfNames{i};
    WolvesDay2(i).Data=Data(i,:,2);
end

这里每组的数据是x和y数据。出于这个问题或示例的目的,上面的数据结构并不是那么重要,但我已经做到了,因此 reader 可以了解全局。


所以使用文件 from MATLAB file exchange 我能够散点图并命名每个点以及它是 class。例如,

lionsData=reshape([LionsDay1(:).Data],2,3);
wolvesData=reshape([WolvesDay1(:).Data],2,4);
xData=[lionsData(1,:) wolvesData(1,:)];
yData=[lionsData(2,:) wolvesData(2,:)];
group=repmat({'Lions'},[1,3]);
group= [group repmat({'Wolves'},[1,4])];
gscatter(xData',yData',group');

Names=[LionNames WolfNames];
labelpoints(xData,yData,Names)

创建,

但是你可以想象,这对于大型数据集(>50 个数据点)来说会变得很混乱;或者如果这些点非常接近,因此是第一个问题。单击一个点以显示名称会好得多。


对于第二个问题,做,

day1Lions=reshape([LionsDay1(:).Data],2,3);
day2Lions=reshape([LionsDay2(:).Data],2,3);

for k = 1 : size(day1Lions, 2)
    plot([day1Lions(1,k), day2Lions(1,k)], [day1Lions(2,k), day2Lions(2,k)],'s-');
    hold on
end
legend('Tyrion','Jamie','Cersei')

给予,

所以在某种意义上我们可以看到两个点在第 1 天和第 2 天之间发生了多少变化但是现在我不知道哪个是第 1 天和第 2 天。最好放一个从第 1 天数据点到第 2 天数据点的箭头。当然,如果上面的 hover/tooltip 问题有足够灵活的答案,那也可能会解决这个问题。

当然最后,我们也会在第 1 天和第 2 天将狮子和狼混在一起,但是回答这两个简单的问题也可能会在做组合情节时解决问题。

答案 1

一种解决方案是为数据工具提示定义自己的回调函数。为此,您首先需要在图中保存 Names。我们可以为此使用 UserData 属性:

% modify the end of your code to:
gsh = gscatter(xData',yData',group');
Names = [LionNames WolfNames];
set(gsh,{'UserData'},{Names});

接下来,我们创建以下回调函数(我使用了 Matlab 的 defualt 并对其进行了编辑),并将其保存在新的 m 文件中:

function output_txt = tooltip_callback(obj,event_obj)
% Display the position of the data cursor
% obj          Currently not used (empty)
% event_obj    Handle to event object
% output_txt   Data cursor text string (string or cell array of strings).

pos = get(event_obj,'Position');
output_txt = {['X: ',num2str(pos(1),4)],...
    ['Y: ',num2str(pos(2),4)],...
    event_obj.Target.UserData{event_obj.Target.XData==pos(1)}}; % <- this line is the only change
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
    output_txt{end+1} = ['Z: ',num2str(pos(3),4)];
end

现在我们点击图中的其中一个工具提示并选择Select文本更新函数:

然后从浏览器中选择我们保存的回调函数。

结果:

以同样的方式,如果需要,您可以将日期添加到工具提示中,或者使用我对 Q2 的回答...

答案 2

下面是如何使用 annotations 来做到这一点:

ax = axes;  % create the axis
% plot all lines (no need for the loop) so we can put the legend after:
p = plot(day1Lions,day2Lions,'-');
legend('Tyrion','Jamie','Cersei')
% get the lines colors:
col = cell2mat(get(p,'Color'));
% loop through the arrows:
for k = 1:size(day1Lions, 2)
    % get the data coordinates:
    x = day1Lions(:,k);
    y = day2Lions(:,k);
    pos = ax.Position;
    % convert them to normalized coordinates:    
    %  white area * ((value - axis min)  / axis length)  + gray area
    normx = pos(3)*((x-ax.XLim(1))./range(ax.XLim))+ pos(1);
    normy = pos(4)*((y-ax.YLim(1))./range(ax.YLim))+ pos(2);
    % plot the arrow
    annotation('arrow',normx,normy,'Color',col(k,:))
end

结果:

您还可以将原始行设置为不可见,方法是:

set(p,{'Visible'},{'off'})

但它会使图例文本变成灰色,而且它们完全被箭头覆盖了。