【问题标题】:Can Excel scatter chart background colours be customized based on data values?Excel散点图背景颜色可以根据数据值自定义吗?
【发布时间】:2022-04-09 09:46:14
【问题描述】:

我有一个 5row x 2col 的表。有 5 个数据点,每个数据点都有对应的 X 和 Y 值。 X,Y 值用于绘制散点图。

我想自定义散点图的背景作为数据点本身的函数,即彩色矩形的 X 和 Y 范围应该在我的控制。理想情况下,我希望数据中的 X 和 Y 值分别构成 X 和 Y “轴”,它们是不同颜色矩形的边界。

目前我在格式化图表区域时选择了“形状填充”->“图片”选项。图片目前是在 MS Powerpoint 中手动创建的,与图表区域的纵横比相同。

示例 VBA 代码。它从“Sheet1”的 A2:B6 范围内的 5x2 表中获取数据。

Sub scatter_plot_simple()
    Dim Chart1 As Chart
    Set Chart1 = Charts.Add
    With Chart1
        .ChartType = xlXYScatter
        .SeriesCollection.NewSeries
        .SeriesCollection(1).Name = "=""Values"""
        .SeriesCollection(1).XValues = "=Sheet1!$B$2:$B$6"
        .SeriesCollection(1).Values = "=Sheet1!C$2:$C$6"
    End With
End Sub

【问题讨论】:

  • 您是如何创建用作背景的图片的?这就是你需要自动化的东西。
  • 那么,您如何创建我们在您的问题中看到的图片?
  • 这里您询问的是两个相互排斥的替代方案。首先,散点图的背景是数据点本身的函数。其次,彩色矩形的 X 和 Y 范围应该在您的控制范围内。这两者如何同时进行。第一个可以根据您没有提到的某些标准自动完成,或者您已经在做第二个。此外,图表区域看起来绝对是白色的,绘图区域似乎有这些颜色。解释你是怎么做的,以便有人可以帮助你使用 vba
  • @JohnColeman 图片是在 MS Powerpoint 中手动创建的保存图像,与图表区域的纵横比相同。然后我在 Excel 图表中手动使用“形状填充”选项 ->“图片”子选项。
  • @FaneDuru 图片是在MS Powerpoint中手动创建的保存图像,与图表区域的纵横比相同。然后我在 Excel 图表中手动使用“形状填充”选项 ->“图片”子选项。

标签: excel vba plot


【解决方案1】:

请尝试下一段代码。它将创建矩形,为它们着色,分组,导出组图片并将其添加为绘图仪区域用户图片。没时间评论代码。如果不清楚,我会在几个小时内发表评论,当我在家时:

