0

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

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
waladi
  • 3
  • 2
  • thx Sir Rufo for the picture, anyway this is my 1st question, if i need to give more data or else please tell me. thanks – waladi Feb 19 '14 at 08:28
  • Possible duplicate, [`Plotting a TChart with time as the X-axis`](http://stackoverflow.com/q/4791053/576719). – LU RD Feb 19 '14 at 08:51
  • i'm not really want the system time for the label, the time i meant was the time that recorded in my table. plus i need to make it a new series everytime the date change, but i'm sorry if i asked the wrong question. – waladi Feb 19 '14 at 10:34
  • Just replace the x-value with your table time (as a TDateTime value), and define how your x-axis should be displayed. `Chart1.Series[dateX].XValues.DateTime := True; Chart1.BottomAxis.DateTimeFormat := 'hh:nn';` – LU RD Feb 19 '14 at 11:37

1 Answers1

1

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);
                ....
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
teran
  • 3,214
  • 1
  • 21
  • 30
  • You don't need a dictionary, if the list is already sorted by group key first `ORDER BY Date, Time`. A new series is needed, if the group key changes – Sir Rufo Feb 19 '14 at 09:10
  • @SirRufo yes, thats why I wrote "if your dataset is not sorted" – teran Feb 19 '14 at 09:11
  • Oh, I was just focused on the code ... but the question targets **Delphi7** and generics are unknown there – Sir Rufo Feb 19 '14 at 09:14
  • @SirRufo oh, really, I've missed `delphi-7` tag. – teran Feb 19 '14 at 09:19
  • thanks, i have sort the date and time when i create the sql statement, still working to make it work, i'll comment again about the result – waladi Feb 19 '14 at 10:19
  • thank @teran , just need little modification, somehow command try, s.beginupdate, finally, s.endupdate not working, God bless you. – waladi Feb 25 '14 at 08:22