VBA:使用默认颜色提取图表中线条的 RGB 值

Posted

技术标签:

【中文标题】VBA:使用默认颜色提取图表中线条的 RGB 值【英文标题】:VBA: Extracting the RGB value of lines in a chart with default colors 【发布时间】:2014-11-07 15:14:40 【问题描述】:

问题

我想知道如何读取图表中自动分配颜色的当前 RGB 值,即使这需要将颜色冻结为其当前值(而不是在更改主题时更新它们,重新排序系列,等等)

用例

我的实际用例是我想让数据标签与折线图中线条/标记的颜色相匹配。如果我通过方案或显式 RGB 值明确设置系列的颜色,这很容易,例如

' assuming ColorFormat.Type = msoColorTypeRGB
s.DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB= _
s.Format.Line.ForeColor.RGB

但是,在自动分配系列颜色时执行此操作会产生白色标签。更具体地说,以下两个等式都成立

s.Format.Line.ForeColor.Type = msoColorTypeRGB 
s.Format.Line.ForeColor.RGB = RGB(255,255,255)  ' White

然而,这条线当然不是白色的,而是主题自动分配的颜色。这表明颜色是自动分配的

s.Border.ColorIndex = xlColorIndexAutomatic

我认为颜色没有与相关系列一起存储是有道理的。即使将索引存储到配色方案中通常也不起作用,因为如果添加了另一个数据系列或有人重新排序数据,Excel 需要更改颜色。不过,如果有某种方法可以自动识别当前的 RGB 值,我会很高兴的。

一个丑陋的解决方法

对于包含 6 个或更少条目的图表,一个简单的解决方法是利用主题颜色按顺序分配的事实,因此我可以这样做(例如)

chrt.SeriesCollection(1).DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.ObjectThemeColor _
= msoThemeColorAccent1

据推测,这可以扩展为在主题耗尽后用于区分条目的 TintAndShade,但这是一个丑陋的 hack。

研究

有人问了基本相同的问题(如何提取主题颜色)here,但从未得到回答。有几个来源建议将已知主题颜色转换为 RGB 值的方法(例如 here 和 here),但这只是引出了问题;我不知道颜色先验,除了“这条线当前是什么颜色”。

【问题讨论】:

这是一个很好的第一个问题。我似乎记得 line 图表特别难以像这样使用,在 PPT 中的图表上使用主题颜色(和一些非主题颜色)时遇到了一些类似的问题。我看看有没有什么功能可以帮到你…… 尝试调试,即使我 assign srs.Format.Line.ForeColor.ObjectThemeColor = msoThemeColorAccent2 然后尝试查询 ?srs.Format.Line.ForeColor.ObjectThemeColor 给我 0(应该是 6)。无论使用什么颜色,我都会得到零。 看看这里的答案能不能帮到你:***.com/questions/21142732/… @DavidZemens 感谢您的建议(以及友好的反馈!)。实际上,我在问题的最后链接到了那个答案;问题是我不知道要尝试提取哪种主题颜色(或其变体)——没有利用我的知识,即它在 6 种调色板颜色之间循环,亮度变化,我宁愿避免这种情况。 对。就好像他们故意让 ThemeColors 难以使用。我看到一个有趣的观察结果,我将其添加为“答案”,因为它太大而无法放入 cmets。 【参考方案1】:

所以这很有趣。我使用所有默认值创建折线图,然后运行此过程:

Sub getLineCOlors()
Dim cht As Chart
Dim srs As Series
Dim colors As String
Dim pt As Point

Set cht = ActiveSheet.ChartObjects(1).Chart

For Each srs In cht.SeriesCollection
    With srs.Format.Line
    colors = colors & vbCrLf & srs.Name & " : " & _
            .ForeColor.RGB
    End With

Next

Debug.Print "Line Colors", colors

End Sub

随即显示立即窗口:

Line Colors   
Series1 : 16777215
Series2 : 16777215
Series3 : 16777215

但显然情况并非如此。很明显,它们都是不同的颜色。如果不是.RGB,而是.ObjectThemeColor,那么我得到所有0,通过观察图表,这同样明显是错误的!

Line Colors   
Series1 : 0
Series2 : 0
Series3 : 0

这里是有趣的地方:

如果在创建图表后我更改系列颜色(或者甚至通过分配相同的 ThemeColors 使它们保持不变),则该函数显示有效的 RGB:

Line Colors   
Series1 : 5066944
Series2 : 12419407
Series3 : 5880731

就好像 Excel(和 PowerPoint/等)完全无法识别折线图上的自动分配颜色。一旦你指定了颜色,它就可以读取颜色。

注意:折线图很挑剔,因为您没有.Fill,而是.Format.Line.ForeColor(和.BackColor)和IIRC 还有一些其他怪癖,就像你可以选择一个单独的 point 并改变它的填充颜色,然后这会影响前面线段的视觉外观等......

这仅限于折线图吗?也许。我过去的经验说“可能”,虽然我不能说这是一个错误,但它确实似乎是一个错误。

如果我在柱形图上运行类似的程序——再次仅使用自动分配的默认颜色,

