如何用C#和Blazor ApexCharts分组数据并构建堆叠柱状图?
Blazor Apex Charts 堆叠柱状图数据展示错误问题
我用Blazor + Blazor Apex Charts开发仪表盘图表,当前遇到以下问题:
- 应用按周期运行,仅展示选中周期回溯的数据,周期为月份的整数格式(如202302、202401)
- 需要实现堆叠柱状图:每个柱子按项目类型堆叠展示收入,数据范围覆盖选中周期至当年首个月份,后续需支持与上一年同期数据对比,且各月项目类型无需一致
- 目前
testStack列表已包含每个周期各项目类型的汇总收入数据,但代码生成的堆叠柱状图数据显示错误,先尝试实现当年数据的堆叠展示
后端代码
[Inject] AppData appData { get; set; } [Parameter] public List<ProjectReport> chartDataForStack { get; set; } private List<RevenueProjectType> testStack = new List<RevenueProjectType>(); private ApexChartOptions<RevenueProjectType> options; protected override Task OnInitializedAsync() { options = new ApexChartOptions<RevenueProjectType> { Chart = new Chart { Stacked = true, }, PlotOptions = new PlotOptions { Bar = new PlotOptionsBar { Horizontal = false } }, }; SortData(); return base.OnInitializedAsync(); } public void SortData() { // chartDataForStack在传入本组件前已按部分参数排序,最早月份为selectedYear var selectedYear = appData.SelectedPeriod / 100; var testData = chartDataForStack.Where(x => x.type == "revenue") .GroupBy(g => g.period) .OrderBy(o => o.Key) .ToList(); var thisYear = new List<IGrouping<int, ProjectReport>>(); var lastYear = new List<IGrouping<int, ProjectReport>>(); testGroup2 = new List<RevenueProjectType>(); foreach (var group in testData) { if (group.Key / 100 == selectedYear) { thisYear.Add(group); } else if (group.Key % 100 <= appData.SelectedPeriod % 100) { lastYear.Add(group); } } foreach (var group in thisYear) { var temp = group.GroupBy(x => x.project_type).ToList(); testGroup.AddRange(temp); } foreach (var item in testGroup) { var revProjType = new RevenueProjectType(); revProjType.revenue = item.Sum(x => x.acc); revProjType.projectType = item.Key; revProjType.period = item.FirstOrDefault(x => x.period != 0).period.ConvertRawPeriod(); testStack.Add(revProjType); } }
cshtml代码
<ApexChart TItem="RevenueProjectType" Title="Test" Options=options> @foreach(var item in testStack) { <ApexPointSeries TItem="RevenueProjectType" Items="@testStack" Name="@item.projectType" SeriesType="SeriesType.Bar" XValue="@(e => e.period)" YAggregate="@(e => e.Sum(e => e.revenue))" ShowDataLabels /> } </ApexChart>
RevenueProjectType类
public class RevenueProjectType { public string projectType { get; set; } public string period { get; set; } public decimal? revenue { get; set; } public string projectTypeName { get; set; } }
问题分析与修复
当前代码核心问题是重复创建了过多的ApexPointSeries:遍历testStack每条数据都生成一个系列,而正确逻辑是按项目类型创建系列,每个项目类型对应一个跨月份的数据集。
修复步骤:
重构数据分组逻辑
修改SortData方法,先收集所有唯一项目类型,再为每个类型整理对应各月份的收入:// 替换原SortData中最后部分代码 var allProjectTypes = testGroup.Select(g => g.Key).Distinct().ToList(); testStack = new List<RevenueProjectType>(); foreach (var type in allProjectTypes) { foreach (var monthGroup in thisYear) { var periodStr = monthGroup.Key.ConvertRawPeriod(); var revenue = monthGroup.Where(x => x.project_type == type).Sum(x => x.acc); testStack.Add(new RevenueProjectType { projectType = type, period = periodStr, revenue = revenue }); } }调整前端系列渲染逻辑
遍历唯一项目类型创建系列,每个系列仅绑定对应类型的数据:@{ var uniqueProjectTypes = testStack.Select(x => x.projectType).Distinct().ToList(); } <ApexChart TItem="RevenueProjectType" Title="Test" Options=options> @foreach(var type in uniqueProjectTypes) { var typeData = testStack.Where(x => x.projectType == type).ToList(); <ApexPointSeries TItem="RevenueProjectType" Items="@typeData" Name="@type" SeriesType="SeriesType.Bar" XValue="@(e => e.period)" YValue="@(e => e.revenue)" ShowDataLabels /> } </ApexChart>后续扩展(上年数据对比)
若要添加上年数据对比,可为RevenueProjectType增加IsLastYear标识字段,渲染时通过StackGroup属性区分当年/上年系列:<ApexPointSeries ... StackGroup="@(item.IsLastYear ? "lastYear" : "thisYear")" />
关键说明:
- Blazor Apex Charts的堆叠逻辑:相同
StackGroup的系列会堆叠在一起,默认所有系列归为同一组 - 每个系列对应一个数据维度(项目类型),需包含该维度下所有X轴(月份)的数据
- 避免在前端用
YAggregate求和,应提前在后端计算好每个项目类型、每个月份的收入值,前端直接绑定YValue
内容的提问来源于stack exchange,提问作者CSP
相关产品推荐
相关产品推荐

