Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..[gelöst]

Rund um die LCL und andere Komponenten
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1452
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..[gelöst]

Beitrag von corpsman »

Hallo zusammen,
Ich habe noch ein Thema mit TAChart

Ich habe 2 Kurven in einem TaChart
die 1. im Bereich 1000 .. -4000 und die zweite im Bereich 0 .. 100. Klar dass beide eine eigene Transformation brauchen sonst ist die 2. immer eine Waagrechte Linie.

Mache ich das mit TLineSeries und der Erklärung von ( https://wiki.freepascal.org/TAChart_Tut ... is,_Legend ) funktioniert das auch wunderbar.
Mein Problem ist nun das die 2. Kurve eine TUserDrawnSeries ist und da kann man die eigentschaft "AxisIndexY" nicht setzen (Kann auch sein, dass es daran nicht liegt, das ist nur ne Vermutung).

Ich hab euch mal ein Demo mit angehängt in dem ich das Problem zeige
Beispiel.PNG
Beispiel.PNG (78.05 KiB) 889 mal betrachtet

In der Demo sieht man Oben wie es nicht geht und unten dass es mit TLineSeries geht.

Weiß jemand wie ich das im Oberen Beispiel auch hin bekomme ?
Dateianhänge
Chart_Test.zip
(3.61 KiB) 41-mal heruntergeladen
Zuletzt geändert von corpsman am Mi 19. Jul 2023, 17:05, insgesamt 1-mal geändert.
--
Just try it

wp_xyz
Beiträge: 4781
Registriert: Fr 8. Apr 2011, 09:01

Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..

Beitrag von wp_xyz »

corpsman hat geschrieben:
Mi 19. Jul 2023, 08:51
Mein Problem ist nun das die 2. Kurve eine TUserDrawnSeries ist und da kann man die eigentschaft "AxisIndexY" nicht setzen
TUserDrawnSeries stammt von TCustomSeries ab und dort werden die Properties AxisIndexX und AxisIndexY eingeführt, aber nur public. Daher solltest du sehr wohl AxisIndexX und AxisIndexY verwenden können, aber halt nicht im Object-Inspector sondern nur zur Laufzeit.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1452
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..

Beitrag von corpsman »

Recht hast du ich hab folgendes im OnCreate gemacht:

Code: Alles auswählen

  ENBWPowerSeries.AxisIndexY := 0;
Wie man sehen kann sind die Achsen nun Korrekt Scalliert, aber das Rendern hat es nun zerwürfelt, ...
Beispiel_neu.PNG
Beispiel_neu.PNG (81.32 KiB) 867 mal betrachtet
Ich vermute mal dass man dann in

Code: Alles auswählen

Procedure TForm1.ENBWPowerSeriesDraw(ACanvas: TCanvas; Const ARect: TRect);
  Function GetColor(y, yref: Double): TColor;
  Begin
    If y > yref Then
      Result := COLOR_BELOW
    Else
      Result := COLOR_ABOVE;
  End;

Var
  i: Integer;
  gp: TDoublePoint;
  p1, p2, p3: TDoublePoint;
  yref: Integer;
Begin
  If Not assigned(data) Then exit;
  Chart1.Drawer.Pen := Pen;
  yref := Chart1.YGraphToImage(0);
  gp := DoublePoint(Data[0].X, Data[0].Y);
  p1 := DoublePoint(Chart1.GraphToImage(gp));
  For i := 1 To High(Data) Do Begin
    gp := DoublePoint(Data[i].X, Data[i].Y);
    p2 := DoublePoint(Chart1.GraphToImage(gp));
    If (p2.y - yref) * (p1.y - yref) <= 0 Then Begin
      p3 := DoublePoint(Intersect(p1, p2, yref), yref);
      Chart1.Drawer.SetPenParams(psSolid, GetColor(p1.y, yref), 2);
      Chart1.Drawer.Line(ToPoint(p1), ToPoint(p3));
      Chart1.Drawer.SetPenParams(psSolid, GetColor(p2.y, yref), 2);
      Chart1.Drawer.Line(ToPoint(p3), ToPoint(p2));
    End
    Else Begin
      Chart1.Drawer.SetPenParams(psSolid, GetColor(p2.y, yref), 2);
      Chart1.Drawer.Line(ToPoint(p1), ToPoint(p2));
    End;
    p1 := p2;
  End;
End; 
die YGraphToImage calls auch auf die Transformation umbiegen muss, oder ? Denn wie man im Screenshot sehen kann bezieht sich das nun auf die 2. Achse und nicht auf die 1.
--
Just try it

wp_xyz
Beiträge: 4781
Registriert: Fr 8. Apr 2011, 09:01

Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..

Beitrag von wp_xyz »

corpsman hat geschrieben:
Mi 19. Jul 2023, 12:36
Ich vermute mal dass man dann in [...] die YGraphToImage calls auch auf die Transformation umbiegen muss, oder ?
Genau. Es gibt drei Koordinatensystem in TAChart:
- Image-Koordinaten = die Pixel auf dem Bildschirm
- Graph-Koordinaten = die linearen Float-Koordinaten, mit denen der Chart intern rechnet, sowas wie die Millimeter auf dem Millimeter-Papier
- Axis-Koordinaten = die Zahlen, die du geplottet haben willst und die an den Achsen stehen.

Die Transformation zwischen Image- und Graph-Koordianten macht der Chart mit GraphToImage u.ä. Und die Transformation zwischen Axis und Graph mach die Series, denn jede Series kann ja eine eigene Transformation haben: AxisToGraph, AxisToGraphX, AxisToGraphY bzw umgekehrt GraphToAxis usw. Wenn keine Transformation verwendet wird, so wird intern die Identitäts-Transformation verwendet, also AxisToGraphX(X) = X.

Um in deinem code also den Pixel-Ort von Data[ i] zu berechnen, muss du also zuerst Data[ i] (Axis-Koordinaten) in die Graph-Koordinaten überführen (ENBWPowerSeries.AxisToGraph(Data[ i])) und dieses Ergebnis dann mit Chart.GraphToImage(...) in Bildschirm-Koordinaten.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1452
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..

Beitrag von corpsman »

OK Danke, und hier ist was du geschrieben hast als "Quellcode" :)