Sub getCOlumnColors()

Dim cht As Chart
Dim srs As Series
Dim colors As String
Dim pt As Point

Set cht = ActiveSheet.ChartObjects(2).Chart

For Each srs In cht.SeriesCollection

    With srs.Format.Fill
    colors = colors & vbCrLf & srs.Name & " : " & _
            .ForeColor.RGB
    End With

Next

Debug.Print "Column Colors", colors

End Sub

然后我得到似乎是有效的 RGB 值:

Column Colors 
Series1 : 12419407
Series2 : 5066944
Series3 : 5880731

但是:它仍然无法识别有效的ObjectThemeColor。如果我更改.RGB,则输出:

Column Colors 
Series1 : 0
Series2 : 0
Series3 : 0

因此,根据这些观察结果,肯定无法访问 自动分配颜色格式的 ObjectThemeColor 和/或 .RGB 属性。

正如 Tim Williams 所证实的,这是一个早在 2005 年就存在的错误,至少与 RGB 相关,并且可能该错误通过 ObjectThemeColor 等延续到 Excel 2007+ 中......不太可能很快就会得到解决,所以我们需要一个黑客解决方案:)

更新的解决方案

结合以上两种方法!将每个系列从 line 转换为 xlColumnClustered,然后从 .Fill 查询 color 属性,然后将系列图表类型更改回其原始状态。这可能比尝试利用顺序索引更可靠(如果用户重新排序了系列,则根本不可靠,例如,“Series1”位于索引 3 等)

Sub getLineColors()
Dim cht As Chart
Dim chtType As Long
Dim srs As Series
Dim colors As String

Set cht = ActiveSheet.ChartObjects(1).Chart

For Each srs In cht.SeriesCollection
    chtType = srs.ChartType
    'Temporarily turn this in to a column chart:
    srs.ChartType = 51
    colors = colors & vbCrLf & srs.Name & " : " & _
            srs.Format.Fill.ForeColor.RGB
    'reset the chart type to its original state:
    srs.ChartType = chtType
Next

Debug.Print "Line Colors", colors

End Sub

【讨论】:

近十年前:类似问题 - office-archive.com/33-excel/57ab74e17cab9710.htm 谢谢蒂姆。如果 Peltier 和 Walkenbach 这么说,那么这绝对是一个错误。很难相信它会持续十年或更长时间! 这是一个绝妙的解决方案。当我实现这个时,图表类型变为模板,右侧的第二个垂直轴仍然存在。这可以通过在最后将图表类型(对于整个图表)更改回 Line 来解决。 很好的答案!我必须修改它以查看条形图中的每个点,因为条形是按值进行颜色编码的。不幸的是,它们设置了主题,我无法找出颜色来制作匹配的图例。现在我已经有了它们,我将使用本练习中的 RGB 值来设置所有内容。【参考方案2】:

半天后,我设法解决了这个问题:

       Sub ......()

       Dim k as Integer
       Dim colorOfLine as Long

       ...............
       .................

       'Loop through each series
       For k = 1 To ActiveChart.SeriesCollection.Count

            With ActiveChart.FullSeriesCollection(k)

                .HasDataLabels = True

                'Put a fill on datalabels
                .DataLabels.Format.Fill.Solid

                'Get color of line of series
                colorOfLine = .Format.Line.ForeColor.RGB

                'Assign same color on Fill of datalabels of series
               .DataLabels.Format.Fill.ForeColor.RGB = colorOfLine

               'white fonts in datalabels
               .DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)

            End With

        Next k
        ..........
        End Sub

【讨论】:

【参考方案3】:

这是我最后使用的代码。

Sub ShowSeries()
Dim mySrs As Series
Dim myPts As Points
Dim chtType As Long
Dim colors As String

With ActiveSheet
    For Each mySrs In ActiveChart.SeriesCollection
        'Add label
        Set myPts = mySrs.Points
        myPts(myPts.Count).ApplyDataLabels ShowSeriesName:=True, ShowValue:=False

        'Color text label same as line color

        'if line has default color
        If mySrs.Border.ColorIndex = -4105 Then
            chtType = mySrs.ChartType
            'Temporarily turn this in to a column chart:
            mySrs.ChartType = 51
            mySrs.DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = _
                mySrs.Format.Fill.ForeColor.RGB
            'reset the chart type to its original state:
            mySrs.ChartType = chtType

        'if line has a color manually changed by user
        Else
            mySrs.DataLabels.Font.ColorIndex = mySrs.Border.ColorIndex
        End If
    Next
End With

结束子

【讨论】:

以上是关于VBA:使用默认颜色提取图表中线条的 RGB 值的主要内容,如果未能解决你的问题,请参考以下文章

vba如何对选取区域设置边框线颜色,边框包括外部边框和内部的。

Matplotlib中的颜色、线条、标记样式汇总

使用开放CV和python提取或获取图像中几个点的平均RGB颜色

Matplotlib简单的不同颜色线图[重复]

AmChart:为图表设置 lineColor 失败

如何根据列值更改线条的颜色