Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..[gelöst]
- 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]
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
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 ?
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
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
Just try it
Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..
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.
- 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 ..
Recht hast du ich hab folgendes im OnCreate gemacht:
Wie man sehen kann sind die Achsen nun Korrekt Scalliert, aber das Rendern hat es nun zerwürfelt, ...
Ich vermute mal dass man dann in
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.
Code: Alles auswählen
ENBWPowerSeries.AxisIndexY := 0;
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;
--
Just try it
Just try it
Re: Dual y-Achse mit TChart und TUserDrawnSeries scheint nicht zu funktionieren ..
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.
- 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 ..
OK Danke, und hier ist was du geschrieben hast als "Quellcode"
Das obige Rendert einfach die Kurve und malt sie dann auch Korrekt wie man das erwartet (y)

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;
--
Just try it
Just try it
- 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 ..
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: und hier der Code dazu
@wp_xyz Danke, ich hoffe du kommst zur Lazarus Konferenz oder mal zum Stuttgarter Lazarustreffen, dann gebe ich dir mal nen Kaffee aus.

Hier das Ergebnis: 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;
--
Just try it
Just try it