TAChart -> TDateTimeIntervalChartSource automatik

Rund um die LCL und andere Komponenten
Antworten
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

Hallo,
ich habe wiedereinmal Verständnisprobleme mit der automatischen Formatierung bei einer Datums-Achse.

Komponenten

Code: Alles auswählen

    Chart1: TChart;
    Chart1ConstantLine1: TConstantLine;
    Chart1ConstantLine2: TConstantLine;
    Chart1LineSeries1: TLineSeries;
    ChartAxisTransformations1AutoScaleAxisTransform1: TAutoScaleAxisTransform;
    DateTimeIntervalChartSource1: TDateTimeIntervalChartSource;
    DS: TDataSource;
    DbChartSource: TDbChartSource;
 
......
  object DbChartSource: TDbChartSource[3]
    DataSource = DS
    FieldX = 'Datum'
    FieldY = 'Kleber'
    Options = [dcsoDateTimeX]
  end
  object DateTimeIntervalChartSource1: TDateTimeIntervalChartSource[4]
    Params.Options = [aipUseMaxLength, aipUseMinLength]
    DateTimeFormat = 'dd.mm.yy'
    Steps = [dtsYear, dtsMonth, dtsDay]
  end
 


Es funktionier die Anzeige der x-Achsenbeschriftung, scheinbar solange genügend Punkte da sind.
TAChart mit Anzeige des Datums
TAChart mit Anzeige des Datums


Wenn ich nur um einen Punkt weniger habe, so sehe ich keine X-Achsenbeschriftung mehr
TAChart ohne Beschriftung
TAChart ohne Beschriftung

Ich habe da die Möglichkeiten und Verhalten der Automatik noch nicht verstanden :D

Wie kann ich das Verhalten steuern ?

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

Auch ich habe lange daran geknabbert, die DateTimeIntervalChartSource zu verstehen, und ich bin auch jetzt nicht sicher, ob mir wirklich alles klar ist...

Je nach Intervall zwischen linkem und rechtem Ende der Achse und Größe des Chart werden unterschiedliche Basis-Einheiten gewählt, also ob die Ticks in Einheiten von Jahren, Monaten, Wochen, Tagen etc weitergezählt werden. Mit Steps kann man lediglich auswählen, bei welchen Basiseinheiten eine Achsenbeschriftung angezeigt werden soll. In deinem Beispiel wird eine Beschriftung angezeigt, wenn die Basiseinheit Jahre, Monate oder Tage sind. Zoomst du sehr stark in den Chart hinein, wird der Unterschied zwischen links und rechts so klein, dass als Einheit z.B. Stunden gewählt werden, und die Beschriftung wird komplett unterdrückt. Aus diesem Grund lasse ich Steps eigentlich immer unverändert.

Du hast des weiteren noch ein DateTimeFormat angegeben. Dies setzt die automatische Suche nach dem best.möglichen Format außer Kraft, und es werden die Achsen immer mit dem Format 'dd.mm.yy' beschriftet, selbst wenn die Spanne zwischen links und rechts nur 1 Sekunde beträgt. Dann sind natürlich alle Labels identisch beschriftet.

Dazu hatte vor kurzem jemand im englischen Forum eine Idee, für jede Basis-Einheit ein eigenes Beschriftungsformat angeben zu können. Das ist in der Trunk-Version von Lazarus eingebaut - siehe Property DateTimeStepFormat.

Zur Steuerung der Beschriftung gibt es noch die Eigenschaft "SuppressPrevUnit", default = true, durch die der konstante Bestandteil der Datum-/Zeit-Beschriftung unterdrückt wird. Wenn also z.B. die Labels im Tagesabstand für die Tage 1.10.2016, 2.10.2016, 3.10.2016, etc, gesetzt werden, erscheint der Monat nur am 1.10, bei den folgenden Tagen aber nicht mehr (bis zum November, wo das erste Label wieder mit Monat beschriftet wird). Schaltest du SuppressPrevUnit aus, wird das Format DateTimeStepFormat[dtDay] genommen.

Ich bin mir nicht sicher, ob man die Umschaltpunkte zwischen den einzelnen Basiseinheiten mit Params.MinLength und .MaxLength steuern kann. Beim Umschalten jedenfalls wird das Ereignis OnDateTimeStepChange ausgelöst, dem der aktuelle Wert der Basiseinheit als Parameter ASteps mit auf den Weg gegeben wird. Du könntest dir so z.B. vorübergehend die aktuelle Basiseinheit anzeigen lassen:

