【问题标题】:Why does my stacked column chart print incorrect x axis labels?为什么我的堆积柱形图打印不正确的 x 轴标签?
【发布时间】:2022-01-23 02:35:58
【问题描述】:

一点信息:

我想用过去 12 个月的交易填充堆积柱形图。 每列应该是一年中的一个月,交易当然是相互叠加的。

目前,我只有一个测试文档,可以从中提取一些数据。我首先尝试将数据(来自 csv)直接放入图表中,但这只会导致多列具有多个重复的 x 轴标签,并且没有堆叠。

我做了一些挖掘并找到了这个解决方案。不幸的是,结果不是我想要的。事务堆叠但x轴标签不正确

目前有

    Dim rowsTra() As String = File.ReadAllLines(".\data\transactions.csv")
    Dim traVal() As String
    Dim preYear As DateTime = DateTime.Now.AddYears(-1)
    Dim j As Integer = 0
    Dim dtTest As DataTable = New DataTable
    dtTest.Columns.Add("col1", GetType(Double))
    dtTest.Columns.Add("col2", GetType(String))
    dtTest.Columns.Add("col3", GetType(String))

    For i As Integer = 0 To rowsTra.Length - 1 Step +1                                      ' Looping through all transactions
        traVal = rowsTra(j).ToString().Split(",")
        Dim traDate As String = Convert.ToDateTime(traVal(1))
        If (traDate >= preYear) Then                                                        ' Check if date is not older than 1 year
            Dim conMonth As Date = CDate(traVal(1))
            Dim month = conMonth.ToString("MMM yyyy")
            dtTest.Rows.Add(traVal(6), month, traVal(4))
        Else
            i = rowsTra.Length - 1                                                          ' Quit loop if year ends (will only work if csv is chronological
        End If
        j += 1
    Next

    Dim dv As DataView = New DataView(dtTest)
    dv.Sort = "col2 asc"

    chTrend.Series.Clear()
    chTrend.Titles.Clear()                                                             ' Clear
    chTrend.DataBindCrossTable(dv, "col3", "col2", "col1", "Label=col1")                    ' Populate chart

    For Each cs As Series In chTrend.Series                                                 ' Stack values
        cs.ChartType = SeriesChartType.StackedColumn
    Next

通过使用这个 csv 文件,我得到了这个结果:

Account 1,19 Dec 2021,Man 1,Cat 1,Subcat 1,test,5
Account 2,01 Dec 2021,Man 2,Cat 2,Subcat 2,test,10
Account 5,01 Nov 2021,Man 4,Cat 2,Subcat 2,test,10
Account 4,27 Oct 2021,Man 4,Cat 4,Subcat 4,test,20
Account 3,10 Oct 2021,Man 3,Cat 3,Subcat 3,test,15
Account 1,03 Sep 2020,Man 1,Cat 1,Subcat 1,test,25
           = col2                  =col3         =col1                  

为什么在这种情况下会在“2021 年 12 月”下添加 4 笔交易,而实际上只有 2 笔交易? 我注意到,当我将第三个列出的交易更改为另一个 Subcat 时,所有交易都在 2021 年 12 月以下。

我也尝试在 dtTest 中为 col2 提供 Date 类型,但这只是给出了一个更奇怪的图表,我不知道如何将日期格式化为“MMM yyyy”。这是我从日期时间转移到字符串的原因

我不确定自己做错了什么。

感谢您的意见。抱歉代码乱七八糟,还在学习中。

【问题讨论】:

  • 好的,所以我可能已经想出了一个解决方案,但我不确定它是否可行。我认为它打印出一个不正确的图表,因为几个月来并不是所有现有的子类别都被赋予了一个值。是否有一种有效的方法可以为每个月生成所有现有子类别,或者最好单独存储子类别并循环遍历它们以在 dataTable 中创建所需的行?

标签: vb.net charts


【解决方案1】:

所以我自己做了一些实验,我相信我找到了解决问题的“A”解决方案。

我正在分享它,因为它可能对将来的某人有所帮助。 最后我想出了这个解决方案。

它不仅可以通过添加所需的额外行来正确堆叠(如我的评论中所述),而且还可以将现有类别的值相加。

这是我最初的问题中没有提到的目标。

我绝对不是说这是最好的解决方案,我知道它会导致一些可扩展性的性能问题。我什至可以说它甚至可能只是意大利面条式代码,所以我很想看到有更多经验的人找到解决这个问题的更佳解决方案。

