TChart: Achsen zwischen linear und logarithmisch umschalten

Rund um die LCL und andere Komponenten
Antworten
Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Hallo Forum,

ich nutze ein TChart
, um Datenpunkte, die aus einem File eingelesen und in eine LineSeries gepackt werden. Die kann ich auch auf einem TChart darstellen - das tut soweit, zumindest rudimentär.

Ich würde jetzt gerne für beide Achsen eine CheckBox einbauen, mit der ich zwischen linearer und logarithmischer Darstellung umschalten kann. Wenn ich das richtig verstanden habe, muss ich eine ChartAxisTransformation definieren, die dann entweder linear (Faktor sollte dann 1 sein) und logarithmisch sein (Info aus https://wiki.lazarus.freepascal.org/TAC ... s,_Fitting).

Kann ich beide parallel definieren und dann zwischen beiden umschalten? Das ist dann jeweils für x- und y-Achse getrennt möglich?

Oder muss ich im Prinzip für jede der 4 Möglichkeiten ein getrenntes Chart anlegen und zwischen denen umschalten? :shock:

Vielleicht ist hier ja jemand, der ein paar Tipps hat.

Danke,
Photor

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

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von wp_xyz »

Für eine Achse habe ich dir ein Beispiel angehängt, die zweite Achse kannst du zur Übung selbst nachbauen. Du brauchst für jede Achse eine ChartAxisTransformations-Komponente, für die du jeweilse eine logarithmische Transformation erzeugst. Das Umschalten linear-logarithmisch geht mit Hilfe der Eigenschaft Enabled der logarithmischen Transformation. Damit in beiden Fällen aber eine "schöne" Achsenbeschriftung verwendet wird, muss man noch eine paar Parameter der Intervals-Property der zugehörigen Achsen anpassen. Je nach Größe des Chart evtl. zu ändern.
Dateianhänge
Logarithmisch.zip
(2.45 KiB) 18-mal heruntergeladen

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Hallo wp_xyz,

Danke für die prompte Antwort. Ich schau mir das (hoffentlich heute noch) in Ruhe genauer an. Nach Deiner Beschreibung hört es sich weniger kompliziert an als ich dachte. Dass da noch jede Menge an Aufhübschungsarbeiten zu erledigen sind, ist klar. Soweit ist mein Programm aber eh noch nicht. Erstmal muss das Prinzip funktionieren.

Ciao,
Photor

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Moin,

so Hausaufgabe erledigt. Fazit: tut für beide Achsen getrennt; man braucht tatsächlich 2 einzelne Transformations - für jede Achse getrennt.

Muss das nun in mein Programm einbauen; teilweise ist das schon geschehen; die Achsenbeschriftung passt noch überhaupt nicht. Dafür muss ich mir die Bedeutung der Parameter mal genau ansehen.

Ciao,
Photor

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

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von wp_xyz »

photor hat geschrieben:
Mo 15. Feb 2021, 19:42
Dafür muss ich mir die Bedeutung der Parameter mal genau ansehen.
Die Achsenbeschriftung spielt sich hier in der Property "Intervals" der Achse ab.

Um die Option "aipGraphCoords" zu verstehen, musst du wissen, dass TAChart mehrere Koordinatensystem verwendet. Zunächst das Koordinatensystem der direkten Eingabedaten, also der Werte vor dem Logarithmieren --> Achsen-Koordinaten, weil das die Zahlen sind, die an der Achse stehen. Dann das Koordinatensystem der logarithmierten Werte --> Graph-Koordinaten, weil das die Einheiten sind, in denen gezeichnet wird. Und die Bildschirmkoordinaten nach Umrechnung der Graph-Koordinaten --> Image-Koordinaten. Nimmt man nun die Option aipGraphCoordinates zu den Interval.Options hinzu, dann versucht die Beschriftungsroutine "schöne" Werte für die logarithmierten Werte zu finden, also z.B. -1, 0, 1, 2 - die Achse wird dann aber mit 10^-1=0.1, 10^0 = 1, 10^1 = 10 und 10^2 =100 beschriftet.

Intervals.MaxLength ist der maximale Abstand der Ticks (in Pixeln). In der Regel sind die Ticks eines Log-Plots weiter voneinander entfernt als die Ticks eines Lin-Plots (weil sie im Idealfall ganze Dekaden überdecken). Daher muss man MaxLength für die Log-Achse vergrößern, sonst ist der Algorithmus gezwungen einen Zwischenwert zu suchen bevor die nächste Dekade erreicht wird.

Intervals.MinLength wäre entsprechend der minimale Abstand zwischen Ticks, auch hiermit kannst du beeinflussen, welche Werte als Labels gefunden werden

Intervals.Tolerance erlaubt, dem Algorithmus um maximal soviele Pixel von einem gefundenen Label abzuweichen, um "schönere" Werte zu finden, wenn die anderen Parameter das nicht zulassen würden. Alexander S.Klenin, der das alles geschrieben hat, meinte, in vielen Fällen wären ein paar Pixel ausreichend. Ich habe jedoch gesehen, dass man für eine logarithmische Achse die Tolerance sehr groß machen muss (über 100), sonst kommen zuviele krumme Werte rein, statt die vollen Dekaden.

Das ganze ist sehr kompliziert ausgefallen, und hat man eine schöne Beschriftung gefunden, so können doch wieder Zwischenwerte auftauchen, wenn man die Größe des Chart verändert.

Wenn du nur Ticks an den vollen Dekaden haben willst (0.001, 0.01, 0.1, 1, 10, 100, 1000 usw.) dann solltest du eine TListChartSource aufs Formular klicken. Im Property DataPoints schreibst du in die X und Y Spalte die gewünschten Werte. Die ListChartSource verbindest du dann mit Marks.Source der betreffenden Achse. Das sieht schick aus, hat aber ein Problem, wenn der User in den Chart hineinzoomt und plötzlich keine Markierungen mehr sieht...

Das ganze ist nicht trivial...

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Da ke für die ausführliche Erklärung. Ich habe heute einiges versucht (mit Hilfe der Doku im Wiki) und bin nicht weiter gekommen - es ist nicht trivial.

Ich setze mich morgen nochmal mit Deiner Erklärung auseinander und probiere es noch mal. Irgendwie werde ich eine brauchbare (und ich hoffe, robuste) Einstellung finden.

Danke,
Photor

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

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von wp_xyz »

Was ist denn genau deine Anforderung? Poste ein kleines Demoprogramm, so dass ich deine Probleme sehen kann. Es reicht ein Formulat mit einem Chart in ähnlicher Größe wie in deinem endgültigen Programm, sowie irgendwelche Dummy-Daten, die den Bereich abdecken, den du für deine echten Daten erwartest.

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Hallo wp_xyz,

ich habe da mal was vorbereitet (vielleicht erkennst du ja einiges wieder). Typische Daten habe ich eingefügt; die sollen aus einer Datei eingelesen werden - hier fest im Source-Code. Es kann also durchaus sein, dass sich der Wertebereich für x- und y-Achse ändert.

Das Chart hat etwa die Größe (in Pixeln), wie bisher in meinem Programm (das mag sich vielleicht noch ändern). Das verrückte ist, dass ich in dem Beispiel hier wenigsten eine Achsenbeschriftung/-einteilung erhalte, wenn auch nicht schön. Das liegt am Format der Achsenbeschriftung.

In meinem Programm erhalte ich im Log-Fall überhaupt keine. Meine Vermutung: ich stelle Min und Max fest und setze die explizit mit z.B. CollectiveChart.Extent.XMin := CyclesMin;

Vielleicht hast du ja einen Tipp. Ich werde in jedem Fall weiter probieren.

Ciao,
Photor
Dateianhänge
LogAxis_Photor.zip
(5.4 KiB) 12-mal heruntergeladen

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

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von wp_xyz »

Ich habe nun etwas mit dem Programm herumgespielt. Eigentlich muss man nur die Tick-Abstände (Axis.Intervals.MaxLength) größer machen, vor allem auf der x-Achse. Wegen der langen Zahlen vor allem auf der x-Achse habe ich das Beschriftungsformat auf %.0n umgestellt, also mit Tausender-Trenner. (Eine Alternative wäre auch das Exponential-Format mit %.0e').

Des weiteren habe ich alternativ für die log-Achsen eine fest verdrahtetet Beschriftung in ganzen Dekaden eingebaut; die Dekadenwerte werden in der ListChartSource1 von 10^-20 bis 10^20 berechnet und sowohl für x als auch für y gespeichert. Da hier die Beschriftungswerte fest vorgegeben sind, kann man auch ein Untergitter einziehen, so dass man auch die Zwischenwerte sieht. Das geht über die "Minors" einer Achse. Es sind 9 Zwischenmarkierungen pro Achseintervall, also pro Dekade vorgegeben. Das sieht recht schick aus, allerdings verschwindet die Achsenmarkierung, wenn deine User stark ins Diagramm reinzoomen - evtl kannst du da auf die automatische Beschriftung zurückschalten - was man dafür ändern muss findest du im Beispiel.

Eine Unschönheit gibt es noch: du hast an der x-Achse ganz schön große Zahlen. Es werden in TAChart immer wieder Float-Zahlen verglichen, und dafür ist irgendwo ein Epsilon von sowas wie 10^-9 definiert. Die letzte Stelle deiner x-Achsenbeschriftung hat liegt damit genau im Bereich dieser Genauigkeit. Darauf führe ich zurück, dass auf der x-Achse manchmal der 2. Beschriftungswert verschwindet. Damit das Demo-Programm nicht gleich mit einem Fehler ins Haus kommt, habe ich kurzerhand deine y-Werte durch 1000 dividiert - damit funktioniert alles. Du solltest dir überlegen, ob du nicht durch Umstellen auf eine andere Einheit die Zahlen in den "üblichen" Bereich transformieren kannst.
In meinem Programm erhalte ich im Log-Fall überhaupt keine. Meine Vermutung: ich stelle Min und Max fest und setze die explizit mit z.B. CollectiveChart.Extent.XMin := CyclesMin;
Wenn du über Chart.Extent den Bereich einer Achse einschränkst musst, du beachten, dass die Min/Max-Werte in Graph-Einheiten zu nehmen sind, denn ein Chart kann mehrere x-Achsen haben und daher nicht "wissen", welche Transformation anzuwenden ist. Konkret heißt das: Wenn du die Achsenbereich zwischen 10 bis 10.000 fest vorgeben willst, dann musst du im Extent.XMin 1 (=log(10) und im Extent.XMax 4 = log(10.000) eintragen. Das musst du natürlich wieder rückgängig machen, wenn die Achse auf linear zurückgeschaltet wird.

Und eins noch: Dein Datensatz enthält als ersten x-Wert den Wert 0 -- der Logarithmus von 0 ist nicht definiert! TAChart irgnoriert das, kommt aber irgendwie aus dem Tritt und wählt den 1.Tick zu spät, so dass die ersten Punkte unterschlagen werden. Das sollte eigentlich nicht sein - es sollte der nächste gültige Datenwert das Achsenminimum bestimmen; das muss ich mir demnächst mal näher ansehen. Der beigefügte Screenshot ist entstanden nach dem Löschen des 1. Datenpunkts (dem mit x=0).
Dateianhänge
logaxis_photor.png
logaxis_photor.png (20.82 KiB) 391 mal betrachtet
LogAxis_Photor_wp.zip
(4.24 KiB) 15-mal heruntergeladen
Zuletzt geändert von wp_xyz am Mi 17. Feb 2021, 22:30, insgesamt 1-mal geändert.

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Vielen Dank wp_xyz,

ich werde das so einbauen. Das sieht schon deutlich übersichtlicher aus als das, was ich bisher zusammen gebracht habe. 8)

Aber du hattest Recht: das Thema ist nicht trivial.

Ciao,
Photor

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Moin,

habe mir deine Sourcen gerade angesehen und compiliert. Mit der 10-er Teilung kann ich leben. D.h. ich baue die ListChartSource als Quelle für die Achsenbeschriftung in mein Programm ein (ohne Hilfestellung hätte das noch Wochen, Monate oder Jahre gedauert, bis ich das hinbekommen hätte).

Beim Compilieren des Testprogramms erhalte ich folgendes:

Code: Alles auswählen

unit1.pas(179,17) Note: Call to subroutine "function TChartAxis.GetMarks:TChartAxisMarks;" marked as inline is not inlined
Die bezieht sich auf diese Zeile im Code:

Code: Alles auswählen

Axis.Marks.Source := ListChartSource1;
Es ist nur eine Note - also nur ein Schönheitsfehler?

Ciao,
Photor

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

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von wp_xyz »

Kein Schönheitsfehler, aber FPC ist seit v3.2 besonders pingelig und meldet vieles, was früher "durchging". Du kannst entweder im Nachrichtenfenster auf der Zeile mit dieser Meldung rechts-klicken und die passende Option wählen um die Meldung zu ignorieren - ich weiß gerade den Wortlaut nicht, aber du verstehst die Optionen sicher. Oder du gehst in die Projekt-Optionen, Seite Meldungen und wähltst die entsprechende Meldung ab. Um diese zu finden, würde ich in der Filterzeile einen Teil des Meldungstextes eintippen (z.B. "inline"), und dann findet man sie gleich in der kleinen Menge der übrig gebliebenen Meldungstexte.

Benutzeravatar
photor
Beiträge: 254
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.10 FPC 3.2.0)
CPU-Target: 64Bit

Re: TChart: Achsen zwischen linear und logarithmisch umschalten

Beitrag von photor »

Solange es nicht mehr Meldungen sind, stört mich das nicht soooo sehr. Die waren nur und wunderten mich.

Ciao,
Photor

Antworten