Code: Alles auswählen

Procedure TForm1.ENBWPowerSeriesDraw(ACanvas: TCanvas; Const ARect: TRect);
Var
  i: Integer;
  p1, p2 : TDoublePoint;
  ip1, ip2: TPoint;
Begin
  If Not assigned(data) Then exit;
  Chart1.Drawer.Pen := Pen;

  For i := 1 To high(data) Do Begin
    p1 := ENBWPowerSeries.AxisToGraph(Data[i - 1]);
    p2 := ENBWPowerSeries.AxisToGraph(Data[i]);
    ip1 := Chart1.GraphToImage(p1);
    ip2 := Chart1.GraphToImage(p2);
    Chart1.Drawer.SetPenParams(psSolid, clred, 2);
    Chart1.Drawer.Line(ip1, ip2);
  End;     
Das obige Rendert einfach die Kurve und malt sie dann auch Korrekt wie man das erwartet (y)
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1452
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..

Beitrag von corpsman »

So und der Vollständigkeithalber für alle die wissen wollen wie es fertig aussieht habe ich den Zeichenalgorithmus nun auch mal ordentlich gemacht ;)

Hier das Ergebnis:
Beispiel_funktioniert.png
Beispiel_funktioniert.png (102.15 KiB) 840 mal betrachtet
und hier der Code dazu

Code: Alles auswählen


Procedure TForm1.ENBWPowerSeriesDraw(ACanvas: TCanvas; Const ARect: TRect);
  Function GetColor(y: Double): TColor;
  Begin
    If y > 0 Then
      Result := COLOR_BELOW
    Else
      Result := COLOR_ABOVE;
  End;

Var
  i: Integer;
  p1, p2, p, p3: TDoublePoint;
  ip1, ip2, ip3: TPoint;
Begin
  If Not assigned(data) Then exit;
  Chart1.Drawer.Pen := Pen;

  For i := 1 To high(data) Do Begin
    p1 := ENBWPowerSeries.AxisToGraph(Data[i - 1]);
    p2 := ENBWPowerSeries.AxisToGraph(Data[i]);
    ip1 := Chart1.GraphToImage(p1);
    ip2 := Chart1.GraphToImage(p2);

    If (data[i - 1].Y < 0) Xor (data[i].Y < 0) Then Begin
      p := DoublePoint(Intersect(data[i - 1], data[i], 0), 0);
      p3 := ENBWPowerSeries.AxisToGraph(p);
      ip3 := Chart1.GraphToImage(p3);
      Chart1.Drawer.SetPenParams(psSolid, GetColor(Data[i - 1].y), 2);
      Chart1.Drawer.Line(ip1, ip3);
      Chart1.Drawer.SetPenParams(psSolid, GetColor(Data[i].y), 2);
      Chart1.Drawer.Line(ip3, ip2);
    End
    Else Begin
      Chart1.Drawer.SetPenParams(psSolid, GetColor(Data[i - 1].y), 2);
      Chart1.Drawer.Line(ip1, ip2);
    End;
  End;
End; 
@wp_xyz Danke, ich hoffe du kommst zur Lazarus Konferenz oder mal zum Stuttgarter Lazarustreffen, dann gebe ich dir mal nen Kaffee aus.
--
Just try it

Antworten