Question

I have a dynamic table from query showed by dbgrid that looked like this

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

The inputs for query are code=1, date1=01-feb-14, date2=03-feb-14

How can I make a line chart that have multiple series, group by date with xlabel = time and y value = score? My pseudo code is:

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

it will look something like this chart sample

Était-ce utile?

La solution

You should create series for each date manually. So you should iterate your dataset, each time when you meet new date you should create new series, add it to the chart, and add values.

In case your dataset is not sorted you might use temporary Dictionary (TDcitionary<integer, TLineSeries> from Generics.Collections)to store series references.

DateTime value actually is a double where int part represents day. So you have own key for each date. Also you can assign it series Tag property for possible further use.

Use BeginUpdate() and EndUpdate() methods before and after populating series values. When you create series use Chart reference as an owner. Next time you clear all series in chart, they will sucesfully destroyed.

Here is an example code:

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;

as question targets Delphi-7, it does not know about generics. So in this case the easiest way is to sort dataset by date (ORDER BY date). And then each time you meet new date, you should create new series. At first you need to initialize dInt := 0, and then compare it to FieldByName('date'). If it has changed, you should create new series.

    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);
                ....
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top