Sub scatter_plot_simple()
    Dim sC As Chart, sh As Worksheet, Chart1 As Chart, sGr As Shape, s As Shape, s1 As Shape, s2 As Shape
    Dim pltH As Double, pltW As Double, pltAH As Double, pltAW As Double, i As Long, j As Long, k As Long
    Dim maxX As Long, maxY As Long, majUnitY As Long, topS As Double, leftS As Double
    
    majUnitY = 20 'major unity for X axes
    'delete the previous chart (used for testing)
    For Each sC In Charts
        Application.DisplayAlerts = False
            If sC.Name = "MyChart" Then sC.Delete: Exit For
        Application.DisplayAlerts = True
    Next
    Set sh = Sheets("Sheet1")
    Set Chart1 = Charts.Add
    With Chart1
        .Name = "MyChart"
        .ChartType = xlXYScatter
        .SeriesCollection.NewSeries
        .SeriesCollection(1).Name = "=""Values"""
        .SeriesCollection(1).XValues = "=" & sh.Name & "!B2:B6"
        .SeriesCollection(1).Values = "=" & sh.Name & "!C2:C6"
        .Axes(xlCategory).MajorUnit = majUnitY
        maxX = .Axes(xlCategory).MaximumScale             'maximum scale of X axes
        pltAH = .PlotArea.height: pltAW = .PlotArea.width 'plot area height
        maxY = .Axes(xlValue).MaximumScale                'maximum scale of X axes
        'extract dimensions of the future rectangles to be created:
        pltH = .PlotArea.height / maxY: pltW = .PlotArea.width / (maxX / majUnitY)
    End With
    'create the rectangle equal to chart Plot area:
    Set s = sh.Shapes.AddShape(msoShapeRectangle, 0, 0, pltAW, pltAH)
    s.Fill.ForeColor.RGB = RGB(255, 255, 255) 'white color
    topS = 0: leftS = 0
    Dim maxGreen As Long  ' variable to be used to change the rectangle colors
    maxGreen = 2
    'create the necessary colored rectangles to reflect the maximum X and maximum Y
    For j = 1 To maxX / majUnitY
        For i = 1 To 6
            Set s1 = sh.Shapes.AddShape(msoShapeRectangle, leftS, topS, pltW, pltH)
            With s1
                .Select
                'color rectangles according to their position:
                .Fill.ForeColor.RGB = IIf(6 - i >= maxGreen, IIf(j = 1, RGB(201, 163, 102), RGB(138, 197, 139)), IIf(j = 1, RGB(231, 157, 126), RGB(145, 208, 215)))
                .line.Weight = 2
                .line.ForeColor.RGB = RGB(255, 255, 255)
            End With
            If i = 1 And j = 1 Then  'group the big rectangle (plot area dimensions) with the first rectangle
                Set sGr = sh.Shapes.Range(Array(s.Name, s1.Name)).Group
            Else
                'group the previous group with the created rectangle
                Set sGr = sh.Shapes.Range(Array(sGr.Name, s1.Name)).Group
            End If
            topS = topS + pltH  'increment Top position for the future rectangle
        Next i
        'adding the rectangles slices over the existing rectangles in second column:
        If j = 2 Then
            topS = 0
            For k = 1 To 6
                Set s2 = sh.Shapes.AddShape(msoShapeRectangle, leftS + 2, topS + 2, pltW / 3, pltH - 4)
                With s2
                    .Select
                    If 6 - k >= maxGreen Then
                        .Fill.ForeColor.RGB = RGB(201, 163, 102)
                        .line.ForeColor.RGB = RGB(201, 163, 102)
                    Else
                        .Fill.ForeColor.RGB = RGB(231, 157, 126)
                        .line.ForeColor.RGB = RGB(231, 157, 126)
                    End If
                End With
                Set sGr = sh.Shapes.Range(Array(sGr.Name, s2.Name)).Group
                topS = topS + pltH
            Next k
            
        End If
        leftS = leftS + pltW: topS = 0 'increment the left possition and reset the Top poz to zero
    Next j
    'Part of exporting the created group as picture:
    Dim pictPath As String
    pictPath = ThisWorkbook.path & "\chartPict.jpg" 'the path where to be saved
    ExportShPict sGr, sh, pictPath                          'export function
    Chart1.PlotArea.Format.Fill.UserPicture pictPath   'place the exported picture to the chart plot area
    sGr.Delete                                                   'delete the helper group
    Chart1.Activate                                            'activate the chart sheet
    MsgBox "Ready..."
End Sub

Private Sub ExportShPict(s As Shape, sh As Worksheet, pictPath As String)
   Dim ch As ChartObject
   'create a new chart using the shape (group) dimensions
   Set ch = sh.ChartObjects.Add(left:=1, top:=1, width:=100, height:=100)
   ch.width = s.width: ch.height = s.height
   'copy the group picture on the newly created chart
   s.CopyPicture: ch.Activate: ActiveChart.Paste
   'export the chart which practically means only the picture
   ch.Chart.Export FileName:=pictPath, FilterName:="JPG"
   ch.Delete 'delete the helper chart
End Sub

我推断出更改垂直轴颜色的逻辑,但您没有说明 X 轴上要更改向下颜色的位置。如果这方面清楚,可以在第二个矩形列上放置一些较小的矩形。

【讨论】:

  • 感谢您在忙碌的情况下快速回复@FaneDuru! X 和 Y 方向颜色变化的位置分别位于 X 和 Y 数据的中值。不知何故,我无法使用您的代码获得预期的数字。不幸的是,我不知道如何在此处附上我的图(带有您的代码)以供您参考。
【解决方案2】:

试试这个。

“这只是基本的数学”,所以代码没有注释... ;-)

编辑:将图表移动到工作表中,形状仅绘制在(透明)图表后面。关闭工作表上的网格线,否则它们会显示...