Code: Alles auswählen

procedure TForm1.DateTimeIntervalChartSource1DateTimeStepChange(
  Sender: TObject; ASteps: TDateTimeStep);
begin
  Caption := GetEnumName(TypeInfo(TDateTimeStep), ord(ASteps));
end;
Zuletzt geändert von wp_xyz am Fr 24. Feb 2017, 10:48, insgesamt 1-mal geändert.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

Die Daten bei mir sind aber über eine größere Spanne, das kann aber nicht das Problem sein.

Die werden auf tägliche Daten im SQL Statment gemittelt, somit bleiben zumindest 6 Datensätze hier über mit einer Zeitspanne von 1.12.16 bis 16.12.16. gebe ich nur einen Tag hinzu = 1 Punkt mehr, so wird das Datum angezeigt.

Code: Alles auswählen

01.12.2016 06:24
02.12.2016 09:46
12.12.2016 07:16
12.12.2016 14:12
12.12.2016 14:22
12.12.2016 15:32
12.12.2016 16:10
12.12.2016 16:43
12.12.2016 17:37
12.12.2016 17:44
12.12.2016 18:03
12.12.2016 18:18
12.12.2016 18:34
12.12.2016 21:04
13.12.2016 14:46
13.12.2016 14:50
13.12.2016 14:55
13.12.2016 17:54
13.12.2016 18:13
13.12.2016 18:33
13.12.2016 20:35
13.12.2016 20:41
14.12.2016 06:52
14.12.2016 06:52
14.12.2016 07:32
14.12.2016 15:43
14.12.2016 16:46
14.12.2016 16:51
14.12.2016 17:39
14.12.2016 19:31
16.12.2016 06:35
16.12.2016 06:38
 


Andi
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

In deiner Einstellung von dtsSteps fehlen die Weeks, ich weiß nicht, ob die Achse vielleicht auf diese Schrittweite schaltet.

Am besten postest du eine kleine Demo mit einer Beispiel-Datenbank (TBufDataset, TMemoryDataset, sqlite), oder mit den Datumswerten in einer ChartListSource, dann kann ich mir das im Detail ansehen.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

Beispiel da, ist aus meinem Programm herauskopiert. Nur die Datenanbindung ist halt anders.

Allerdings funktioniert das in dem Beispiel überhaupt nicht. Da wird nie die BottomAxis mit Datum angezeigt.

Danke

Andreas
Dateianhänge
TAChartAchse.7z
Beispiel für verschwundenes Datum
(2.44 KiB) 78-mal heruntergeladen
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

