Page 1 of 1

Understanding bars and series

Posted: Wed Nov 22, 2023 3:12 pm
by 16895550
I can only see how to add series at runtime but not actual bars. I want a simple stacked bar chart. My data is -

Chartdate JobType Total
20/11/20203 0
21/11/20203 Tip/Return 2

Re: Understanding bars and series

Posted: Wed Nov 22, 2023 3:17 pm
by 16895550
The previous message posted while I was half way through.

I can only see how to add series at runtime but not actual bars. I want a simple stacked bar chart. My data is -

Code: Select all

Chartdate          JobType       Total
20/11/2023                       0
21/11/2023         Tip/Return    2
21/11/2023         Deliver       1
22/11/2023         Deliver       1
23/11/2023                       0
So only some days in the 6 day period have totals. The days with no totals should just be an empty bar, and the others stacked based on Jobtype.

I kinda was expecting to so something like

Code: Select all

while not eof etc.
add bar
 for each jobtype
   add series
but there only seems to be an add series

Can any one provide a bit of real or seudo code, so I can understand it better. Thanks

Re: Understanding bars and series

Posted: Thu Nov 23, 2023 10:13 am
by yeray
Hello,

I would create a self stacked TBarSeries for each jobtype:

Code: Select all

for jobtype in jobtypes do
begin
  with TBarSeries(Chart1.AddSeries(TBarSeries)) do
  begin
    MultiBar:=mbSelfStacked;
    Title:=jobtype.name;
  end;
end;
Then I would loop the data and add the values to one series or another depending on it:

Code: Select all

while not dataset.eof do
begin 
  for s in Chart1.Series do
  begin
    if s.Title=currentField.jobtype then
    begin
      s.Add(currentField.value);
      Break;
    end;
  end
  dataset.next;
end;

Re: Understanding bars and series

Posted: Thu Nov 23, 2023 3:42 pm
by 16895550
Hi Yeray

Wouldn't it be a TBarseries for each day ? and then jobtypes within each day ?


The bottom axis will have dates form Monday to Saturday, Left axis the totals, Each day could have up to 10 different series.

Andy

Re: Understanding bars and series

Posted: Thu Nov 23, 2023 3:51 pm
by 16895550
Ive added an image to show how I want it. Maybe its best to manipulate the datasource instead whihc is what I;ve done in the designer?
Screenshottchart.png
Screenshottchart.png (39.25 KiB) Viewed 26071 times
Thanks

Andy

Re: Understanding bars and series

Posted: Thu Nov 23, 2023 6:15 pm
by 16895550
Hi

I've created a series for each JObtype requested - Code below. I've hard coded until I fully understand how it works.
Screenshot 1chart2.png
Screenshot 1chart2.png (16.57 KiB) Viewed 26066 times
. However the resulting chart shows an extra series on Tuesday that I'm not adding and also a value for Wednesday, when I passed 0.
I've attached the chart image.
Andy

Code: Select all

         sJOBTYPE := 'Deliver' ;
         S1 := TBarSeries(Chart1.AddSeries(TBarSeries));
         S1.Clear;
         S1.Title := sJOBTYPE;
         S1.MultiBar := mbStacked;
         S1.Marks.Visible := False;
         S1.Marks.Style := smsValue ;
         S1.Color := GetJobTypeColour(sJobType) ;

         sJOBTYPE := 'Collect' ;
         S2 := TBarSeries(Chart1.AddSeries(TBarSeries));
         S2.Clear;
         S2.Title := sJOBTYPE;
         S2.MultiBar := mbStacked;
         S2.Marks.Visible := False;
         S2.Marks.Style := smsValue ;
         S2.Color := GetJobTypeColour(sJobType) ;

         sJOBTYPE := 'Exchange' ;
         S3 := TBarSeries(Chart1.AddSeries(TBarSeries));
         S3.Clear;
         S3.Title := sJOBTYPE;
         S3.MultiBar := mbStacked;
         S3.Marks.Visible := False;
         S3.Marks.Style := smsValue ;
         S3.Color := GetJobTypeColour(sJobType) ;

           S1.Add( 2 , 'Monday', clTeeColor);
           S1.Add( 4 , 'Tuesday', clTeeColor);
           S1.Add( 0 , 'Wednesday', clTeeColor);
           S1.Add( 5 , 'Thursday', clTeeColor);

           S2.Add( 3 , 'Monday', clTeeColor);
           S2.Add( 4 , 'Tuesday', clTeeColor);
           S2.Add( 1 , 'Thursday', clTeeColor);

           S3.Add( 1 , 'Monday', clTeeColor);
           S3.Add( 1 , 'Thursday', clTeeColor);

Re: Understanding bars and series

Posted: Mon Nov 27, 2023 12:34 pm
by yeray
Hello,

