Understanding bars and series

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
andydyble
Newbie
Newbie
Posts: 8
Joined: Fri Mar 31, 2023 12:00 am

Understanding bars and series

Post by andydyble » Wed Nov 22, 2023 3:12 pm

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

andydyble
Newbie
Newbie
Posts: 8
Joined: Fri Mar 31, 2023 12:00 am

Re: Understanding bars and series

Post by andydyble » Wed Nov 22, 2023 3:17 pm

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

Yeray
Site Admin
Site Admin
Posts: 9622
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Understanding bars and series

Post by Yeray » Thu Nov 23, 2023 10:13 am

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;
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

andydyble
Newbie
Newbie
Posts: 8
Joined: Fri Mar 31, 2023 12:00 am

Re: Understanding bars and series

Post by andydyble » Thu Nov 23, 2023 3:42 pm

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

andydyble
Newbie
Newbie
Posts: 8
Joined: Fri Mar 31, 2023 12:00 am

Re: Understanding bars and series

Post by andydyble » Thu Nov 23, 2023 3:51 pm

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 28265 times
Thanks

Andy

andydyble
Newbie
Newbie
Posts: 8
Joined: Fri Mar 31, 2023 12:00 am

Re: Understanding bars and series

Post by andydyble » Thu Nov 23, 2023 6:15 pm

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 28260 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);

Yeray
Site Admin
Site Admin
Posts: 9622
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Understanding bars and series

Post by Yeray » Mon Nov 27, 2023 12:34 pm

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.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

andydyble
Newbie
Newbie
Posts: 8
Joined: Fri Mar 31, 2023 12:00 am

Re: Understanding bars and series

Post by andydyble » Tue Dec 05, 2023 5:57 pm

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

Yeray
Site Admin
Site Admin
Posts: 9622
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Understanding bars and series

Post by Yeray » Mon Dec 11, 2023 11:50 am

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 27358 times
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Post Reply