TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Rund um die LCL und andere Komponenten
Antworten
Rob
Beiträge: 34
Registriert: Fr 8. Jul 2011, 10:45
OS, Lazarus, FPC: Win7, Ubuntu 64 und 32bit Lazarus (immer aktuellstes Release) FPC 2.6.4
CPU-Target: amd_64 und i386
Kontaktdaten:

TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von Rob »

Hallo,

ich schon wieder mit TAChart...
Ich versuche gerade die Breite einer Achsenbeschriftung festzulegen.

Wann immer ich einen Chart mit neuen Daten befülle wird die Linie der Y Achse an eine andere Position gesetzt, da sich die Breite der Y-Achsenbeschriftung ändert. Soweit klar, aber ich will/muss dies fixieren. Ich habe schon mit LeftAxis - Marks Distance und Margin, sowie mit vielen anderen Properties rumgespielt, aber keine Erfolg erzielt.
Die Breite der Achsenbeschriftung wird immer neu zu allen Abständen hinzuaddiert, das führt dazu das die Linie der Y Achsen(n) immer neu positioniert wird.
Schön wäre es wenn ich z.b. eingebe Margin=30 und die Linie hat diese Position und sie bleibt fix.

Grüße
Rob
Zuletzt geändert von Rob am Do 4. Dez 2014, 13:43, insgesamt 2-mal geändert.

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse selbst

Beitrag von wp_xyz »

Eine eingebaute Eigenschaft, die die Position der Achsen fixiert, gibt es nicht. Daher musst du "basteln": Die Lage der y-Achse wird durch die Höhe des y-Achsen-Titels bestimmt und durch die Länge der y-Achsen-Markierungsbeschriftungen.

(1) Stelle sicher, dass der Titel der y-Achse für alle Datensätze immer dieselbe Zahl von Zeilen ergibt. Ergänze ggfs durch Anhängen von LineEndings, dass die Zeilenanzahl immer gleich ist.

(2) Bestimme den Maximalwert, den die y-Labels auch mit verschiedenen Datensätzen haben können. Ich weiß, im allgemeinen geht das nicht, aber für die meisten Charts weiß man, dass die y-Werte maximal einen bestimmten Wert annehmen können. Berechne, wieviele Ziffern/Zeichen du für diesen Maximalwet benötigst, z.B.: Digits := Length(FloatToStr(MaxYValue)). Schreibe einen Eventhandler für das Achsen-Ereignis OnMarkToText, der den Text der Achsenlabel vorne mit Leerzeichen ergänzt, bis alle Digits belegt sind. Verwende einen Font mit konstanter Zeichenbreite für die y-Labels.

Alternativ zu (2) könntest du auch die y-Labels um 90° drehen, so dass sie horizontal immer dieselben Pixelanzahl benötigen.

Mit diesen Maßnahmen benötigen der y-Achsentitel und die y-Ticks immer gleich viel Platz (entlang der Horizontalen). Daher muss die y-Achse immer an derselben Stelle im Chart auftauchen.

Rob
Beiträge: 34
Registriert: Fr 8. Jul 2011, 10:45
OS, Lazarus, FPC: Win7, Ubuntu 64 und 32bit Lazarus (immer aktuellstes Release) FPC 2.6.4
CPU-Target: amd_64 und i386
Kontaktdaten:

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse selbst

Beitrag von Rob »

Hi,
wp_xyz hat geschrieben:Schreibe einen Eventhandler für das Achsen-Ereignis OnMarkToText, der den Text der Achsenlabel vorne mit Leerzeichen ergänzt, bis alle Digits belegt sind. Verwende einen Font mit konstanter Zeichenbreite für die y-Labels.
Das funktioniert jetzt, aber, recht langsam, das leigt aber daran das ich mittels Font und breite die des größten Labels festlege und die einzelnen Labels so lange mit Blanks auffülle bis es passt. Damit funktioniert es auch mit Fonts mit variabler Zeichenlänge.
Es schient so als würde er immer alle Labels beim Zeichnen durchgehen, und nicht nur die drei Labels die gezeichnet werden sollen.

Ich hab jetzt mal folgendens gemacht.
Neue ListChartSource
diese wird mit Werten befüllt die Ganzzahlig den gewünschten Bereich abdecken.
Diese hänge ich an Chart.LeftAxis.Marks.Source
Also wie bei der XAchse.

Und nun klappt es :-)
... zumindest sehe ich noch kein weiteres Problem.

Grüße
Rob

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

