首页 文章

检测Excel图表中比Excel窗口更宽的第一个和最后一个可见点

提问于
浏览
2

我有一个包含烛台图表的Excel工作表 - 但是出于这个问题的目的,它可能是常规的2D线图,或任何具有水平轴的图表 .

图表的数据源不是数学函数;相反,它是表示价格的任意数据,从另一个工作表的列读取 .

我的图表比工作表窗口宽许多倍 - 而不是Excel窗口本身 . 我只需使用工作表的常规水平滚动条水平浏览图表,滚动工作表,包括其中的图表 .

我将按钮放在同一个工作表中,通过VBA代码手动调整图表的垂直刻度(Y轴),因为当水平滚动时,变为可见的新图表值可能需要显示不同的最小和最大Y轴值以最佳方式 .

我想用自动缩放替换手动缩放:在每次滚动之后,我需要知道最左边的可见图表点和最右边 - 这是第一个和最后一个可见点 . 从那里我将计算出最佳的Y尺度并将其设置到图表中 .

所以我正在尝试编写VBA代码来检测第一个和最后一个可见点 . Chart 对象没有找到这样做的方法 . 这是我的问题 .

Chart.AutoScaling 属性无效,因为它会影响整个图表,而我的目标是设置一个垂直比例,该比例仅适用于图表的当前可见部分 . 所以我需要找到图表的第一个和最后一个可见点 .

此图表的用户可能具有与Excel 2007一样旧的Excel版本,因此适用于旧版本最佳版本的解决方案,但是需要较新Excel版本的解决方案也会很棒 .

