散点饼图

3

我正在尝试可视化软聚类。有许多点和少量聚类,每个点以某种概率属于每个聚类。

目前,我正在为每个聚类叠加散点图,'o'标记的大小随概率变化。这样可以轻松识别最可能的聚类,但不太了解其它情况。

我想绘制一个饼状图的散点图,即每个数据点都有一个小的饼状图,显示这些概率。在Matlab中是否可能实现?我没有找到一种方法来将饼状图绘制为标记或在一个图中放置多个饼状图...

2个回答

5
作为首次尝试,我只使用了两个LINE图形对象来绘制每个点上的饼图:一个用于圆圈,另一个用于圆圈内的分区。因此,我们只是绘制未填充的饼图。
这在性能方面非常高效。它通过使用NaN将线条分成段来实现。与其他提议的解决方案相比,如果我们查看其源代码,我们会发现它为每个单独的点创建一个轴,并在其中调用MATLAB的函数PIE
我们从一些数据点开始,以及它们的“模糊聚类”:
numPoints = 15; numClasses = 5;

%# random 2D points
points = randn(numPoints,2);

%# fuzzy clustering: probabilistic distribution
prob = rand(numPoints,numClasses);
prob = bsxfun(@rdivide, prob, sum(prob,2));

现在这里有绘制饼图散点图的代码:
%# pie parameters
theta = linspace(0, 2*pi, 100); %# steps to approximate a circle
r = min(range(points)) / 10;    %# radius (determined based on points spread)

%# pie circles
px = bsxfun(@plus, cos(theta).*r, points(:,1))';
py = bsxfun(@plus, sin(theta).*r, points(:,2))';
px(end+1,:) = NaN; py(end+1,:) = NaN;

%# pie divisions
tt = cumsum(prob,2) .* 2*pi;
qx = cat(3, ...
    bsxfun(@plus, cos(tt).*r, points(:,1)), ...
    repmat(points(:,1), [1 numClasses]), ...
    NaN(numPoints,numClasses));
qy = cat(3, ...
    bsxfun(@plus, sin(tt).*r, points(:,2)), ...
    repmat(points(:,2), [1 numClasses]), ...
    NaN(numPoints,numClasses));
qx = permute(qx, [3 2 1]); qy = permute(qy, [3 2 1]);

%# plot
figure
line(px(:), py(:), 'Color','k')
line(qx(:), qy(:), 'Color','k')
axis equal

screenshot1


在我的第二次尝试中,我成功地使用PATCH函数绘制每个圆中的每个部分,从而实现了彩色饼图的绘制。显然,这意味着我们要比以前创建更多的图形对象...

我们本可以使用相同的NaN技术,通过单个PATCH调用来绘制每个圆中的相同部分,但当饼图重叠时(具体来说是z-order不正确),这种方法会出现问题。

clr = hsv(numClasses);          %# colors for each class
r = min(range(points)) / 10;    %# radius (determined based on points spread)
tt = cumsum(prob,2) .* 2*pi;    %# pie divisions

figure
h = zeros(numPoints,numClasses);    %# handles to patches
for idx=1:numPoints                 %# for each point
    for k=1:numClasses              %# for each class
        %# start/end angle of arc
        if k>1
            t(1) = tt(idx,k-1);
        else
            t(1) = 0;
        end
        t(2) = tt(idx,k);

        %# steps to approximate an arc from t1 to t2
        theta = linspace(t(1), t(2), 50);

        %# slice (line from t2 to center, then to t1, then an arc back to t2)
        x = points(idx,1) + r .* [cos(t(2)) ; 0 ; cos(t(1)) ; cos(theta(:))];
        y = points(idx,2) + r .* [sin(t(2)) ; 0 ; sin(t(1)) ; sin(theta(:))];
        h(idx,k) = patch('XData',x, 'YData',y, ...
            'FaceColor',clr(k,:), 'EdgeColor','k');

        %# show percentage labels
        ind = fix(numel(theta)./2) + 3;     %# middle of the arc
        text(x(ind), y(ind), sprintf('%.2f%%', prob(idx,k)*100), ...
            'Color','k', 'FontSize',6, ...
            'VerticalAlign','middle', 'HorizontalAlign','left');
    end
end
axis equal

labels = cellstr( num2str((1:numClasses)', 'Cluster %d') );
legend(h(1,:), labels)

如果百分比标签太多,只需删除上面的TEXT调用即可。

太好了!我必须使用 set(gcf, 'Renderer', 'painters'); 否则这些线会在所有东西的上面。 - pascal
@Amro:我建议你将其作为FileExchange提交。如果正确处理输入输出参数、错误处理等,它很容易成为“本周之巅”。MATLAB确实缺少这样的功能。BubblePie为每个饼图使用单独的轴,并存在许多其他问题。祝好运! - yuk
一个建议:让圆的半径r取决于sum(prob,2)(对于初始概率)。 - yuk
@yuk:谢谢,也许我就这么做吧(我一直想将我的一些自定义文件提交到FEX,但从未找到时间创建一个干净的API函数)。如果您愿意,您也可以这样做,毕竟SO上的贡献都是在cc-by-sa下授权的,因此在此帖子中添加归属链接应该足够了(有点像FEX上的“灵感来自”功能)。 - Amro

4

Bubble Pie由Abraham Anderson在Matlab文件交换平台上发布,似乎与您所描述的内容相关。

enter image description here


啊,谢谢,我不知道有文件交换这个功能。但是用这种方式绘制数百个数据点还是有点慢。 - pascal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接