Kannst du mal eine Minimalversion des Programms hier posten, damit ich mir das wegen der Geschwindigkeit ansehen kann? Es gibt einen BeginUpdate/EndUpdate-Mechanismus der ChartSources, der das Neuzeichnen unterbindet, wobei ich aber glaube, dass das hier nicht greift. Ich befürchte, du änderst die Labels während der Paint-Routine, und dann können wir sogar froh sein, dass es keinen Stacküberlauf gibt (Paint -> Label ändern -> nochmals Paint --> wieder Label ändern --> usw).

Rob
Beiträge: 34
Registriert: Fr 8. Jul 2011, 10:45
OS, Lazarus, FPC: Win7, Ubuntu 64 und 32bit Lazarus (immer aktuellstes Release) FPC 2.6.4
CPU-Target: amd_64 und i386
Kontaktdaten:

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von Rob »

wp_xyz hat geschrieben:Kannst du mal eine Minimalversion des Programms hier posten,...
Die müsste ich erst bauen, aber ich versuche mal ein Tesprogramm zu extrahieren..

Grüße
Rob

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

Ja, wär schön. Denn ich kann mir nicht vorstellen, dass das Ergänzen von Leerzeichen bei der Achsenbeschriftung einen merkbaren Geschwindigkeitsverlust bewirkt.

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

In der Anlage ist ein kleines Demo-Projekt, das die zueinander ausgerichteten y-Achsen zweier Charts zeigt, so wie ich mir das vorgestellt habe. Es ist auch ein TChartExtentLink eingebaut, mit dem man den x-Achsenausschnitt beider Charts aneinander koppeln kann - dadurch wird, wenn man in dem einen Chart zoomt, die x-Achse des anderen nachgeführt - könnte sein, dass das die nächste Frage ist ;-)
rob hat geschrieben: das ich mittels Font und breite die des größten Labels festlege und die einzelnen Labels so lange mit Blanks auffülle bis es passt. Damit funktioniert es auch mit Fonts mit variabler Zeichenlänge.
Das kann ich mir nicht vorstellen. Durch Auffüllen mit Leerzeichen kriegst du Strings nie auf gleiche Pixellänge, wenn der Font keine feste Zeichenbreite hat.
Dateianhänge
aligned-axes.png
Chart_aligned_axes.zip
(2.53 KiB) 79-mal heruntergeladen

Rob
Beiträge: 34
Registriert: Fr 8. Jul 2011, 10:45
OS, Lazarus, FPC: Win7, Ubuntu 64 und 32bit Lazarus (immer aktuellstes Release) FPC 2.6.4
CPU-Target: amd_64 und i386
Kontaktdaten:

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von Rob »

Hi,
wp_xyz hat geschrieben:... Es ist auch ein TChartExtentLink eingebaut, ... - könnte sein, dass das die nächste Frage ist ;-)
kannst du Gedanken lesen? ;-)
Auch wenn ich das auf später verschoben habe.
rob hat geschrieben: Das kann ich mir nicht vorstellen. Durch Auffüllen mit Leerzeichen kriegst du Strings nie auf gleiche Pixellänge, wenn der Font keine feste Zeichenbreite hat.
Ich dachte auch nicht das das richtig funktioniert, aber es scheint trotzdem irgendwie zu klappen.

Grüße
Rob

Rob
Beiträge: 34
Registriert: Fr 8. Jul 2011, 10:45
OS, Lazarus, FPC: Win7, Ubuntu 64 und 32bit Lazarus (immer aktuellstes Release) FPC 2.6.4
CPU-Target: amd_64 und i386
Kontaktdaten:

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von Rob »

Hi,

so nach dem Versuch die Charts aus meinem Programm zu isolieren und mit Testdaten zu füttern ist es passiert,
die Idee die Breiten der Labels anhand des Fonts zu bestimmen und zum Vergrößern mit Leerzeichen aufzufüllen funktioniert nicht sauber.

Aber hier trotzdem kurz die Idee:
ich baue einen TLabel als Dummy, und gebe ihm den Font des Charts
Die Caption wird der Referenzwert also z.b. "999,99"

Code: Alles auswählen

 
dummyLbl := TLabel.Create(self);
dummyLbl.Parent := self;
dummyLbl.AutoSize := False;
dummyLbl.WordWrap := False;
dummyLbl.Font := AdditionalChart.LeftAxis.Marks.LabelFont;
dummyLblMaxWidth := dummyLbl.Canvas.TextWidth('999,9');
 
