Excel XY 图表(散点图)数据标签无重叠

2024-02-04

So I've been working on this for the past week. Although it can't do miracles, I can say I've got a pretty good result: Before and After Before and After in a more serious chart
I just wanted to put this code out there for all the poor souls like me that are looking for some kind of vba macro that helps them avoid label overlaps in a scatter plot, because while doing my research on the subject, I wasn't able to find anything helpful.


Const PIXEL_TO_POINT_RATIO As Double = 0.72 '1 Pixel = 72/96*1 Point
Const tStep As Double = 0.1
Const rStep As Double = 0.1
Dim pCount As Integer

Sub ExampleMain()

        RearrangeScatterLabels Sheet5 

        RearrangeScatterLabels Sheet25

End Sub

Sub RearrangeScatterLabels(sht As Worksheet)
    Dim plot As Chart
    Dim sCollection As SeriesCollection
    Dim dLabels() As DataLabel
    Dim dPoints() As Point
    Dim xArr(), yArr(), stDevX, stDevY As Double
    Dim x0, x1, y0, y1 As Double
    Dim temp() As Double
    Dim theta As Double
    Dim r As Double
    Dim isOverlapped As Boolean
    Dim safetyNet, validEntry, currentPoint As Integer

    Set plot = sht.ChartObjects(1).Chart 'XY chart (scatter plot)
    Set sCollection = plot.SeriesCollection 'All points and labels
    safetyNet = 1
    pCount = (sCollection.Count - 1)

    ReDim dLabels(1 To 1)
    ReDim dPoints(1 To 1)
    ReDim xArr(1 To 1)
    ReDim yArr(1 To 1)

    For pt = 1 To sCollection(1).Points.Count
        For i = 1 To pCount
            If sCollection(i).Points.Count <> 0 Then
                'Dynamically expand the arrays
                validEntry = validEntry + 1
                If validEntry <> 1 Then
                    ReDim Preserve dLabels(1 To UBound(dLabels) + 1)
                    ReDim Preserve dPoints(1 To UBound(dPoints) + 1)
                    ReDim Preserve xArr(1 To UBound(xArr) + 1)
                    ReDim Preserve yArr(1 To UBound(yArr) + 1)
                End If

                Set dLabels(i) = sCollection(i).Points(pt).DataLabel 'Store all label objects
                Set dPoints(i) = sCollection(i).Points(pt)           'Store all point objects
                temp = getElementDimensions(, dPoints(i))
                xArr(i) = temp(0) 'Store all points x values
                yArr(i) = temp(2) 'Store all points y values
            End If
        Next
    Next

    If UBound(dLabels) < 2 Then Exit Sub

    pCount = UBound(dLabels)
    stDevX = Application.WorksheetFunction.StDev(xArr) 'Get standard deviation for x
    stDevY = Application.WorksheetFunction.StDev(yArr) 'Get standard deviation for y
    If stDevX = 0 Then stDevX = 1
    If stDevY = 0 Then stDevY = 1
    r = 0

    For currentPoint = 1 To pCount
        theta = Rnd * 2 * Application.WorksheetFunction.Pi()
        x0 = xArr(currentPoint)
        y0 = yArr(currentPoint)
        x1 = xArr(currentPoint)
        y1 = yArr(currentPoint)
        isOverlapped = True

        Do Until Not isOverlapped
            safetyNet = safetyNet + 1

            If safetyNet < 500 Then
                If Not checkForOverlap(dLabels(currentPoint), dLabels, dPoints, plot) Then
                    'No label is within bounds and not overlapping
                    isOverlapped = False
                    r = 0
                    theta = Rnd * 2 * Application.WorksheetFunction.Pi()
                    safetyNet = 1
                Else
                    'Move label so it does not overlap
                    theta = theta + tStep
                    r = r + rStep * tStep / (2 * Application.WorksheetFunction.Pi())
                    x1 = x0 + stDevX * r * Cos(theta)
                    y1 = y0 + stDevY * r * Sin(theta)
                    dLabels(currentPoint).Left = x1
                    dLabels(currentPoint).Top = y1
                End If
            Else
                safetyNet = 1
                Exit Do
            End If
        Loop
    Next