Dim rowsTra() As String = File.ReadAllLines(".\transactions.csv")
    Dim traVal() As String
    Dim strCat As String = ""
    Dim strDate As String = ""
    Dim preYear As DateTime = DateTime.Now.AddYears(-1)                                     ' Start date for all visible transactions in chart
    Dim dtTrend As DataTable = New DataTable
    dtTrend.Columns.Add("outflow", GetType(Double))                                         ' Columns for DataTable
    dtTrend.Columns.Add("date", GetType(String))
    dtTrend.Columns.Add("category", GetType(String))
    Dim valExist As Boolean
    Dim l As Integer = 0 'l
    Dim m As Integer = 0 'm

    For i As Integer = 0 To rowsTra.Length - 1 Step +1                                      ' Loop all transactions to add to DataTable and list all dates and categories
        traVal = rowsTra(l).ToString().Split(",")
        Dim traDate As String = Convert.ToDateTime(traVal(1))
        Dim traMonth = CDate(traVal(1)).ToString("MMM yyyy")                                ' Convert to Month Year
        If (traDate >= preYear) Then                                                        ' Check if date is not older than 1 year
            If dtTrend.Rows.Count = 0 Then                                                  ' First transaction loop
                dtTrend.Rows.Add(traVal(6), traMonth, traVal(4))                            ' Add row to DataTable in order "outflow/date/category"
            Else                                                                            ' If not first transaction
                m = 0
                valExist = False                                                            ' Reset valExist to false
                While m < dtTrend.Rows.Count                                                ' Loop DataTable, used to add outflow to existing categories
                    If dtTrend.Rows(m)(1).ToString = traMonth And dtTrend.Rows(m)(2) = traVal(4) Then   ' Check if date and category match between DataTable and Transactions 
                        dtTrend.Rows(m)(0) = dtTrend.Rows(m)(0) + traVal(6)                 ' Add outflow to existing DataTable row
                        m = dtTrend.Rows.Count
                        valExist = True
                    End If
                    m += 1
                End While

                If valExist = False Then                                                    ' If combo of date and subcategory does not exist:
                    dtTrend.Rows.Add(traVal(6), traMonth, traVal(4))                        ' Add new line to DataTable
                End If
            End If

            If strCat = "" Then                                                             ' If string has no value (first loop). Used to create list of subcategories
                strCat = traVal(4)
            ElseIf strCat.Contains(traVal(4)) Then                                          ' Check if category already exist in the string
            Else
                strCat = strCat + "," + traVal(4)
            End If
            If strDate = "" Then                                                            ' Ditto about but for Date
                strDate = traMonth
            ElseIf strDate.Contains(traMonth) Then
            Else
                strDate = strDate + "," + traMonth
            End If
        Else
            i = rowsTra.Length - 1                                                          ' Quit loop if year ends (will only work if csv is chronological
        End If
        l += 1
    Next

    Dim arrCat() As String = strCat.Split(",")                                              ' Split string to use in array
    Dim arrDate() As String = strDate.Split(",")
    Dim tfMatch As Boolean
    For i As Integer = 0 To arrCat.Length - 1 Step +1                                       ' Loop existing categories, used to add non existing row
        For j As Integer = 0 To arrDate.Length - 1 Step +1                                  ' Loop existing dates, rows need to be added to get full series
            Dim dtRows = dtTrend.Rows.Count
            For k As Integer = 0 To dtRows - 1                                              ' Loop through original DataTable values
                If dtTrend.Rows(k)(1) = arrDate(j) And dtTrend.Rows(k)(2) = arrCat(i) Then  ' Check if date and categorys match anywhere in the DataTable
                    tfMatch = True
                End If
            Next
            If tfMatch = True Then                                                          ' If match, reset and search with next date
                tfMatch = False
            Else
                dtTrend.Rows.Add(0, arrDate(j), arrCat(i))                                  ' If no match, add as new row in DataTable
                tfMatch = False                                                             ' Reset, moving to next category
            End If
        Next
    Next

    Dim dv As DataView = New DataView(dtTrend)
    dv.Sort = "date desc"

    chTrend.Series.Clear()                                                                  ' Clear chart before fill so no exceptions are generated
    chTrend.Titles.Clear()
    chTrend.DataManipulator.FilterSetEmptyPoints = True                                     ' Filter to get correct stack
    chTrend.DataManipulator.FilterMatchedPoints = True
    chTrend.DataBindCrossTable(dv, "category", "date", "outflow", "Label=outflow")          ' Populate chart

    For Each cs As Series In chTrend.Series                                                 ' Removes labels of newly added rows with value "0"
        chTrend.DataManipulator.Filter(DataVisualization.Charting.CompareMethod.EqualTo, 0, cs)   'Compare if equal to zero, filter out
        cs.ChartType = SeriesChartType.StackedColumn                                        ' Chart type
        'Dim dpcp As DataPointCustomProperties = New DataPointCustomProperties
    Next

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 2020-10-27
    • 1970-01-01
    相关资源
    最近更新 更多