VBA 从分散的数据行创建图表

VBA chart creation from scattered data rows

我正在创建一个 UI 用于输入、编辑、导出、导入患者数据(胆固醇生物标志物)。 我遇到了一个问题,需要显示来自“数据”作品的可用数据sheet。

数据如下所示:

我需要根据 ,, Elizbeth Norton,, 的可用数据创建图表,X 轴为日期,Y 轴为 Chol, Trig, LDL, HDL(单独的线)。

结果是通过使用listBox使用用户形式来管理的(在其中选择数据时,按钮应创建图表。在列表框中选择数据) 此代码找到所需的数据并将选定的结果放入数组

用户表单:

查找所需数据的代码:

If Len(f_FindAll.TextBox_Find.Value) >= 3 Then 'Do search if text in find box is longer than 3 character.
    
    Set SearchRange = ActiveWorkbook.Worksheets("Data").Range("C:E").Cells
    
    FindWhat = f_FindAll.TextBox_Find.Value
    'Calls the FindAll function
    Set FoundCells = FindAll(SearchRange:=SearchRange, _
                            FindWhat:=FindWhat, _
                            LookIn:=xlValues, _
                            LookAt:=xlPart, _
                            SearchOrder:=xlByColumns, _
                            MatchCase:=False, _
                            BeginsWith:=vbNullString, _
                            EndsWith:=vbNullString, _
                            BeginEndCompare:=vbTextCompare)
    If FoundCells Is Nothing Then
        ReDim arrResults(1 To 1, 1 To 5)
        arrResults(1, 1) = "Data not found!!!"

    Else
        'Add results of FindAll to an array
        ReDim arrResults(1 To FoundCells.Count, 1 To 5)
        lFound = 1
         For Each FoundCell In FoundCells
            If FoundCell.Column = 3 Then
                arrResults(lFound, 1) = FoundCell.Offset(0, -1).Value
                arrResults(lFound, 2) = FoundCell.Value
                arrResults(lFound, 3) = FoundCell.Offset(0, 1).Value
                arrResults(lFound, 4) = FoundCell.Offset(0, 2).Value
                arrResults(lFound, 5) = FoundCell.Address
                lFound = lFound + 1
            Else
                If FoundCell.Column = 4 Then
                    arrResults(lFound, 1) = FoundCell.Offset(0, -2).Value
                    arrResults(lFound, 2) = FoundCell.Offset(0, -1).Value
                    arrResults(lFound, 3) = FoundCell.Value
                    arrResults(lFound, 4) = FoundCell.Offset(0, 1).Value
                    arrResults(lFound, 5) = FoundCell.Address
                    lFound = lFound + 1
                Else
                    If FoundCell.Column = 5 Then
                        arrResults(lFound, 1) = FoundCell.Offset(0, -3).Value
                        arrResults(lFound, 2) = FoundCell.Offset(0, -2).Value
                        arrResults(lFound, 3) = FoundCell.Offset(0, -1).Value
                        arrResults(lFound, 4) = FoundCell.Value
                        arrResults(lFound, 5) = FoundCell.Address
                        lFound = lFound + 1
                    End If
                End If
            End If
            
        Next FoundCell
    End If
    
    'Populate the listbox with the array
    Me.ListBox_Results.List = arrResults

在用户表单中显示所选数据的代码:

Private Sub ListBox_Results_Click()
'Go to selection on the sheet when the result is clicked