nun messe ich die Breite des Labels und fülle mit Leerzreichen auf bis die Referenzbreite erreicht wird.
Nun gibt es hier immer eine Unschärfe von ein paar Pixeln, ich achte darauf das der Referenzwert maximal erreicht, aber nicht überschritten wird.

Code: Alles auswählen

 
procedure TfrmMain.AdditionalChartAxisList0MarkToText(var AText: String; AMark: Double);
var
  w: integer;
  s: string;
begin
  s := AText;
  w := dummyLbl.Canvas.TextWidth(s);
  while (w < dummyLblMaxWidth) do begin
    w := dummyLbl.Canvas.TextWidth(' ' + s);
    if w <= dummyLblMaxWidth then s := ' ' + s;
  end;
  AText := s;
end;
 
Das funktioniert, bringt aber leider nicht das gewünschte Ergebnis, deshalb mache ich so nicht weiter,
ich nutze jetzt, wie von wp_xyz vorgeschlagen einen Font mit fester Zeichenbreite.
Mal sehen wie sich das so macht.

Vielleicht gibt es ja in Zukünftigen Versionen von TAChart ein property mit dem man die Breite der Marks fest einstellen oder aber die Position der Achsen selbst festlegen kann. Z.B. LeftAxis-Minimum-Offset gebe ich hier z.B. 30 ein so wird die Linie der Linken XAchse so lange an der Position gehalten, bis ein AchsenbeschriftungsWert den zur Verfügung stehenden Platz überschreitet, dann bewegt sich die Achse weiter nach rechts. Selbiges für die rechte Achse, nur umgekehrt.

Und wenn ich schon beim Wünschdirwas bin, die Methode MarkToText, wenn es mögich ist die Parameter zu erweitern dann hätte ich da gerne auch den X-AchsenWert, Das was als AMark kommt ist ja ein Wert aus der gesamten Werteliste des Grafen. Wenn ich beide Werte habe kann ich damit in mein Datenobjekt gehen und z.B. spezielle Formatierungs Methoden nutzen.

Grüße
Rob

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

Rob hat geschrieben:Vielleicht gibt es ja in Zukünftigen Versionen von TAChart ein property mit dem man die Breite der Marks fest einstellen oder aber die Position der Achsen selbst festlegen kann.
Das habe ich schon im Hinterkopf abgespeichert. Die Bestimmung der Achsenposition ist aber nicht ganz ohne, mal sehen, ob ich mich da reinfinde.
Rob hat geschrieben:die Methode MarkToText, wenn es mögich ist die Parameter zu erweitern dann hätte ich da gerne auch den X-AchsenWert.
Das verstehe ich nicht. Du willst zur Y-Achse auch den X-Wert? Was hat denn die Y-Achse mit den X-Werten zu tun?

Rob
Beiträge: 34
Registriert: Fr 8. Jul 2011, 10:45
OS, Lazarus, FPC: Win7, Ubuntu 64 und 32bit Lazarus (immer aktuellstes Release) FPC 2.6.4
CPU-Target: amd_64 und i386
Kontaktdaten:

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von Rob »

wp_xyz hat geschrieben:
Rob hat geschrieben:die Methode MarkToText, wenn es mögich ist die Parameter zu erweitern dann hätte ich da gerne auch den X-AchsenWert.
Das verstehe ich nicht. Du willst zur Y-Achse auch den X-Wert? Was hat denn die Y-Achse mit den X-Werten zu tun?
Naja, man übergibt ja immer ein Wertepärchen denn die Position eines Punktes auf dem Chart wird ja durch x und y bestimmt.
Meine Vermutung ist, dass im Hintergrund diese Zuordnung erhalten bleibt, denn der Wert auf der YAchse kommt ja eigentlich von einem Datenpärchen des Charts.
Dann könnte ich mit dem X Wert in mein Datenobjekt gehen und mir den dazupassenden YWert Sauber als String formatiert zurückgeben lassen.

Wenn aber die Y Achse einfach nur eine Liste aus Werten min-Y bis max-Y ist, die keine Zuordnung zur LineSeries im Chart haben, dann geht das natürlich nicht.
Und wenn ich das so weiter überlege hab ich schon eine Idee wie ich die Achsenbeschriftung optimieren kann ohne alle möglichen YWerte in der Achsenliste zu haben.

Hmmm, da hab ich wohl nicht weit genug überlegt, sorry!

Grüße
Rob

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

