饼图图标放置算法

时间:2013-03-28 10:46:08

标签: algorithm pie-chart labels

我在尝试绘制饼图时遇到问题。 Design example

当然,绘制图表没有问题,问题是图标放置。 理想情况下,图标应放在圆圈上(让我们暂时忘记百分比标签)。

然而,当存在具有较小值的邻居项时,设计显然会中断。

Implementation example

您能推荐一种解决此问题的算法吗?为了简化,作为输入,我们有:
PIE_RADIUS - 馅饼的外半径。
ICON_RADIUS - 图标圈的半径 ICON_PLACEMENT_RADIUS - 理想放置图标中心时圆的半径 NUM_ICONS - 要放置的图标数量 iconAngles每个图标的角度,位于其部分的中心

要求的输出:
对于放置在饼图周围的项目,iconAnglesiconPositions将图标移出理想圆圈时,可以(0, 0)

我知道如何检查两个图标是否重叠。 我们可以认为馅饼的中心位于{{1}}。

(该实现是iOS应用程序的一部分,但我对一般算法感兴趣)。

3 个答案:

答案 0 :(得分:1)

第一个天真的算法,我们“推”与其他图标重叠的图标:

FOR iconToPlace in icons do:
    isPlaced = false

    WHILE(not isPlaced) DO:
        isPlaced = true
        FOR icon in icons DO:
            IF overlap(iconToPlace, icon) AND iconToPlace != icon THEN:
                isPlaced = false
                push(iconToPlace) // same angle but the icon is now further
                BREAK
            ENDIF
        ENDFOR
    ENDWHILE

ENDFOR

使用这个第一个算法,一些图标将从中心进一步比其他图标更远。但它没有通过改变角度来利用可能的地方。通过将其应用于您的第二个设计(具有较小的值),很明显该解决方案将远离理想的解决方案。

第二个不太天真的算法,首先我们为每个图标分配一个新的角度(差值小于DeltaAngleMax),然后我们应用第一个算法:

icons = SORT(icons)
iconsRef = icons
isFinished = false
WHILE(not isFinished) DO:
    isFinished = true
    FOR i = 0 TO i = NUM_ICONS-1 DO:
        IF   overlap(icons(i), icons(i+1 % NUM_ICONS))
         AND not overlap(icons(i), icons(i-1 % NUM_ICONS)) //seems useless
         AND not overlap(icons(i)-DeltaAngle % 360, icons(i-1 % NUM_ICONS))
         AND ABS(icons(i)-iconsRef(i)) <= DeltaAngleMax THEN:
            //overlap with next icon but not with previous, 
            //if we decrease angle we still not overlap with previous icon and
            //the futur delta angle is less than DeltaAngleMax
            //then we can move the icon :
            icons(i) = icons(i)-DeltaAngle
            isFinished = false
        ELSE IF   overlap(icons(i), icons(i-1 % NUM_ICONS))
         AND not overlap(icons(i), icons(i+1 % NUM_ICONS))  //seems useless
         AND not overlap(icons(i)+DeltaAngle % 360, icons(i+1 % NUM_ICONS))
         AND ABS(icons(i)-iconsRef(i)) <= DeltaAngleMax THEN:
            //vice et versa:
            icons(i) = icons(i)+DeltaAngle
            isFinished = false
    ENDFOR
ENDWHILE

APPLY_FIRST_ALGO

明智地选择deltaAngle和DeltaAngleMax。 deltaAngle太少会导致大的运行时间。

为了更进一步,你应该看看the force-directed graph drawing算法,这是一种更加健壮的方法来实现你的目标,其中一个难点是找到正确的节点力(你的图标,你没有边缘) )。

答案 1 :(得分:1)

只是头脑风暴:

具有适应度函数的遗传算法,其具有重叠的高惩罚加上等于每个候选位置与其理想位置之间的角距离的平方和(相对于其切片居中)的惩罚。

答案 2 :(得分:0)

我实施的解决方案如下:

  1. 计算所有图标相对于其切片的位置(以ICON_PLACEMENT_RADIUS为中心的图标)
  2. 查找重叠图标的序列(迭代图标并检查下一个图标是否与前一个图标重叠)。
  3. 计算两个图标(约(2.0f * ICON_RADIUS + 1.0f) / ICON_PLACEMENT_RADIUS
  4. 之间的最小角距离
  5. 计算序列的中心(对序列的所有切片求和并找到中心),将图标放在一起(它们之间的距离是最小角距离)。
  6. 放置所有图标后,检查图标是否重叠,如果是,则合并其序列并进行迭代。
  7. 请注意,只有当所有图标数量与圆圈的大小相比较小时,此算法才有效,但它很简单且非常快。

    结果是:
    enter image description here

相关问题