Dim strAddress As String
Dim l As Integer

    For l = 0 To ListBox_Results.ListCount
        If ListBox_Results.Selected(l) = True Then
            strAddress = ListBox_Results.List(l, 4)
            Rownum = Range(strAddress).Row
            Colnum = Range(strAddress).Column
            ActiveWorkbook.Worksheets("Data").Select
            Cells(Rownum, Colnum).Select
            'Populate textboxes with results
            'and maybe populate chart data range with results aswell????
            With ActiveWorkbook.Worksheets("Data")
                f_FindAll.TextBox_Results1.Value = .Cells(.Range(strAddress).Row, 1).Value
                f_FindAll.TextBox_Results2.Value = .Cells(.Range(strAddress).Row, 2).Value
                f_FindAll.TextBox_Results3.Value = .Cells(.Range(strAddress).Row, 3).Value
                f_FindAll.TextBox_Results4.Value = .Cells(.Range(strAddress).Row, 4).Value
                f_FindAll.TextBox_Results5.Value = .Cells(.Range(strAddress).Row, 5).Value
                f_FindAll.TextBox_Results6.Value = .Cells(.Range(strAddress).Row, 6).Value
                f_FindAll.TextBox_Results7.Value = .Cells(.Range(strAddress).Row, 7).Value
                f_FindAll.TextBox_Results8.Value = .Cells(.Range(strAddress).Row, 8).Value
                f_FindAll.TextBox_Results9.Value = .Cells(.Range(strAddress).Row, 9).Value
                f_FindAll.TextBox_Results10.Value = .Cells(.Range(strAddress).Row, 10).Value
                f_FindAll.TextBox_Results11.Value = .Cells(.Range(strAddress).Row, 11).Value
                f_FindAll.TextBox_Results12.Value = .Cells(.Range(strAddress).Row, 12).Value
            End With
            GoTo EndLoop
        End If
    Next l

EndLoop:
    
End Sub

那么最好的选择是什么?也许改为对 sheet“数据”中的数据进行排序并根据所选范围创建图表?

感谢您的帮助。

一种方法是构建行号集合,然后使用它们为图表的每个系列创建数组。或者将数组转储到另一个 sheet 并将其用作源数据。

Option Explicit

Sub PlotData()

    Dim wb As Workbook, ws As Worksheet
    Dim rngSearch As Range, rngFound As Range
    Dim FindWhat As String, FirstFound As String
    Dim datarows As Collection, ar
    Dim r As Long, i As Integer, n As Integer
    
    Set wb = ThisWorkbook
    Set ws = wb.Sheets("Data")
    Set datarows = New Collection
    Set rngSearch = ws.UsedRange.Columns("C:E")

    ' build collection of rows
    FindWhat = "11342"
    Set rngFound = rngSearch.Find(FindWhat, _
                    LookIn:=xlValues, LookAt:=xlPart, _
                    SearchOrder:=xlByColumns, MatchCase:=False)
    
    If rngFound Is Nothing Then
        ' no match
        Exit Sub
    Else
        FirstFound = rngFound.Address
        Do
            n = n + 1
            datarows.Add rngFound.Row, CStr(n)
            Set rngFound = rngSearch.FindNext(After:=rngFound)
        Loop While Not rngFound Is Nothing And rngFound.Address <> FirstFound
    End If

    ' fill array
    ReDim ar(1 To n, 1 To 5), x(n - 1), y(n - 1)
    Dim sname
    sname = Array("date", "chol", "trig", "LDL", "HDL")
    For i = 1 To n
        With ws
           r = datarows(i)
           x(i - 1) = .Cells(r, "B") 'date
           ar(i, 1) = .Cells(r, "B") 'date
           ar(i, 2) = .Cells(r, "I") 'chol
           ar(i, 3) = .Cells(r, "J") 'trig
           ar(i, 4) = .Cells(r, "K") 'LDL
           ar(i, 5) = .Cells(r, "L") 'HDL
        End With
    Next

    ' copy to sheet if required as source data for plot
    'Sheet2.Range("A1:E1") = sname
    'Sheet2.Range("A2:E" & n + 1) = ar

    ' plot graph
    Dim cht As Chart, c As Integer, srs As Series
    Set cht = ws.Shapes.AddChart(xlLineMarkers).Chart
    With cht
        .HasTitle = True
        .ChartTitle.Text = FindWhat
        For c = 2 To 5
            'Define the array of values for each series
            For i = 1 To n
                y(i - 1) = ar(i, c)
            Next
            Set srs = .SeriesCollection.NewSeries
            With srs
                .XValues = x
                .Values = y
                .name = sname(c - 1)
            End With
        Next
        .Location Where:=xlLocationAsNewSheet, name:=FindWhat
    End With

    MsgBox "Done"
End Sub