【问题标题】:Asp.net chart multi-series showing wrong dataAsp.net图表多系列显示错误数据
【发布时间】:2012-10-20 01:19:07
【问题描述】:

用asp.net多系列图表编程解决this problem后,在另一个多系列图表中发现了另一个问题:

我想显示月度销售报告,显示最近m 个月在批准和拒绝提案中的演变。有些月份,没有任何被拒绝的提案,因此以下查询 (C#/Oracle) 返回一些空结果。

select to_char(c.date,'YYYYMM') ctb_month, 
       c.approved,
       count(distinct c.f1) amt_c, 
       count(b.f1) amt_b, 
       sum(nvl(b.value,0)) sum_values
from bens b 
     join contracts c
     on b.contract_id = c.f1
where b.seller = :USR_ID 
AND c.date 
     BETWEEN add_months(:DATAI,:MONTHS) AND :DATAI
group by to_char(c.date,'YYYYMM'), c.approved
order by ctb_month

OBS:在绑定:MONTHS参数之前,我确保它的值为负数。

查询结果示例:

CTB_MONTH APPROVED AMT_C AMT_B SUM_VALUES

201209    APPROVED    10    20    1234.56
201209    PENDING      3     3     120.21
201210    APPROVED    12    18     850.52
201210    PENDING      4     4     158.71
201210    REJECTED     1     1      80.40

注意:在这种情况下,当前卖家在 201209 年没有任何被拒绝的提案。

填充图表的代码:

我将低层传递的数据存储在 var report 中,并通过 APPROVED 状态过滤数据:

var approved = queryResult
              .Where(r => r.APPROVED == "APPROVED")
              .ToList()
              ;
var rejected = queryResult
              .Where(r => r.APPROVED == "REJECTED")
              .ToList()
              ;
var pending =  queryResult
              .Where(r => r.APPROVED == "PENDING")
              .ToList()
              ;

然后,我在循环中创建系列

for (int i = 0; i < 6; i++) {
    Series temp = new Series {
        XAxisType = AxisType.Primary,
        XValueType = ChartValueType.DateTime,
        YAxisType = AxisType.Primary,
        //mostra só a quantidade de contratos
        IsValueShownAsLabel = i % 2 == 0 ? true : false,
        ChartType = SeriesChartType.Column,
        CustomProperties = "EmptyPointValue=Zero",
        Legend = "Legenda"
    };
    grafico.Series.Add(temp);
}

并手工对每个系列进行DataBinding

// approved contracts
grafico.Series[0].Points.DataBindXY(approved, "MONTH", approved, "AMT_C");
grafico.Series[0].LegendText = "Cont. approved";
// approved bens
grafico.Series[1].Points.DataBindXY(approved, "MONTH", approved, "AMT_B");
grafico.Series[1].LegendText = "Ben. approved";
grafico.Series[1].ChartType = SeriesChartType.Line;
// pending contracts
grafico.Series[2].Points.DataBindXY(pending, "MONTH", pending, "AMT_C");
grafico.Series[2].LegendText = "Cont. pending";
// pending bens
grafico.Series[3].Points.DataBindXY(pending, "MONTH", pending, "AMT_B");
grafico.Series[3].LegendText = "Ben. pending";
grafico.Series[3].ChartType = SeriesChartType.Line;
// rejected contracts
grafico.Series[4].Points.DataBindXY(rejected, "MONTH", rejected, "AMT_C");
grafico.Series[4].LegendText = "Cont. rejected";
// rejected bens
grafico.Series[5].Points.DataBindXY(rejected, "MONTH", rejected, "AMT_B");
grafico.Series[5].LegendText = "Ben. rejected";
grafico.Series[5].ChartType = SeriesChartType.Line;

注意:grafico 是我的图表对象;一些视觉设置在&lt;asp:Chart&gt; 标记中定义。

当我运行应用程序时,完整的系列被正确绘制,但不完整的系列(201209 / REJECTED,在上面的例子中)被绘制在错误的X 坐标中(201210 的值在列中绘制为201209,在这种情况下),就好像控件忽略了在 DataBindXY 方法中传递的 X 值并按顺序绘制值。

有人知道如何解决这个问题吗? 提前致谢。

[已解决]感谢@jbl,图表现在可以在正确的位置绘制值。

代码:

var allMonths = queryResult
    .Select(x => x.MONTH)
    .Distinct()
    .OrderBy(mes => mes)
    ;

foreach (var mes in allMonths) {

    bool hasData = rejected.Any(r => r.MONTH == mes);
    if (hasData == false) {
        rejected.Add(new MonthlyData() { MONTH = mes, APPROVED = "REJECTED" });
    }
    hasData = pending.Any(r => r.MONTH == mes);
    if (hasData == false) {
        pending.Add(new MonthlyData() { MONTH = mes, APPROVED = "PENDING" });
    }
    hasData = approved.Any(r => r.MONTH == mes);
    if (hasData == false) {
        approved.Add(new MonthlyData() { MONTH = mes, APPROVED = "APPROVED" });
    }
}
approved = approved.OrderBy(v => v.MONTH).ToList();
pending = pending.OrderBy(v => v.MONTH).ToList();
rejected = rejected.OrderBy(v => v.MONTH).ToList();

grafico.ChartAreas[0].AxisX.Interval = 1;
grafico.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Months;
grafico.ChartAreas[0].AxisX.IntervalOffset = 1;
grafico.ChartAreas[0].AxisX.IntervalOffsetType = DateTimeIntervalType.Months;

注意: MonthlyData 是一个简单的类,用于传输查询结果中每一行的值。

【问题讨论】:

    标签: c# asp.net .net-4.0 charts


    【解决方案1】:

    我猜你将不得不使用空数据点 http://msdn.microsoft.com/en-us/library/dd456677.aspx 来对齐你的所有系列

    这意味着:

    • 构建系列中所有 x 值的集合
    • 将所有这些 x 值与您的系列进行左连接以检测所有缺失点
    • 用空数据点填充缺失点

    希望这会有所帮助

    编辑:您可以为已批准/AMT_C 系列尝试(未测试)类似的东西

    var allXvalues = queryResult.select(r=>r.CTB_MONTH).Distinct().OrderBy(month=>month).ToList();
    
    
    allXvalues
      .ForEach
       (
        xvalue=>
          {
            var p = approved.Where(o=>o.MONTH==xValue).FirstOrDefault();
            if(p==null)
                grafico.Series[0].Points.Add(new DataPoint(p.MONTH,p.AMT_C));
            else
                grafico.Series[0].Points.Add(new DataPoint(xvalue,0){IsEmpty=true});
          }
       );
    

    【讨论】:

    • 在代码末尾添加了grafico.DataManipulator.InsertEmptyPoints(1, IntervalType.Days, "Series1,Series2,Series3,Series4,Series5,Series6");这一行。没用:(
    • @TimoteoBrasil :在我的答案中添加了一个示例。顺便说一句:您是否“指定了与图表区域的主轴或辅助轴(ChartArea.AxisX 或 ChartArea.AxisX2 对象)中的 Interval、IntervalOffset、IntervalType 和 IntervalOffsetType 属性相对应的间隔。” ?
    • 谢谢,@jbl。我用对我有用的代码更新了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多