TChart Line Chart Series with DrawStyle Curve Dips Below Zero - How to Fix?

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
Cortech
Newbie
Newbie
Posts: 2
Joined: Wed Oct 05, 2022 12:00 am

TChart Line Chart Series with DrawStyle Curve Dips Below Zero - How to Fix?

Post by Cortech » Wed Sep 06, 2023 6:24 am

I am facing an issue with the Line chart series of TChart when using the DrawStyle Curve. The line is going below 0, even though none of the values are below zero (please refer to the attached image). I am looking for a solution to prevent the line from dipping below zero and maintain the curve style. Any help would be greatly appreciated, and thank you in advance for your responses.
Attachments
chart.jpg
chart.jpg (39.93 KiB) Viewed 12725 times

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

Re: TChart Line Chart Series with DrawStyle Curve Dips Below Zero - How to Fix?

Post by Yeray » Wed Sep 06, 2023 9:41 am

Hello,

I'd say this is something to expect if you want the curve to pass through the points.
If you don't need the curve to pass though the points, you can use a TSmoothingFunction with Interpolate:=false as follows:

Code: Select all

uses Chart, Series, TeeSpline;

var Chart1: TChart;

procedure TForm1.FormCreate(Sender: TObject);
begin
  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;
    Legend.Hide;
    View3D:=False;

    Axes.Left.SetMinMax(-1, 4);
    Axes.Left.Increment:=1;
    Axes.Bottom.Grid.Hide;
  end;

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
  begin
    Pointer.Show;
    Pointer.Size:=2;
    DrawStyle:=dsCurve;

    Add(0);
    Add(0);
    Add(3);
    Add(0);
    Add(0);
    Add(2);
    Add(2);
    Add(0);
    Add(1);
    Add(0);
    Add(0);
  end;

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
  begin
    FunctionType:=TSmoothingFunction.Create(Self);
    with TSmoothingFunction(FunctionType) do
    begin
      Interpolate:=False;
      Factor:=6;
    end;
    DataSource:=Chart1[0];
  end;
end;
curvedLine.png
curvedLine.png (17.79 KiB) Viewed 12703 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

Cortech
Newbie
Newbie
Posts: 2
Joined: Wed Oct 05, 2022 12:00 am

Re: TChart Line Chart Series with DrawStyle Curve Dips Below Zero - How to Fix?

Post by Cortech » Tue Sep 12, 2023 9:06 am

Thank you so much for the response.
Please note, that I am expecting the curve to pass through the points because it will affect the presented information.

Thank you
V

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

Re: TChart Line Chart Series with DrawStyle Curve Dips Below Zero - How to Fix?

Post by Yeray » Tue Sep 12, 2023 10:22 am

Hello,

I've tried with a custom cubic spline, but it doesn't give the result I'd expect:
Project3_2023-09-12_12-21-08.png
Project3_2023-09-12_12-21-08.png (10.15 KiB) Viewed 12570 times

Code: Select all

uses Chart, Series;

var Chart1: TChart;

type TCoeficient = record
    X, Y, b, c, d: Double;
  end;

type TCoeficients = array of TCoeficient;
type TPoints = array of TPointFloat;

procedure CalculateCubicSplineCoefficients(const Points: TPoints; var Coefficients: TCoeficients);
var
  N, i: Integer;
  h: array of Double;
  alpha, l, mu, z: array of Double;
  c, b, d: array of Double;
begin
  N := Length(Points) - 1;

  SetLength(h, N);
  SetLength(alpha, N);
  SetLength(l, N);
  SetLength(mu, N);
  SetLength(z, N);
  SetLength(c, N);
  SetLength(b, N);
  SetLength(d, N);

  // Calculate h values
  for i := 0 to N - 1 do
    h[i] := Points[i + 1].X - Points[i].X;

  // Calculate alpha, l, mu, and z values
  for i := 1 to N - 1 do
  begin
    alpha[i] := (3.0 / h[i]) * (Points[i + 1].Y - Points[i].Y) - (3.0 / h[i - 1]) * (Points[i].Y - Points[i - 1].Y);
    l[i] := 2.0 * (Points[i + 1].X - Points[i - 1].X) - h[i - 1] * mu[i - 1];
    mu[i] := h[i] / l[i];
    z[i] := (alpha[i] - h[i - 1] * z[i - 1]) / l[i];
  end;

  // Calculate c, b, and d values
  for i := N - 1 downto 0 do
  begin
    c[i] := z[i] - mu[i] * c[i + 1];
    b[i] := (Points[i + 1].Y - Points[i].Y) / h[i] - h[i] * (c[i + 1] + 2.0 * c[i]) / 3.0;
    d[i] := (c[i + 1] - c[i]) / (3.0 * h[i]);
  end;

  // Store the coefficients
  SetLength(Coefficients, N);
  for i := 0 to N - 1 do
  begin
    Coefficients[i].X := Points[i].X;
    Coefficients[i].Y := Points[i].Y;
    Coefficients[i].c := c[i];
    Coefficients[i].b := b[i];
    Coefficients[i].d := d[i];
  end;
end;

procedure GenerateSmoothCurve(const Coefficients: TCoeficients; var SmoothCurve: TPoints);
var
  i, j: Integer;
  t: Double;
begin
  // Calculate the smooth points along the curve
  SetLength(SmoothCurve, 0);
  for i := 0 to High(Coefficients) - 1 do
  begin
    for j := 0 to 100 do // 100 points between each pair of input points
    begin
      t := j / 100;
      SetLength(SmoothCurve, Length(SmoothCurve) + 1);
      SmoothCurve[High(SmoothCurve)].X := Coefficients[i].X + t * (Coefficients[i + 1].X - Coefficients[i].X);
      SmoothCurve[High(SmoothCurve)].Y :=
        Coefficients[i].Y + t * (Coefficients[i + 1].Y + t * (Coefficients[i + 1].b + t * Coefficients[i + 1].c)) + t * t *
        (Coefficients[i + 1].d);
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
    data: TPoints;
    coeficients: TCoeficients;
begin
  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;
    Legend.Hide;
    View3D:=False;

    Axes.Left.SetMinMax(-1, 4);
    Axes.Left.Increment:=1;
    Axes.Bottom.Grid.Hide;
  end;

  with TPointSeries(Chart1.AddSeries(TPointSeries)) do
  begin
    Pointer.Size:=2;

    Add(0);
    Add(0);
    Add(3);
    Add(0);
    Add(0);
    Add(2);
    Add(2);
    Add(0);
    Add(1);
    Add(0);
    Add(0);
  end;

  // Calculate cubic spline
  SetLength(data, Chart1[0].Count);
  for i:=0 to Chart1[0].Count-1 do
  begin
    data[i].X:=Chart1[0].XValue[i];
    data[i].Y:=Chart1[0].YValue[i];
  end;

  CalculateCubicSplineCoefficients(data, coeficients);
  GenerateSmoothCurve(coeficients, data);

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
    for i:=0 to High(data) do
      AddXY(data[i].x, data[i].y);
end;
You could try to modify that algorithm or implement your own.
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