3 回答

  • 1

    我很少发布另一个答案,所以这需要一些思考 .

    考虑一个动态图表,它只显示数据的选定部分,而不是显示所有数据的静态图表 . 考虑到不是构建一个跨越多个屏幕宽度的图表,而是可以使用一个完全适合屏幕的图表,但用户可以确定他们想要在该图表中看到什么 .

    然后给用户一些控制单元,在那里他们可以输入图表数据的起点,另一个控件可以确定他们想要在图表中看到多少蜡烛/条/点 .

    利用用户提供的信息,您可以应用已 Build 的动态图表技术,例如图表范围的命名公式 . 然后在顶部洒一点VBA以确定所选图表范围的最小值和最大值 .

    如果您想查看该技术的示例,请告诉我,我将添加一个链接 . 与在窗口的左侧和右侧消失的图表滚动相比,这真的不是那么难以做到并且用户体验要好得多 .

    Edit :我创建了一个示例文件,您可以使用此Dropbox link下载

    您需要为此文件启用宏 .

    顶部的图表显示了所有数据 .

    第26行中的图表使用动态范围 . 用户可以操作F17和F18来选择起点和要绘制的行数 . 然后,行26中的图表使用Excel默认值来使用一些填充来适应值轴,就像Excel那样 .

    第42行中的图表(喜欢该编号)会覆盖Exel默认值,并分别使用F23和F24中的值作为最小值和最大值 . 这是通过工作表更改事件宏完成的,该宏在工作表中的任何单元格更改时运行 .

    有很多方法可以微调和改进这种方法,例如,只有当F23或F24中的图表参数发生变化时才会触发宏,但这不是重点 .

    关键是您可以使用动态范围名称在图表中显示您选择的数据 . 没有任何代码,但让Excel决定Y轴min和max应该是什么 . 就像D26中的图表一样 .

    如果想要更多地控制Y轴的最小值和最大值,请使用D42中的代码版本和图表 .

    很高兴接受提问 .

  • 2

    我在VBA中不够精通为此提供确切的代码,但从概念上讲,如果你水平滚动页面,应该有一种方法来确定可见窗口中左上角单元格的地址,例如 ActiveWindow.VisibleRange.Cells(1,1) 和沿着相同的逻辑线,如果您知道列宽和缩放系数,则可以确定可见窗口的最后一个单元格 .

    然后你可以连接这些可见单元格及其各自的地址与图表数据源中的相关范围 . 例如,如果可见范围是A到M列,那么图表中的数据范围必须是第1行到第55行,如果可见范围是M到Z列,那么图表中的数据范围必须是第55到100行 . 您可能需要为该关系制定转换公式 .

    然后,您可以获取将在图表中绘制的源数据中的相关值,并处理值轴的最小值和最大值 .

  • 1

    这是一个根据可见x值缩放轴的功能 .

    我试图评论它,但逻辑如下:

    • 使用 .VisibleRange 属性获取可见范围

    • 获取可见范围和绘图区域的左右点

    • 计算最左侧和最右侧的可见x值,然后找到每个值最接近的实际数据点 . 这避免了必须假设等距x数据

    • 获取数据中这些极值的索引,以便获得相应的y值 .

    • 将轴缩放为y值

    Note: 这当前依赖于 ActiveChart 对象,使用具有给定名称的已定义图表对象会更加健壮 . 这取决于您的具体用法 .

    码:

    Sub scaley()
        ' Get visible range
        Dim visrange As Range
        Set visrange = ActiveWindow.VisibleRange
        ' Get left and right in points
        Dim L As Double, R As Double
        L = visrange.Left
        R = visrange.Cells(visrange.Cells.Count).Offset(0, 1).Left
        ' Get left and right of chart, relies on chart being active
        ' could easily replace with calling your chart by name
        Dim chtL As Double, chtR As Double
        Dim cht As Chart
        Set cht = ActiveChart
        chtL = cht.Parent.Left + cht.PlotArea.Left
        chtR = chtL + cht.PlotArea.Width
        ' Get visible region by percentage
        Dim pL As Double, pR As Double
        pL = WorksheetFunction.Max((L - chtL) / (chtR - chtL), 0)
        pR = WorksheetFunction.Min((R - chtL) / (chtR - chtL), 1)
        ' Get x axis values, and the visible x axis range
        Dim xval() As Variant
        xval = cht.SeriesCollection(1).XValues
        Dim xmin As Double, xmax As Double, xrange As Double
        xmin = WorksheetFunction.Min(xval)
        xrange = WorksheetFunction.Max(xval) - xmin
        xmax = xmin + pR * xrange
        xmin = xmin + pL * xrange
        ' Get actual corresponding x values
        Dim imin As Long, imax As Long
        For imin = LBound(xval) To UBound(xval)
            If xval(imin) >= xmin Then Exit For
        Next imin
        For imax = UBound(xval) To LBound(xval) Step -1
            If xval(imax) <= xmax Then Exit For
        Next imax
        ' Get y values in the visible range
        Dim allyval() As Variant, yval() As Variant
        allyval = cht.SeriesCollection(1).Values
        ReDim yval(0 To imax - imin)
        Dim i As Long
        For i = imin To imax
            yval(i - imin) = allyval(i)
        Next i
        ' scale axes, including buffer so max/min values dont sit right on edge
        Dim buffer As Double
        buffer = 0.1
        cht.Axes(xlValue).MaximumScale = WorksheetFunction.Max(yval) + buffer
        cht.Axes(xlValue).MinimumScale = WorksheetFunction.Min(yval) - buffer
    End Sub
    

    以下是一些示例输出 . 我使用 arbitrary data x = -10, -9, ..., 10y = 100, 81, 64, 49, ..., 81, 100 (这是 x^2 )来创建散点图,然后在不同的窗口位置运行子 .

    图表大小不会改变,我只需更改窗口大小/滚动,确保选中图表(参见上面的“注释”)并运行子图:

    zoom 1

    zoom 2


    如果您确实需要在滚动事件上触发此子,那么您可能需要查看此处:cpearson - DetectScroll . 这不是一件简单的事情!一个更简单的选择是在顶部(或类似的东西)有一个非常宽的按钮,可以调用上面的 scaley sub .

相关问题