Sub scatter_plot_simple()
    Const CHT_NAME As String = "QUADRANTS"
    Dim cht As Chart, rngX As Range, rngY As Range, wsData As Worksheet, co
    Dim medX, medY, wsChart As Worksheet
    
    Set wsChart = Worksheets("Chart")
    Set wsData = Worksheets("Data")
    Set rngX = wsData.Range("B2:B400")
    Set rngY = wsData.Range("C2:C400")
    
    DeleteAllShapes wsChart
    
    'hosting the chart on a worksheet...
    Set co = wsChart.Shapes.AddChart2(240, xlXYScatter)
    co.Name = CHT_NAME
    co.Fill.Visible = msoFalse 'no background
    co.Top = 10
    co.Left = 10
    co.Width = 400
    co.Height = 400
    
    Set cht = co.Chart
    ClearSeries cht    'make sure no "auto-plotted" series
    With cht
        .ChartType = xlXYScatter
        .SeriesCollection.NewSeries
        .SeriesCollection(1).Name = "Data"
        .SeriesCollection(1).XValues = rngX
        .SeriesCollection(1).Values = rngY
        .PlotArea.Format.Fill.Visible = msoFalse 'no background
    End With
    
    medX = Application.Median(rngX)
    medY = Application.Median(rngY)
    
    AddQuadrants cht, medX, medY
    
End Sub

Sub AddQuadrants(cht As Chart, medX, medY)
 
    Dim minX, maxX, minY, maxY, xAxis As Axis, yAxis As Axis
    Dim xSpan, ySpan, shp1, Q1 As Shape, Q2 As Shape, Q3 As Shape, Q4 As Shape
    Dim Q1W, Q1H, ws As Worksheet, co As Object, posTop As Long, posleft As Long
    
    Set co = cht.Parent 'chartobject (a container for the chart when hosted on a worksheet)
    Set ws = co.Parent  'the hosting worksheet
    
    Set xAxis = cht.Axes(xlCategory)
    Set yAxis = cht.Axes(xlValue)
    
    minX = xAxis.MinimumScale
    maxX = xAxis.MaximumScale
    xSpan = maxX - minX
    
    minY = yAxis.MinimumScale
    maxY = yAxis.MaximumScale
    ySpan = maxY - minY
    
    Q1W = ((medX - minX) / xSpan) * xAxis.Width
    Q1H = ((maxY - medY) / ySpan) * yAxis.Height
    
    posTop = 4 + co.Top + yAxis.Top     'fudging this a bit...
    posleft = 4 + co.Left + xAxis.Left  'fudging this a bit...
    
    Set Q1 = Quadrant(ws, posleft, posTop, Q1W, Q1H, vbYellow)
    Set Q2 = Quadrant(ws, posleft + Q1W, posTop, xAxis.Width - Q1W, Q1H, vbRed)
    Set Q3 = Quadrant(ws, posleft, posTop + Q1H, Q1W, yAxis.Height - Q1H, vbBlue)
    Set Q4 = Quadrant(ws, posleft + Q1W, posTop + Q1H, _
                      xAxis.Width - Q1W, yAxis.Height - Q1H, vbGreen)
    
End Sub

Function Quadrant(ws As Worksheet, l, t, w, h, clr As Long) As Shape
    Dim rv As Shape
    Set rv = ws.Shapes.AddShape(msoShapeRectangle, l, t, w, h)
    rv.Fill.ForeColor.RGB = clr
    rv.Fill.Transparency = 0.9
    rv.Fill.Solid
    rv.Line.Visible = False
    rv.ZOrder msoSendToBack
    Set Quadrant = rv
End Function

Sub ClearSeries(cht As Chart)
    Do While cht.SeriesCollection.Count > 0
        cht.SeriesCollection(1).Delete
    Loop
End Sub

Sub DeleteAllShapes(ws As Worksheet)
    Do While ws.Shapes.Count > 0
       ws.Shapes(1).Delete
    Loop
End Sub

或者没有 VBA:https://peltiertech.com/excel-chart-with-colored-quadrant-background/

【讨论】:

  • 我很惊讶@Tim Williams 这么快就回复了这么有用的代码。这是我在 StackOverFlow 中的第一个问题,我不得不承认,我只是被这种以这种方式帮助随机陌生人的善良(和熟练)的人的回答所淹没。非常感谢!
  • 顺便问一下,您对如何获取绘制的 XY 散点图后面的形状有任何想法吗?如果能够将鼠标悬停在任何数据点上以查看所有值,那就太好了。我确实添加了数据标签,所以看起来不错,但如果我能看到全彩色的数据点和标签(并且不会在彩色矩形后面褪色)会更好。
  • 如果您想要图表后面的形状,那么您需要在添加图表之前将它们添加到工作表(如果使用嵌入式图表)或空图表工作表中。然后将图表填充设置为“无”,以便可以在图表后面看到形状。如果我可以修改我的代码来做到这一点,我可能会稍后看看......
猜你喜欢
  • 2015-07-17
  • 2011-12-27
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
  • 2020-02-11
  • 1970-01-01
  • 2016-04-03
相关资源
最近更新 更多