End Sub

Function checkForOverlap(ByRef dLabel As DataLabel, ByRef dLabels() As DataLabel, ByRef dPoints() As Point, ByRef dChart As Chart) As Boolean
    checkForOverlap = False 'Return false by default

    'Detect label going over chart area
    If detectOverlap(dLabel, , , dChart) Then
        checkForOverlap = True
        Exit Function
    End If

    'Detect labels overlap
    For i = 1 To pCount
        If Not dLabel.Left = dLabels(i).Left Then
            If detectOverlap(dLabel, dLabels(i)) Then
                checkForOverlap = True
                Exit Function
            End If
        End If
    Next

    'Detect label overlap with point
    For i = 1 To pCount
        If detectOverlap(dLabel, , dPoints(i)) Then
            checkForOverlap = True
            Exit Function
        End If
    Next
End Function

Function getElementDimensions(Optional dLabel As DataLabel, Optional dPoint As Point, Optional dChart As Chart) As Double()
    'Get element dimensions and compensate slack
    Dim eDimensions(3) As Double

    'Working in IV quadrant
    If dPoint Is Nothing And dChart Is Nothing Then
        'Get label dimensions and compensate padding
        eDimensions(0) = dLabel.Left + PIXEL_TO_POINT_RATIO * 3                'Left
        eDimensions(1) = dLabel.Left + dLabel.Width - PIXEL_TO_POINT_RATIO * 3 'Right
        eDimensions(2) = dLabel.Top + PIXEL_TO_POINT_RATIO * 6                 'Top
        eDimensions(3) = dLabel.Top + dLabel.Height - PIXEL_TO_POINT_RATIO * 3 'Bottom
    End If
    If dLabel Is Nothing And dChart Is Nothing Then
        'Get point dimensions
        eDimensions(0) = dPoint.Left - PIXEL_TO_POINT_RATIO * 5 'Left
        eDimensions(1) = dPoint.Left + PIXEL_TO_POINT_RATIO * 5 'Right
        eDimensions(2) = dPoint.Top - PIXEL_TO_POINT_RATIO * 5  'Top
        eDimensions(3) = dPoint.Top + PIXEL_TO_POINT_RATIO * 5  'Bottom
    End If
    If dPoint Is Nothing And dLabel Is Nothing Then
        'Get chart dimensions
        eDimensions(0) = dChart.PlotArea.Left + PIXEL_TO_POINT_RATIO * 22                         'Left
        eDimensions(1) = dChart.PlotArea.Left + dChart.PlotArea.Width - PIXEL_TO_POINT_RATIO * 22 'Right
        eDimensions(2) = dChart.PlotArea.Top - PIXEL_TO_POINT_RATIO * 4                           'Top
        eDimensions(3) = dChart.PlotArea.Top + dChart.PlotArea.Height - PIXEL_TO_POINT_RATIO * 4  'Bottom
    End If

    getElementDimensions = eDimensions 'Return dimensions array in Points
End Function

Function detectOverlap(ByVal dLabel1 As DataLabel, Optional ByVal dLabel2 As DataLabel, Optional ByVal dPoint As Point, Optional ByVal dChart As Chart) As Boolean
    'Left, Right, Top, Bottom
    Dim AxL, AxR, AyT, AyB As Double 'First label coordinates
    Dim BxL, BxR, ByT, ByB As Double 'Second label coordinates
    Dim eDimensions() As Double 'Element dimensions

    eDimensions = getElementDimensions(dLabel1)
    AxL = eDimensions(0)
    AxR = eDimensions(1)
    AyT = eDimensions(2)
    AyB = eDimensions(3)

    If dPoint Is Nothing And dChart Is Nothing Then
        'Compare with another label
        eDimensions = getElementDimensions(dLabel2)
    End If
    If dLabel2 Is Nothing And dChart Is Nothing Then
        'Compare with a point
        eDimensions = getElementDimensions(, dPoint)
    End If
    If dPoint Is Nothing And dLabel2 Is Nothing Then
        'Compare with chart area
        eDimensions = getElementDimensions(, , dChart)
    End If
    BxL = eDimensions(0)
    BxR = eDimensions(1)
    ByT = eDimensions(2)
    ByB = eDimensions(3)

    If dChart Is Nothing Then
        detectOverlap = (AxL <= BxR And AxR >= BxL And AyT <= ByB And AyB >= ByT) 'Reverse De Morgan's Law
    Else
        detectOverlap = Not (AxL >= BxL And AxR <= BxR And AyT >= ByT And AyB <= ByB) 'Is in chart bounds (working in IV quadrant)
    End If