Folgendes stimmt zunächst mit dem Projekt nicht:

  • SdfDataset wird nirgendwo geöffnet --> ein FormCreate mit SdfDataset1.Open eingefügt
  • "Unable to open dataset" weil der Dateiname von SdfDataset1 einen führenden Backslash enthält --> entfernt --> Chart erscheint, aber ohne x Labels.
  • In BottomAxis.Marks.Source ist nichts eingetragen. Das bewirkt, dass die Werte der internen Listsource genommen werden - die ist aber deaktiviert, weil du die Series-Daten ja aus der DbChartSource beziehst. --> DatetimeIntervalChartSource eintragen --> x-Label werden angezeigt
  • In den Chart zoomen (durch Aufziehen eines Rechtecks von links oben nach rechts unten über dem zu vergrößernden Bereich, z.b. zwischen 19.11 und 27.11 --> Bereich wird vergrößert, aber x-Labels verschwinden. Aktivere dtsHour in den Steps der DateTimeIntervalChartSource --> Labels sind wieder da. Wie schon oben gesagt, würde ich bei DateTimeIntervalChartSource.Steps alle Häkchen gesetzt lassen.
Insofern erscheint mir das Programm jetzt ok. Was muss ich tun, um das Verschwinden der Labels beim Hinzufügen eines Datenpunktes zu provozieren?

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

wp_xyz hat geschrieben:[*]In BottomAxis.Marks.Source ist nichts eingetragen. Das bewirkt, dass die Werte der internen Listsource genommen werden - die ist aber deaktiviert, weil du die Series-Daten ja aus der DbChartSource beziehst. --> DatetimeIntervalChartSource eintragen --> x-Label werden angezeigt
[*]In den Chart zoomen (durch Aufziehen eines Rechtecks von links oben nach rechts unten über dem zu vergrößernden Bereich, z.b. zwischen 19.11 und 27.11 --> Bereich wird vergrößert, aber x-Labels verschwinden. Aktivere dtsHour in den Steps der DateTimeIntervalChartSource --> Labels sind wieder da. Wie schon oben gesagt, würde ich bei DateTimeIntervalChartSource.Steps alle Häkchen gesetzt lassen.[/list]

Die BottomAxis.Marks.Source muß ich mir in der eigentlichen Applikation nochmals genauer ansehen.

Ich habe die Anzahl der Datenpunkte verringert, unter 5 oder 6 verschwanden die.

Danke, für dein Bemühen.

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

Kannst du die csv-Datei hochladen, bei der die x-Labels verschwunden sind?

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

Die Daten kommen aus einer SQL DB und sind für den Test extra in die Textdatei geschrieben.

Ich muss mir den Input von Dir noch genauer ansehen und ich will das TChart begreifen, da ich in nächster Zeit einiges damit vorhabe.

Andreas

Edit:
Wenn ich im DateTimeIntervalChartSource alle unter Steps ankreuze, dann habe ich doppelte Tage drinnen, aber die Beschriftung bleibt. Nehme ich nur [dtsYear,dtsQuarter,dtsMonth,dtsWeek,dtsDay] so verschwindet die Beschriftung wenn es wenige Datenpunkte sind. Es hat etwas mit der Automatik im DateTimeIntervalChartSource
zu tun.

Edit1:
Wenn ich nur dtsHour dazunehme wird angezeigt, aber mit zeitweise doppelten Datum.
TAChart DateTimeIntervalChartSource Versuch
TAChart DateTimeIntervalChartSource Versuch
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

af0815 hat geschrieben:Wenn ich im DateTimeIntervalChartSource alle unter Steps ankreuze, dann habe ich doppelte Tage drinnen, aber die Beschriftung bleibt.

Wie ich geschrieben habe, hast du in DateTimeFormat den Formatierungsstring "dd.mm.yyyy" eingetragen. Dieser wird für alle Step-Werte genommen, auch wenn er gar nicht passt, also zum Beispiel auch wenn der Chart nur wenige Tage umfasst und die Automatik auf Stunden-Intervalle umschaltet; in diesem Modus können pro Tag mehrere Labels gezeichnet werden - mit dem festen Formatierungsstring wird aber jeder Tick desselben Tages mit dem identischen Text beschriftet. Wenn du spezielle Formatierungswünsche hast, ist es schlauer, DateTimeFormat leer zu lassen und stattdessen DateTimeStepFormat zu verwenden, in dem man den Formatierungstext für jedes Step-Intervall festlegen kann. Damit könntest du z.B. für dtHour den Formatierungsstring auf 'dd.mm.yyyy'+LineEnding+'hh:nn' setzen, der weiterhin das Datum anzeigt, darunter in einer zweiten Zeile aber auch die Uhrzeit. Gibt es aber erst in Laz trunk.

Vielleicht solltest du einmal spezifizieren, wie, unter welchen Bedingungen, die Achsenlabels aussehen sollen
Zuletzt geändert von wp_xyz am Fr 24. Feb 2017, 21:41, insgesamt 1-mal geändert.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

Spezifikation: Teilung in Tagen oder auch grober, egal ob die Daten Löcher haben - fehlende Tage. Es soll optisch gleiche Teilung haben, nicht wie im Beispiel.

Vorerst werden die Daten in der kleinsten Einheit Tag über Mittelwert verdichtet. Es gibt also keine kleineren Einheiten.

Später verdichte ich für Boxplot je Tag, da muss ich mir die optimale Verarbeitung der Median Werte überlegen. Auch in Hinblick mit milden und großen Ausreißern.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

Wenn ich das richtig verstehe, willst du auf jeden Fall eine Tagesskala haben (oder gröber), eine zusätzliche Uhrzeit-Angabe ist nicht erwünscht.

Ich bin nicht sicher, ob man das mit DateTimeIntervalChartSource hinkriegt. Falls du nicht zoomen willst, wäre es am einfachsten, eine ListChartSource mit den gewünschten Labels zu füllen und diese dann anstatt der DateTimeIntervalchartSource in Marks.Source der Achse einzuhängen. Hier hätte man volle Kontrolle, muss allerdings etwas programmieren. Hier ein Beispiel, wie man die ListSource, je nach angezeigtem Start-bis-Ende-Intervall, mit geeigneten Labels füllen könnte (nicht konkret getestet, aber die Idee funktioniert schon mehrfach bei Usern):

Code: Alles auswählen

procedure PopulateDateLabels(AListChartSource: TListChartSource; AStartDate, AEndDate: TDate);
type
  TDateInterval = (diOneDay, diTwoDays, diOneWeek, diOneMonth, diThreeMonths, diYears);
var
  d: TDate;
  interval: TDateInterval;
  diff: Double;
begin
  ListChartSource.Clear;
 
  // Schrittweite bestimmen (Schwellwerte konkret anpassen, hier nur grobe Schätzung, ungetestet)
  diff := AEndDate - AStartDate;
  if diff < 15 then
    interval := diOneDay 
  else if diff < 30 then
    Interval := diTwoDays
  else if diff < 60 then
    Interval := diOneWeek
  else if diff < 360 then
    Interval := diOneMonth
  else if diff < 3*360 then
    Interval := diThreeMonths
  else
    Interval := diYears;
 
  // Datum für erstes Label bestimmen
  d := AStartDate;
  case interval of
    diOneDay: d := AStartDate;
    diTwoDays: if odd(trunc(AStartdate) then d := AStartDate - 1 else d := AStartDate;
    diOneWeek: d := StartOfTheWeek(d);
    diOneMonth:  d := StartOfTheMonth(d);
    dithreeMonths:  // Das Label soll am 1.1, 1.4., 1.7., 1.10. sitzen
        case MonthOf(d) of
          1, 2, 3: d := EncodeDate(YearOf(AStartDate), 1, 1);
          4, 5, 6: d := EncodeDate(YearOf(AStartDate), 4, 1);
          7, 8, 9: d := EncodeDate(Yearof(AStartDate), 7, 1);
          else d := EncodeDate(YearOf(AStartDate), 10, 1);
       end;
    diYears:
      d := StartOfTheYear(d);
  end;
  ListChartSource.Add(d, d, FormatDateTime('dd.mm.yyyy', d));
 
  // Nun d in Schleife bis nach den Endedatum durchlaufen und Labeltext ermitteln und in ListSource schreiben
  while d <= AEndDate do begin
     // Nächsten Wert ermitteln
    case interval of
      dtOneDay: d := d + 1;
      dtTwoDays: d := d + 2;
      dtOneWeek: incWeek(d);
      dtOneMonth: IncMonth(d);
      dtThreeMonths: IncMonth(d, 3);
    end;
    ListChartSource.Add(d, d, FormatDateTime('dd.mm.yyyy', d));
    // Hinweis: Das erste und letzte Label sollten vor dem Achsenbeginn bzw. hinter dem Achseende liegen.
    // Falls später einmal Minor-Ticks gebraucht werden, kann man sie dann einfach zwischen allen Labels
    // erzeugen und hat dann keine leeren Bereiche.
    // Dadurch das Datum am Anfang der Schleife erhöht wird, ist das sichergestellt.
  end;
end;

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

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von wp_xyz »

Im Anhang das obige als getestetes und lauffähiges Projekt. Vielleicht muss man, wie oben schon als Code-Kommentar angedeutet, die Schwellen, an denen die Umschaltung zwischen den einzelnen Incrementen erfolgt, noch etwas anders definieren.
Dateianhänge
DateIntervals_ListSource.zip
(3.45 KiB) 84-mal heruntergeladen

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TAChart -> TDateTimeIntervalChartSource automatik

Beitrag von af0815 »

Interessantes Thema. Nachdem ich noch etwas Zeit habe, möchte ich mal verstehen wie die Automatik von DateTimeIntervalChartSource funktioniert. Die macht ja fast alles richtig :D Es geht mir aktuell nicht so 100% um eine schnelle Lösung, ich möchte die TAChart-Komponenten auch verstehen.

Mal sehen was ich mit dem Input alles anfangen kann.

Danke jedenfalls für die Hilfe

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten