【发布时间】:2015-07-14 14:52:23
【问题描述】:
我收到了一张包含 4 个图表的 Excel 表格。图表的数据位于另一个未提供的工作簿中。
目标:我想使用 VBA 子程序从图表中提取数据。
问题:我在“类型不匹配”方面遇到了一些问题。当我尝试将 Variant 数组 oSeries.XValues 分配给一系列单元格时。
Option Explicit
Option Base 1
' 1. Enter the following macro code in a module sheet.
' 2. Select the chart from which you want to extract the underlying data values.
' 3. Run the GetChartValues Sub. The data from the chart is placed in a new worksheet named "ChartName Data".
'
Sub GetChartValues()
'
Dim lxNumberOfRows As Long
Dim lyNumberOfRows As Long
Dim oSeries As Series
Dim lCounter As Long
Dim oWorksheet As Worksheet
Dim oChart As Chart
Dim xValues() As Variant
Dim yValues() As Variant
Dim xDestination As Range
Dim yDestination As Range
Set oChart = ActiveChart
' If a chart is not active, just exit
If oChart Is Nothing Then
Exit Sub
End If
' Create the worksheet for storing data
Set oWorksheet = ActiveWorkbook.Worksheets.Add
oWorksheet.Name = oChart.Name & " Data"
' Loop through all series in the chart and write there values to
' the worksheet.
lCounter = 1
For Each oSeries In oChart.SeriesCollection
xValues = oSeries.xValues
yValues = oSeries.values
' Calculate the number of rows of data. 1048576 is maximum number of rows in excel.
lxNumberOfRows = WorksheetFunction.Min(UBound(oSeries.xValues), 1048576 - 1)
lyNumberOfRows = WorksheetFunction.Min(UBound(oSeries.values), 1048576 - 1)
' Sometimes the Array is to big, so chop off the end
ReDim Preserve xValues(lxNumberOfRows)
ReDim Preserve yValues(lyNumberOfRows)
With oWorksheet
' Put the name of the series at the top of each column
.Cells(1, 2 * lCounter - 1) = oSeries.Name
.Cells(1, 2 * lCounter) = oSeries.Name
Set xDestination = .Range(.Cells(1, 2 * lCounter - 1), .Cells(lxNumberOfRows + 1, 2 * lCounter - 1))
Set yDestination = .Range(.Cells(1, 2 * lCounter), .Cells(lxNumberOfRows + 1, 2 * lCounter))
'Assign the x and y data from the chart to a range in the worksheet
xDestination.value = Application.Transpose(xValues)
yDestination.value = Application.Transpose(yValues)
' This does not work either
' .Range(.Cells(2, 2 * lCounter - 1), .Cells(lxNumberOfRows + 1, 2 * lCounter - 1)).value = Application.Transpose(oSeries.xValues)
' .Range(.Cells(2, 2 * lCounter), .Cells(lxNumberOfRows + 1, 2 * lCounter)).value = Application.Transpose(oSeries.values)
End With
lCounter = lCounter + 1
Next
' Cleanup
Set oChart = Nothing
Set oWorksheet = Nothing
End Sub
主要问题是以下几行:
.Range(.Cells(2, 2 * lCounter - 1), .Cells(lxNumberOfRows + 1, 2 * lCounter - 1)) = Application.Transpose(oSeries.xValues)
.Range(.Cells(2, 2 * lCounter), .Cells(lxNumberOfRows + 1, 2 * lCounter)) = Application.Transpose(oSeries.values)
使用 Locals 窗口进一步检查后,我发现以下内容:
下面的代码有效,上面的代码无效。
Sub Test2()
Dim A(6) As Variant
'A(1) = 1
A(2) = 2#
A(3) = 3#
A(4) = 4#
A(5) = 5#
Range(Cells(1, 1), Cells(6, 1)).value = Application.Transpose(A)
End Sub
为什么第一段代码不起作用?
在这种情况下,循环遍历许多单元格很慢(我已经尝试过)。请不要使用循环,除非它是 1,000,000 个元素的秒数。
【问题讨论】:
-
我没有看到将具有
Empty值的数组分配给工作表的任何问题 - 你确定这是问题吗? -
同意@TimWilliams,我对
Empty和输出到某个范围没有问题。可能想在.Range()调用的末尾添加.Value以明确您想要的内容。有时,数组输出 IIRC 可能会出现问题。附带说明一下,Resize在像这样构建Ranges时是一个有用的功能。省去了很多中间使用.Cells会犯的错误。不过可能与您的问题无关。 -
如果我将
Empty以外的其他内容分配给第一个元素,那么我没有问题。这就是为什么我专注于Empty。当我从一个范围读入一个数组时,大小是(1 to 300, 1 to 1)。我正在使用的数组是(1 to 1048576),因此错过了一个维度。这与我的问题有关吗? -
由于这是最大行数,您可能会使用
Range超出Worksheet的底部,因为您要向其中添加1 行。我相信你所说的关于Empty的内容,但很难说是这个问题,因为我们中的两个人说它工作正常。我正在使用 Excel 2013 来实现它的价值。如果从第 1 行而不是第 2 行开始,是否存在问题? -
从 1 还是 2 开始都没有关系。我的代码中确实有一些逻辑来处理最大行数。为了清楚起见,我没有在这里展示它。