The Add function appends a value to the series value list, regardless of the label you are assigning to it.
That's the reason why the second value added in S3 is shown in the second bar, even if it's label is 'Thursday'. And the same for the third value in S2.
You should add the same number of values to all the series, so they can be stacked at the positions you expect them. To do so, you can add a zero (as you are doing in the first series for 'Wednesday') or a null, ie:

Code: Select all

  S1.Add( 2 , 'Monday', clTeeColor);
  S1.Add( 4 , 'Tuesday', clTeeColor);
  S1.Add( 0 , 'Wednesday', clTeeColor);
  S1.Add( 5 , 'Thursday', clTeeColor);

  S2.Add( 3 , 'Monday', clTeeColor);
  S2.Add( 4 , 'Tuesday', clTeeColor);
  S2.AddNull();
  S2.Add( 1 , 'Thursday', clTeeColor);

  S3.Add( 1 , 'Monday', clTeeColor);
  S3.AddNull();
  S3.AddNull();
  S3.Add( 1 , 'Thursday', clTeeColor);
I hope this clarifies how it works. Otherwise please let us know.

Re: Understanding bars and series

Posted: Tue Dec 05, 2023 5:57 pm
by 16895550
Hi Yeray

I've got that working now thanks.
Just one thing. I won't know how many series I will need each time as it depends on the data, Jobtypes in my case.

Is there a way to assign a Series on the fly ?

At the moment, I still need to do if Jobtype = 'Collect' then S1. createseries etc. and S1.Add

But it would be better if it just added the next one along, whatever its called. S1, S2 etc.

Thansk
Andy

Re: Understanding bars and series

Posted: Mon Dec 11, 2023 11:50 am
by yeray
Hello Andy,

To do it automatically, you'll need to create a series for each of the "jobs" you have, and then you can loop the "weekDays" you want to track and search in your data structure and your series and add the value for matching that weekDay, or a zero if none.

I created a simple example with a couple of dirty records to emulate your data structure. This part should be accommodated to your datasource.
Then, I'm creating the series and looping the weekDays as indicated above.

Code: Select all

uses Chart, Series, TeEngine;

var Chart1: TChart;

type TJobValue = record
  Value: double;
  WeekDay: string;
end;

type TJob = record
  Title: string;
  Values: array of TJobValue;
end;

var jobs: array of TJob;

const weekDays: array[0..3] of string = ('Monday', 'Tuesday', 'Wednesday', 'Thursday');

procedure TForm1.FormCreate(Sender: TObject);

  function GetValueFromJob(job: TJob; AWeekDay: string): TChartValue;
  var i: Integer;
  begin
    Result:=0;
    for i:=0 to High(job.Values) do
      if job.Values[i].WeekDay=AWeekDay then
      begin
        Result:=job.Values[i].Value;
        Exit;
      end;
  end;

var i, j: Integer;
    sJOBTYPE: string;
begin
  SetLength(jobs, 3);
  with jobs[0] do
  begin
    Title:='Deliver';
    SetLength(Values, 4);
    Values[0].WeekDay:=weekDays[0];
    Values[0].Value:=2;
    Values[1].WeekDay:=weekDays[1];
    Values[1].Value:=4;
    Values[2].WeekDay:=weekDays[2];
    Values[2].Value:=0;
    Values[3].WeekDay:=weekDays[3];
    Values[3].Value:=5;
  end;

  with jobs[1] do
  begin
    Title:='Collect';
    SetLength(Values, 3);
    Values[0].WeekDay:=weekDays[0];
    Values[0].Value:=3;
    Values[1].WeekDay:=weekDays[1];
    Values[1].Value:=4;
    Values[2].WeekDay:=weekDays[3];
    Values[2].Value:=1;
  end;

  with jobs[2] do
  begin
    Title:='Exchange';
    SetLength(Values, 2);
    Values[0].WeekDay:=weekDays[0];
    Values[0].Value:=1;
    Values[1].WeekDay:=weekDays[3];
    Values[1].Value:=1;
  end;

  // Create Chart
  Chart1:=TChart.Create(Self);

  with Chart1 do
  begin
    Parent:=Self;
    Align:=alClient;
    Color:=clWhite;
    Gradient.Visible:=False;
    Walls.Back.Color:=clWhite;
    Walls.Back.Gradient.Visible:=False;
    Axes.Bottom.LabelsAngle:=90;
    Axes.Left.Increment:=1;
  end;

  // Create a series for each "job"
  for j:=0 to High(jobs) do
  begin
    with TBarSeries(Chart1.AddSeries(TBarSeries)) do
    begin
      Title := jobs[j].Title;
      MultiBar := mbStacked;
      Marks.Visible := False;
      Marks.Style := smsValue;
    end;
  end;

  // Populate series
  for i:=0 to High(weekDays) do
  begin
    for j:=0 to High(jobs) do
      Chart1[j].Add(GetValueFromJob(jobs[j], weekDays[i]), weekDays[i]);
  end;
end;
And this is what I get with the example above:
jobs.png
jobs.png (13.73 KiB) Viewed 25164 times