End Function


我意识到代码有点粗糙并且没有优化,但我不能在这个项目上花费更多时间。我留下了很多注释来帮助阅读它,如果有人选择继续这个项目的话。

希望这可以帮助。
最美好的祝愿,幸灾乐祸。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Excel XY 图表(散点图)数据标签无重叠 的相关文章

  • Excel VBA:通过快捷键运行打开文档后宏挂起,但从 VB 编辑器运行完美

    我遇到了一个奇怪的问题 我决定分配一个键盘快捷键Ctrl Shift P我的 VBA 例程之一 该例程假设打开一个现有的 Excel 工作簿 复制一些信息并 SaveAs另一个名字 当我在 Visual Basic 编辑器中点击 播放 时
  • 防止 Excel 公式中的单元格数量增加

    我在 Excel 中有一个公式 需要根据该行中的数字除以一个常数对该列的几行运行 当我复制该公式并将其应用于范围中的每个单元格时 所有单元格编号都会随行增加 包括常量 所以 B1 127 C4 IF B4 lt gt B4 B1 如果我复制
  • Rails 4/5 发送动态 ActionMailer::Base.mail 电子邮件,附件标记为 Noname

    我看过类似的帖子 主要涉及通过创建视图和控制器来发送附件 例如 电子邮件中的 PDF 附件称为 Noname https stackoverflow com questions 12816042 pdf attachment in emai
  • 如何通过VBA刷新所有单元格

    有没有办法触发 从VBA Excel要求它重新评估所有Excel单元格 谢谢 The 计算 http msdn microsoft com en us library aa223802 28office 11 29 aspx方法可以重新计算
  • 如何在 C# 中将 excel ListObject 添加到给定工作表?

    我目前正在 C 中开发一个 Excel 插件 其中包含多种方法 表值函数 可供 Excel 用户和程序员 VBA 使用 如何编写一个方法 将新的 ListObject Excel 表 添加到给定的 Excel 工作表 并将给定的 DataT
  • 使用 SAS 导出到 Excel

    假设我有 2 个 SAS 数据集 test1 sas 和 Test2 sas 现在我想将这2个数据集导出到Excel中 其中Excel文件Sheet1中将有test1 sas数据 Sheet2中将有test2 sas数据 怎么做 从 开始这
  • 数据透视和运行时错误 1004:应用程序定义或对象定义的错误

    我对宏和 VBA 编码很陌生 我正在尝试创建一个非常简单的宏 它从包含 33 列的表中获取数据并将其转换为数据透视表 只有最后 3 列 31 32 33 包含数字 我需要将其显示在枢轴上 因为我想比较当前月份 上个月以及逐月的变动 到目前为
  • 在 C# 中更改 Excel 单元格格式

    如何使用 C 中的 Microsoft Excel 12 0 库更改 Excel 中单元格的格式 更具体地说 我想将给定单元格更改为文本格式 我读过了 net c 改变Excel单元格格式 https stackoverflow com q
  • 带有 For 循环的多维数组 VBA

    尝试检查第一列中的值 即多维数组中的列 如果它匹配 则对另一列中与该行匹配的值进行排序 我认为我做错了 但这是我第一次搞乱多维数组 我是否需要在每个 for 循环中使用 UBound 和 LBound 来告诉它要查看哪一列 除了当前问题的答
  • 通过vba在每个空间范围之间添加求和公式

    我试图进行自动化 但我被困在这里 我需要在空间范围之间动态添加总和公式 我完全迷失了使用 VBA 添加公式的能力 任何人都可以帮助我 先感谢您 我假设您想要的是 如果单元格中有空白 您希望将所有其他元素相加并将结果放置在该空白中 可能有很多
  • 在 Excel 2010 中添加基本功能区的 VBA 代码?

    我已经使用产品在 C addin express 中为 Excel 编写功能区 但我需要知道如何使用 vba 生成功能区 有人能为我提供一些代码来为此在工具栏中插入一个额外的功能区吗 我所说的功能区是指上面写着 公式 数据 评论 等的地方
  • 列表框错误“无法设置列表属性。属性值无效。”

    我有一个带有列表框 文本框 组合框和保存按钮的用户表单 下面是我的保存按钮代码 Private Sub cmdsave Click Dim x As Integer x Me ListBox1 ListCount If Me cmbtran
  • 使用新数据输入自动更新图表

    我的图表从 DataGridView 加载数据 如果将新值插入到 DataGridView 中 我希望自动使用新数据更新图表 我的图表必然是table1 and table2在我的 DataGridView 中 它从 DataTable 获
  • 如何让 selenium 等待页面在 Selenium - Excel VBA 包装器中完全加载?

    Selenium Excel VBA 的包装器使用什么代码或函数 以便程序将等待页面完全加载然后执行其他命令 最新版本在执行所需操作之前隐式等待目标元素存在 例如 driver FindElementById Click 默认情况下会在抛出
  • 将图表导出为图像 - 只需单击按钮

    我正在尝试创建一个按钮 将 图表 工作表中的图表导出为 jpeg 文件 这是我的代码 但它不断显示此错误 运行时错误 424 需要对象 具体来说 Set myChart Graphs ChartObjects 3 Name Chart4 这
  • Word VBA“项目不可见”

    有谁知道如何使模板在 Word 2007 中可见 我创建了一个模板 Experiments dotm 使用加载项添加它 但是当我尝试在其中创建模块时 收到错误消息 项目无法查看 关于 项目无法查看 问题的解释可以参见here http ms
  • VBA:访问 JSON

    我正在处理 VBA 投影 但不确定如何访问此 JSON 中的 id 应该将 players 设置为什么才能在循环中获取 id 我已经用更多代码更新了问题 JSON event games players id 182759 Code Pri
  • Python:使用 python 运行 Excel 宏

    我需要通过 python 运行 Excel 宏 但总是收到以下错误 result self oleobj InvokeTypes dispid LCID wFlags retType argTypes args pywintypes com
  • 在react-highcharts中动态更改系列数据,无需重新渲染图表

    I have created a line chart using react highcharts It has 3 series and different data for each of them And I have a rang
  • 在 OpenXML 中应用数字格式

    我正在尝试使用 OpenXML 从头开始 创建 Excel 电子表格 并且一切正常 将实际值转储到实际单元格中 但现在我正在尝试将数字格式应用于列 但遇到了问题 我有styles xml看起来像这样

