要根据“检查数据”标签的W列中的值为系列中的所有标记着色(“检查数据”标签的O和P列中的XY值)
beforeunload
答案 0 :(得分:0)
您的代码实际上只有一个问题。用于获取土地使用数据的Offset
减1。使用
Set cl = valRange(p).Offset(0, 8)
它应该可以工作。
由于我自己编写了代码以进行检查,因此这是我的版本(略有不同)。请注意以下几点:
Split
函数获得Range
字符串以获取x值范围。对我来说,拆分Formula
字符串比解析它几次要容易得多。String
声明$
和使用Long
声明#
并不是完全不推荐使用,但是最近很少使用。LCase
对土地使用字符串进行了规范化以来,每个Case
语句都应该全部小写。Offset(0, 9)
,因为我正在使用x值范围。您使用了y值范围。这是我的版本(略有不同):
Sub ColorScatterPoints2()
Dim thisWS As Worksheet
Dim thisChart As Chart
Dim thisSeries As Series
Set thisWS = ActiveSheet
Set thisChart = thisWS.ChartObjects("EastingNorthingGraph").Chart
Set thisSeries = thisChart.SeriesCollection("Survey Point")
'--- establish a Range for the "x" values of the series
' and use it to create a Range for the Land Use data
Dim landUseArea As Range
Dim xValues As Range
Dim tokens() As String
tokens = Split(thisSeries.Formula, ",")
Set xValues = Range(tokens(1))
Set landUseArea = xValues.Offset(0, 9)
Dim i As Long
Dim thisPoint As Point
Dim myColor As Long
For i = 1 To thisSeries.Points.Count
Select Case LCase(landUseArea.Cells(i, 1))
Case "crop"
myColor = RGB(255, 0, 0)
Case "gravel"
myColor = RGB(255, 192, 0)
Case "native grass"
myColor = RGB(0, 255, 0)
End Select
Set thisPoint = thisSeries.Points(i)
With thisPoint.Format.Fill
.Visible = msoTrue
.ForeColor.RGB = myColor
End With
Next i
End Sub
答案 1 :(得分:0)
在您对我之前的回答的评论中提供了新信息后,应该更改您的方法,因为您的数据集非常大。 VBA方法的限制因素是与图表中每个数据点进行交互所花费的时间。您可以将数据范围移动到基于内存的数组中或禁用屏幕更新,但是使用该大小的数据集,您仍在修改Point
中的每个单独的Series
。非常耗时。
提出的这种不同方法将您的数据集分为两列,并根据土地利用数据创建三个“虚拟”数据集。然后,我们将三个单独的数据系列添加到图表中,每个系列可以分别设置颜色,大小,样式等样式。
逻辑从为数据创建三个不同的范围开始:
Dim landUseWS As Worksheet
Set landUseWS = ThisWorkbook.Sheets("Sheet2")
Dim lastRow As Long
Dim xValues As Range
Dim yValues As Range
Dim useValues As Range
With landUseWS
lastRow = .Cells(.Rows.Count, "N").End(xlUp).Row
Set xValues = .Range("N1").Resize(lastRow, 1)
Set yValues = .Range("O1").Resize(lastRow, 1)
Set useValues = .Range("W1").Resize(lastRow, 1)
End With
接下来,我创建了一个Sub
以将我连接到土地使用图本身。由于我反复测试代码,因此将此逻辑移到一个单独的子目录中将使我有机会适当地设置图表。
Private Function GetLandUseChart(ByRef ws As Worksheet) As Chart
Dim theChart As Chart
On Error Resume Next
Set theChart = ws.ChartObjects("EastingNorthingGraph").Chart
If theChart Is Nothing Then
'--- can't find it, so create it
Dim newObject As ChartObject
Set newObject = ws.ChartObjects.Add(Top:=10, Left:=325, _
Width:=600, Height:=300)
newObject.Name = "EastingNorthingGraph"
Set theChart = newObject.Chart
With theChart
.ChartType = xlXYScatter
.Location Where:=xlLocationAsObject, Name:=ws.Name
End With
End If
'--- delete any existing series so we have an empty chart to work with
Do Until theChart.SeriesCollection.Count = 0
theChart.SeriesCollection(1).Delete
Loop
Set GetLandUseChart = theChart
End Function
下一步是根据现有数据创建虚拟系列(Range
)。您的数据基本上是三列:X,Y和LandUse。我们要创建一个范围,将X和Y值与每种匹配的土地利用类型配对。范围中的单元格可能不是连续的,因此我们使用Union
函数来创建范围对象,该对象会将许多不同的单元格“分组”到一个范围内。我也将其分为自己的功能。
Private Function CreateLandUseSeries(ByVal useType As String, _
ByRef xValues As Range, _
ByRef yValues As Range, _
ByRef useValues As Range) As Range
Dim xData As Variant
Dim yData As Variant
Dim useData As Variant
xData = xValues.Value
yData = yValues.Value
useData = useValues.Value
Dim useRange As Range
Dim i As Long
For i = LBound(useData) To UBound(useData)
If useData(i, 1) = useType Then
If useRange Is Nothing Then
Set useRange = Union(xValues(i, 1), yValues(i, 1))
Else
Set useRange = Union(useRange, xValues(i, 1), yValues(i, 1))
End If
End If
Next i
Set CreateLandUseSeries = useRange
End Function
因此,您可以按照自己的主要逻辑进行操作:
Dim cropSeries As Range
Dim gravelSeries As Range
Dim nativeGrassSeries As Range
Set cropSeries = CreateLandUseSeries("Crop", xValues, yValues, useValues)
Set gravelSeries = CreateLandUseSeries("Gravel", xValues, yValues, useValues)
Set nativeGrassSeries = CreateLandUseSeries("Native Grass", xValues, yValues, useValues)
最后,将这些系列中的每一个都添加到图表中也很简单,也可以使用它自己的Sub
。
Private Sub AddSeries(ByVal newName As String, _
ByRef newSeries As Range, _
ByRef theChart As Chart, _
ByVal theMarker As XlMarkerStyle)
Dim theSeries As Series
With theChart
Set theSeries = .SeriesCollection.newSeries
With theSeries
.Name = newName
.xValues = newSeries.Resize(, 1)
.Values = newSeries.Offset(, 1).Resize(, 1)
'--- add some parameters to customize the marker style
' color, size, etc
.MarkerStyle = theMarker
End With
End With
End Sub
注意如何添加各种参数,以便可以更改数据系列的标记样式,颜色或任何其他方面。
AddSeries "Crop", cropSeries, landUseChart, xlMarkerStyleCircle
AddSeries "Gravel", gravelSeries, landUseChart, xlMarkerStyleDiamond
AddSeries "Native Grass", nativeGrassSeries, landUseChart, xlMarkerStyleSquare
(可选)您可以添加逻辑以设置图表标题,自定义图例以及图表的其他方面。
这是整个模块:
Option Explicit
Sub BuildLandUseChart()
Dim landUseWS As Worksheet
Set landUseWS = ThisWorkbook.Sheets("Sheet2")
Dim lastRow As Long
Dim xValues As Range
Dim yValues As Range
Dim useValues As Range
With landUseWS
lastRow = .Cells(.Rows.Count, "N").End(xlUp).Row
Set xValues = .Range("N1").Resize(lastRow, 1)
Set yValues = .Range("O1").Resize(lastRow, 1)
Set useValues = .Range("W1").Resize(lastRow, 1)
End With
Dim landUseChart As Chart
Set landUseChart = GetLandUseChart(landUseWS)
Dim cropSeries As Range
Dim gravelSeries As Range
Dim nativeGrassSeries As Range
Set cropSeries = CreateLandUseSeries("Crop", xValues, yValues, useValues)
Set gravelSeries = CreateLandUseSeries("Gravel", xValues, yValues, useValues)
Set nativeGrassSeries = CreateLandUseSeries("Native Grass", xValues, yValues, useValues)
AddSeries "Crop", cropSeries, landUseChart, xlMarkerStyleCircle
AddSeries "Gravel", gravelSeries, landUseChart, xlMarkerStyleDiamond
AddSeries "Native Grass", nativeGrassSeries, landUseChart, xlMarkerStyleSquare
End Sub
Private Sub AddSeries(ByVal newName As String, _
ByRef newSeries As Range, _
ByRef theChart As Chart, _
ByVal theMarker As XlMarkerStyle)
Dim theSeries As Series
With theChart
Set theSeries = .SeriesCollection.newSeries
With theSeries
.Name = newName
.xValues = newSeries.Resize(, 1)
.Values = newSeries.Offset(, 1).Resize(, 1)
'--- add some parameters to customize the marker style
' color, size, etc
.MarkerStyle = theMarker
End With
End With
End Sub
Private Function GetLandUseChart(ByRef ws As Worksheet) As Chart
Dim theChart As Chart
On Error Resume Next
Set theChart = ws.ChartObjects("EastingNorthingGraph").Chart
If theChart Is Nothing Then
'--- can't find it, so create it
Dim newObject As ChartObject
Set newObject = ws.ChartObjects.Add(Top:=10, Left:=325, _
Width:=600, Height:=300)
newObject.Name = "EastingNorthingGraph"
Set theChart = newObject.Chart
With theChart
.ChartType = xlXYScatter
.Location Where:=xlLocationAsObject, Name:=ws.Name
End With
End If
'--- delete any existing series so we have an empty chart to work with
Do Until theChart.SeriesCollection.Count = 0
theChart.SeriesCollection(1).Delete
Loop
Set GetLandUseChart = theChart
End Function
Private Function CreateLandUseSeries(ByVal useType As String, _
ByRef xValues As Range, _
ByRef yValues As Range, _
ByRef useValues As Range) As Range
Dim xData As Variant
Dim yData As Variant
Dim useData As Variant
xData = xValues.Value
yData = yValues.Value
useData = useValues.Value
Dim useRange As Range
Dim i As Long
For i = LBound(useData) To UBound(useData)
If useData(i, 1) = useType Then
If useRange Is Nothing Then
Set useRange = Union(xValues(i, 1), yValues(i, 1))
Else
Set useRange = Union(useRange, xValues(i, 1), yValues(i, 1))
End If
End If
Next i
Set CreateLandUseSeries = useRange
End Function