【问题标题】:create a multiple line chart's series from one table by grouping by date通过按日期分组从一个表中创建多折线图系列
【发布时间】:2014-02-19 05:34:46
【问题描述】:

我有一个来自 dbgrid 显示的查询的动态表,看起来像这样

code | Name | Date      | Time |Score
1    | Alex | 01-Feb-14 | 0600 |5
1    | Alex | 01-Feb-14 | 0700 |7
1    | Alex | 01-Feb-14 | 0800 |8
1    | Alex | 02-Feb-14 | 0600 |7
1    | Alex | 02-Feb-14 | 0800 |8
1    | Alex | 02-Feb-14 | 0900 |8
1    | Alex | 03-Feb-14 | 0700 |7
1    | Alex | 03-Feb-14 | 0800 |5
1    | Alex | 03-Feb-14 | 0900 |8

查询的输入是code=1, date1=01-feb-14, date2=03-feb-14

如何制作具有多个系列的折线图,按日期分组,xlabel = time 和 y value = score? 我的伪代码是:

for date1 to date 2
chart1.addseries
  for time=lowesttime to highesttime do
  begin
  series.xlabel = time
  series.yvalue = score
  end

它看起来像这样

【问题讨论】:

  • 感谢 Rufo 先生的图片,无论如何这是我的第一个问题,如果我需要提供更多数据,或者请告诉我。谢谢
  • 我真的不想要标签的系统时间,我的意思是我表中记录的时间。另外,每次日期更改时,我都需要制作一个新系列,但如果我问错了问题,我很抱歉。
  • 只需将 x 值替换为您的表格时间(作为 TDateTime 值),并定义您的 x 轴应如何显示。 Chart1.Series[dateX].XValues.DateTime := True; Chart1.BottomAxis.DateTimeFormat := 'hh:nn';

标签: delphi charts delphi-7


【解决方案1】:

您应该手动为每个日期创建系列。因此,您应该迭代您的数据集,每次遇到新日期时,您都应该创建新系列,将其添加到图表中并添加值。

如果您的数据集未排序,您可以使用临时字典(TDcitionary<integer, TLineSeries> from Generics.Collections)来存储系列参考。

DateTime 值实际上是一个double,其中 int 部分表示日期。因此,每个日期您都有自己的密钥。您还可以为其分配系列Tag 属性以供进一步使用。

在填充系列值之前和之后使用BeginUpdate()EndUpdate() 方法。 创建系列时,请使用图表参考作为所有者。下次你清除图表中的所有系列时,它们将成功销毁。

这是一个示例代码:

procedure TForm7.UpdateSeries();
var sd : TDictionary<integer, TLineSeries>;
    s : TLineSeries;
    d : TDate;
    dInt : integer;
    x : double;
    xlabel : string;
    i : integer;
begin
    DataChart.SeriesList.Clear();

    sd := TDictionary<integer, TLineSeries>.Create();
    try
        while not query.eof do begin
            d := query.FieldByName('Date').AsDateTime;
            dInt := round(d);

            if not sd.ContainsKey(dInt) then begin
                s := TLineSeries.Create(DataChart);
                s.Tag := dInt;  {for further use}
                DataChart.AddSeries(s);
                s.ParentChart := DataChart;
                s.Title := DateToStr(query.FieldByName('date').AsDateTime);
                s.Color := Random($FFFFFF);

                s.BeginUpdate();

                sd.AddOrSetValue(dInt, s);
            end
            else s := sd[dInt];

            //x value and label
            x := query.FieldByName('time').AsDateTime;
            xlabel := Format('Label %f', [x]);

            s.AddXY(x, query.FieldByName('score').AsInteger, xlabel);

            query.Next();
        end;
    finally
        for i := 0 to DataChart.SeriesCount - 1 do begin
            DataChart.Series[i].EndUpdate();
        end;

        sd.Free();
    end;
end;

作为问题目标Delphi-7,它不知道generics。所以在这种情况下,最简单的方法是按日期(ORDER BY date)对数据集进行排序。然后每次你遇到新的日期,你应该创建新的系列。首先需要初始化dInt := 0,然后与FieldByName('date')进行比较。如果它发生了变化,您应该创建新系列。

    dInt := 0;
    try
        while not query.eof do begin
            d := query.FieldByName('Date').AsDateTime;
            if round(d) <> dInt then begin
                dInt := round(d);
                s := TLineSeries.Create(DataChart);
                ....

【讨论】:

  • 你不需要字典,如果列表已经先按组键排序ORDER BY Date, Time。如果组键发生变化,则需要一个新系列
  • @SirRufo 是的,这就是我写“如果您的数据集未排序”的原因
  • 哦,我只是专注于代码......但是问题的目标是 Delphi7 并且泛型在那里是未知的
  • @SirRufo 哦,真的,我错过了delphi-7 标签。
  • 谢谢,我已经对创建 sql 语句时的日期和时间进行了排序,仍在努力使其工作,我将再次评论结果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 2021-10-17
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多