Jede Chart-Achsen kennt von den Daten nur den kleinsten und größten Wert entlang der eigenen Achsenrichtung. Insbesondere weiß die y-Achse nicht, wo alle Datenpunkte bzgl. der x-Achse liegen. Mit Hilfe des Range-Parameters der Achse (bzw. Extent des Chart) kann man diese Grenzen noch auf einen festen Wert, also unabhängig von den Series-Werten, festzurren. Dann rundet die Achse die so festgelegten Minimal- und Maximalwerte auf "schöne" Zahlen und unterteilt den Bereich dazwichen in "schöne" Intervalle. Die Intervallgrenzen ergeben jeweils einen "Mark", bei dem auch OnMarkToText aufgerufen wird.

Diesen Automatismus kann man deaktivieren, indem man der Marks.Source einer Achse eine ChartDataSource zuweist, in der die Markierungswerte explizit drin stehen müssen.

Was willst du denn genau erreichen? Ich habe das Gefühl, du packst an der falschen Stelle an.

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

rob hat geschrieben:Rob hat geschrieben:Vielleicht gibt es ja in Zukünftigen Versionen von TAChart ein property mit dem man die Breite der Marks fest einstellen oder aber die Position der Achsen selbst festlegen kann.
Das habe ich schon im Hinterkopf abgespeichert. Die Bestimmung der Achsenposition ist aber nicht ganz ohne, mal sehen, ob ich mich da reinfinde.
Im Anhang findest du probeweise eine neue Version der TAChartAxis-Unit, in der jede Achse eine neue Eigenschaft "Distance" erhält. Der Default-Wert 0 behält das bisherige Verhalten der automatischen Achsenpositionierung bei. Die Distance-Werte > 0 sind Pixel zwischen Chart-Rand und einem mir noch nicht bekannten imaginären Teil der Achse. Bei niedrigen Werten überlappt die Achsenbeschriftung mit dem Titel. Werte ab etwa 20 oder 30 sind ok für einen "schönen" Abstand. Wenn du bei zwei übereinander angeordneten Charts jeweils bei der y-Achse denselben Distance-Wert > 0 verwendest, sind die Achsenlinien untereinander ausgerichtet. Um auch die rechten Seiten auszurichten, musst du jeweils eine y-Achse rechts einfügen (Rechtsklick auf "AxisList" im Objekt-Baum, und "Eintrag hinzufügen" wählen, dann "Alignment" auf "calRight") und auch wieder einen gleichen Distance-Wert nehmen; die Beschriftung der rechten y-Achse kannst du mit Marks.Visible ausblenden.

Zur Installation gehe in den Ordner components\tachart deiner Lazarus-Installation. Benenne die Datei TAChartAxis.pas um, so dass du alles hinterher wieder rückgängig machen kannst. Dann kopiere die gleichnamige Datei aus dem Anhang in den tachart-Ordner. Starte Lazarus und kompiliere mit "Werkzeuge" / "Kompiliere Lazarus..." neu - dauert ein bisschen. Dann startet Lazarus neu mit der geänderten Komponente. (Um das wieder rückgängig zu machen, löschst du die neue Datei, benennst die alte TAChartAxis wieder zurück, und kompilierst Lazarus wieder neu).

Spiele ein bisschen herum, ob das deiner Vorstellung entspricht.

Ich bin mit der jetzigen Version noch nicht ganz zufrieden, weil auf Geräten mit anderer Auflösung (Drucker) der Abstand nicht so rauskommt wie auf dem Bildschirm, und weil der Abstand irgendwie den Achsentitel mitrechnet. Beide Charts müssen einen Achsentitel mit der gleichen Zeilenanzahl haben, damit die Ausrichtung klappt - das gefällt mir nicht.

Wenn alles fertig ist, werde ich die neue Unit in TAChart hochladen.
Dateianhänge
Aligned_Axes.png
tachartaxis.zip
(7.62 KiB) 55-mal heruntergeladen

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

Re: TAChart: Achsenbeschriftung Y-Achse und YAchse [gelöst]

Beitrag von wp_xyz »

In Lazarus trunk, r47194, hat TChartAxis jetzt eine neue Eigenschaft "LabelSize" (entsprechend der Eigenschaft "Distance" aus dem vorigen Posting). Bezeichnung und Verhalten sind Delphi-kompatibel. Es gibt auch ein Demo-Projekt "axisalign", in dem die Ausrichtung der Achsen von zwei Charts gezeigt wird, und einen Eintrag in der TAChart-Dokumentation (http://wiki.lazarus.freepascal.org/TACh ... belSize.22).

Antworten