随机推荐

  • WPF - 数据模板的参数?

    我有一个列表框 显示有关员工的数据 例如姓名 部门照片 徽章号码等 员工可能有不同的类型 例如经理 员工 志愿者 我有 3 个独立的数据模板 每种类型一个 所有这些模板显示的数据基本相同 但呈现方式不同 根据登录应用程序的用户 图片 徽章编
  • 如何从Scala的标准库继承Scaladoc?

    如果我理解正确的话 方法的 Scaladoc 应该自动继承它覆盖的父方法的 Scaladoc 这似乎适用于一组本地类 但在从 Scala 的标准库 可能还有任何外部依赖项 扩展时则不然 class LocalParent some docu
  • 搜索文本后去掉 Vim 的高亮显示

    在 VIM 中 使用 命令查找文本后 该文本保持突出显示状态 删除它的命令是什么 我根本不想删除突出显示功能 但一旦找到我需要的内容 我又不想拥有所有这些明亮的文本点 Thanks 输入 noh
  • SQL-根据列组合连续的日期行

    假设我有以下 SQL 结果 BegDate EndDate quanitty 1 1 2014 1 31 2014 1 2 1 2014 2 28 2014 1 3 1 2014 3 31 2014 2 4 1 2014 4 30 2014
  • AngularJS $resource GET 中的多个参数

    use strict angular module rmaServices ngResource factory rmaService resource function resource return resource RMAServer
  • 编译先前预处理的文件会更改输出

    我有一个源文件 我使用选项对其进行预处理 E and P 对于基于 vxWorks 的嵌入式平台使用 GCC 4 1 2 所有其他选项与我编译文件时相同 这些选项是 Wall march pentium nostdinc O0 fno bu
  • 在 matplotlib 中打开灯

    我有以下Python代码 import numpy as np from matplotlib import pyplot as plt plt rcParams figure figsize 12 7 n 100 m 100 X np a
  • 在 Xcode 中打开权利会阻止 Bare Bones 应用程序启动

    我在 Xcode 4 2 中创建了一个基本应用程序 非常简单的应用程序 我没有改变任何东西 按下运行 您将获得标准的基本应用程序窗口 如果我打开目标的权利并点击运行 我不会收到任何调试器错误 但窗口永远不会出现 我使用 Console ap
  • 当关联计数更改时强制更新 NSFetchedResultsController

    我有一个 NSFetchedResultsController 它在表视图中显示项目列表 包括关联实体的计数 当为此关联添加对象时 使用 addXXXObject 不会调用回调来通知我的控制器更新 如何接收对象被添加到父实体的 NSSet
  • Java Beans Binding 的状态如何?

    我发现一篇旧文章http www artima com lejava articles beans binding html http www artima com lejava articles beans binding html以及一
  • 针对单个客户端请求并行多个数据库查询

    为了完成用户的某些请求 在我的应用程序中 我从单个方法发出多个数据库查询 但它们当前正在按顺序执行 因此应用程序被阻止 直到它收到前一个查询的响应 数据 然后继续下一个查询 这不是我很喜欢的事情 我想发出并行查询 另外 在发出查询之后 我想
  • 使用 ffmpeg 在同一张图像上使用两次淡入/淡出

    我使用此命令在流开始 5 秒后淡入徽标 并在 25 秒后淡出 如下所示 ffmpeg re i test mp4 ignore loop 0 i logo gif filter complex 1 v fade in st 5 d 1 al
  • 在 QML 中截取特定项目的屏幕截图的方法是什么?

    我知道如何在 QML 中截取整个窗口的屏幕截图 https stackoverflow com questions 33165733 qquickwindowgrabwindow scene graph already in use lq
  • “onclick”不适用于具有 svg-image 的对象元素[重复]

    这个问题在这里已经有答案了 当我使用onclick的属性object html 文档中的元素 它不响应点击 在我的文档中 我有一个 svg 图像并将其存储在object element 因为图像中存在一些动画 仅使用img tag 在下面的
  • Silverlight:画布溢出

    我创建了一个 Canvas 并在其中放置了一个 StackPanel StackPanel 是水平的 它接受缩略图列表 画布有固定的大小 当我放置的缩略图数量超过 Canvas 宽度可以容纳的数量时 StackPanel 应该会从 Canv
  • 如何在运行时向角色添加动画控制器?

    我在 Assets Resources System PLController 中有一个 Animator 控制器 我必须在运行时使用脚本添加它 如何实现这一点 使用Unity 5 5 3 0f4 PLController 动画控制器 首先
  • CMake 中的 CMAKE_SOURCE_DIR 和 PROJECT_SOURCE_DIR 是否相同?

    这一页 https gitlab kitware com cmake community wikis doc cmake Useful Variables包含 CMake 已经为我们定义的变量的良好摘要 我觉得有些变量是相同的 举个例子CM
  • 即使任务启动后,AsyncResult(task_id)也会返回“PENDING”状态

    在项目中 我尝试轮询长时间运行的任务的task state并更新其运行状态 它在开发中有效 但当我将项目移动到生产服务器上时它不起作用 即使我可以看到任务在花上开始 我仍然收到 待处理 消息 但是 当任务完成时 当task state SU
  • 省略 Access 报告最后一页的页眉?

    如何删除 Access 报告最后一页上的标题 将组添加到报告中 根据表达式进行分组 True 这将创建一个包含报告中所有记录的组 为该组提供组标题 然后将列标题标签从页标题移动到组标题 在组标题的属性中 设置Repeat Section t
  • Excel XY 图表(散点图)数据标签无重叠

    So I ve been working on this for the past week Although it can t do miracles I can say I ve got a pretty good result I j