TAChart für Dummies .....

Rund um die LCL und andere Komponenten
Antworten
jomixl
Beiträge: 18
Registriert: Mo 22. Okt 2012, 12:21

TAChart für Dummies .....

Beitrag von jomixl »

Hallo Gemeinde,
seit Tagen versuche ich mich mit TAChart und hab immer das gleiche Problem.
Ich will ein Chart mit fester horizontaler Zeitachse erstellen. Dazu benutze ich bisher TChart und TTimeIntervalChartSource wie im Wiki beschrieben.
Weil ich eine feste Zeitachse will hab ich BottomAxis.Range gesetzt:

Code: Alles auswählen

  Chart1.BottomAxis.Range.Min := StrToTime('6:00');
  Chart1.BottomAxis.Range.Max := StrToTime('22:00');
  Chart1.BottomAxis.Range.UseMax := true;
  Chart1.BottomAxis.Range.UseMin := true;
wenn ich nun aber mit
Chart1LineSeries1.AddXY(StrToTime('6:00:00'),0)
den ersten Punkt setze ist der im Chart bei ca 5:30, d.h. die Achse wird nach rechts verschoben.

Kennt jemand dieses Verhalten bzw. was mach ich falsch?

Grüsse Joachim
Zuletzt geändert von Lori am Di 23. Okt 2012, 11:44, insgesamt 1-mal geändert.
Grund: Highlighter

jomixl
Beiträge: 18
Registriert: Mo 22. Okt 2012, 12:21

Re: TAChart für Dummies .....

Beitrag von jomixl »

hallo zusammen,

hab den Fehler gefunden, der Wert in DateTimeIntervalChartSource.Params.MinLength war zu groß.
Hätte aber noch eine Frage, gibt es eine Komponente mithilfe derer die x/y Koordinaten des Graphen unter dem Cursor angezeit werden?

Grüße Joachim

Benutzeravatar
h-elsner
Lazarusforum e. V.
Beiträge: 282
Registriert: Di 24. Jul 2012, 15:42
OS, Lazarus, FPC: LINUX Mint21.1, Win10, Lazarus 2.2.4, FPC3.2.2
CPU-Target: X86-64; arm 32bit
Wohnort: Illertissen
Kontaktdaten:

Re: TAChart für Dummies .....

Beitrag von h-elsner »

Hi,

es gibt die TATools (TChartToolset), aber ich habe nie kapiert, wie das funktioniert und wie man das anwendet.
Es gibt jedoch die Möglickkeit, ein Fadenkreuz einzublenden. Beispiel:

Code: Alles auswählen

 
procedure TForm1.MenuItem3Click(Sender: TObject); {Fadenkreuz einschalten}
begin
  if Chart4.ReticuleMode=rmNone then begin
    Chart4.ReticuleMode:=rmCross;
    MenuItem3.Caption:=capCrossHairOff;
  end else begin
    Chart4.ReticuleMode:=rmNone;
    MenuItem3.Caption:=capCrossHairOn;
  end;
end;
 
Wenn das Fadenkreuz an ist springt es automatisch zu dem nächsten Datenpunkt. Da kann man dann die X/Y-Werte auslesen:

Code: Alles auswählen

 
procedure TForm1.Chart4DrawReticule(ASender: TChart; ASeriesIndex,
  AIndex: Integer; const AData: TDoublePoint);     {Fadenkreuz-Anzeige}
var s: string;
begin
  case ASeriesIndex of  {feststellen, auf welche Linie fokusiert wurde}
    0:   Linie1;
    1:   Linie2;
    2:   Linie3;
  end;
  s:=s+FloatToStrF(AData.Y, ffFixed, 12, 3)+        {Y-Wert als Float}
       FormatDateTime('hh:nn', AData.X)+rsUhr;     {X-Wert hier Zeit}
  StatusBar1.Panels[2].Text:=s;                 {Meßpunkt anzeigen}
end;
 
Wie du das dann zum Cursor bringst, weiß ich auch nicht. Wenn du das rausfindest, würde ich es gerne wissen.

Gruß HE

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

Re: TAChart für Dummies .....

Beitrag von wp_xyz »

Reticule ist veraltet und wird vom Autor demnächst entfernt werden. Der empfohlene Weg geht über die ChartTools. Ich habe über die Tools einige Tutorials geschrieben (http://wiki.lazarus.freepascal.org/TACh ... hart_Tools, http://wiki.lazarus.freepascal.org/TACh ... s,_Zooming), allerdings bin ich auf das entsprechende "DatapointCrosshairTool" nicht eingegangen.

Daher hier eine Kurzanleitung: Setze eine ChartToolset Komponente auf das Formular und verbinde sie mit der Eigenschaft "Toolset" des Chart. Doppelklick auf dem Toolset öffnet einen Dialog, mit dem man Tools hinzufügen kann. Wähle "Add", dann "Datapoint Crosshair". Lege unter "Shift" fest, mit welcher Taste/welchen Tasten das Tool aktiviert wird, z.B. ssCtrl und ssLeft --> wenn du mit gedrückter Ctrl-Taste und linker Maustaste über die Kurve fährst, springt das Fadenkreuz auf den nächsten Kurvenpunkt (wenn er innerhalb des "GrabRadius" liegt). Zum Auslesen benutzt du das Event OnDraw; über den "Sender", der das betreffende Crosshairtool kennzeichnet, hat man Zugriff auf die Series und den Punktindex, auf dem das Fadenkreuz hängt, bzw. die Position des Fadenkreuzes. Evl. stört dich (wie mich) das formatfüllende Fadenkreuz, setze Size etwa auf 16 um ein kleineres Kreuz zu erhalten.

Benutzeravatar
h-elsner
Lazarusforum e. V.
Beiträge: 282
Registriert: Di 24. Jul 2012, 15:42
OS, Lazarus, FPC: LINUX Mint21.1, Win10, Lazarus 2.2.4, FPC3.2.2
CPU-Target: X86-64; arm 32bit
Wohnort: Illertissen
Kontaktdaten:

Re: TAChart für Dummies .....

Beitrag von h-elsner »

Vielen Dank. Das werde ich bald ausprobieren. Möglicherweise habe ich ja damit endlich mal Glück, die ChartTools zu verstehen ;-).
Ansonsten werde ich hier nochmal melden - die Überschrift passt ja...

Gruß HE

Komoluna
Beiträge: 565
Registriert: So 26. Aug 2012, 09:03
OS, Lazarus, FPC: Windows(10), Linux(Arch)
CPU-Target: 64Bit

Re: TAChart für Dummies .....

Beitrag von Komoluna »

Hallo

Ich hab da mal ne' frage:
Kennt ihr eine Komponente, mit der man einfach eine funktion(z.b.: f(x)=x²+4 )
in einem dynamischen Koordinatensystem darstellen kann?

Komoluna
Programmer: A device to convert coffee into software.

Rekursion: siehe Rekursion.

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

Re: TAChart für Dummies .....

Beitrag von wp_xyz »

Wenn die Funktion schon zur Laufzeit feststeht, findest du eine Anleitung für TAChart/TFuncSeries unter http://wiki.lazarus.freepascal.org/TACh ... ion_Series.

Willst du aber auch die Funktion parsen, dann hast du am wenigsten Arbeit mit plotfunction, ist bei Lazarus mit dabei, du musst aber das Package lazplotfunction noch installieren (verwendet nicht TAChart).

Ansonsten geht es auch mit TAChart und einer TFuncSeries, und zum Parsen der Funktion kannst du fpexprpars verwenden, was zum FPC gehört, (oder auch symbolic, das ich selbst aber noch nicht ausprobiert habe). Mit fpexprpars erzeugst du den Parser folgendermaßen:

Code: Alles auswählen

 
var
  FParser: TFPExpressionParser;
 
...
 
  FParser := TFpExpressionParser.Create(self);
  with FParser do begin
    BuiltIns := [bcMath];
    Identifiers.AddFloatVariable('x', 0.0);
    Identifiers.AddFloatVariable('e', exp(1.0));
    Identifiers.AddFunction('tan', 'F', 'F', @ExprTan);
    // etc.
  end;
 
function ArgToFloat(Arg: TFPExpressionResult): TExprFloat;
// Utility function for the built-in math functions. Accepts also integers
// in place of the floating point arguments. To be called in builtins or
// user-defined callbacks having float results.
begin
  if Arg.ResultType = rtInteger then
    result := Arg.resInteger
  else
    result := Arg.resFloat;
end;
 
Procedure ExprTan(Var Result: TFPExpressionResult; Const Args: TExprParameterArray);
var
  x: Double;
begin
  x := ArgToFloat(Args[0]);
  if IsNumber(x) and ((frac(x - 0.5) / pi) <> 0.0) then
    Result.resFloat := tan(x)
  else
    Result.resFloat := NaN;
end;
 
Mit den Aufruf von "AddFloatVariable" machst du die Variable "x" bekannt. "AddFunction" wird benötigt, um weitere Funktionen einzubinden (per Default kennt FPExpressionParser nur die in der Unit System verwendeten Funktionen.). "ArgToFloat" ist ein nützliches Utility, weil der Parser bezüglich Datentypen sehr pingelig ist, d.h. "sin(1)" funktioniert nicht, weil "1" ein Integer ist, aber die Sin-Funktion Floats erwartet.

Um dann einen Funktionsterm, z.B. s := 'tan(x*4)' zu plotten, rufst du einmalig

Code: Alles auswählen

 
  FParser.Expression := s;
 
auf und kannst dann im OnCalculate event der TFuncSeries folgendermaßen die Funktionswerte abrufen

Code: Alles auswählen

 
procedure TForm1.Chart1FuncSeries1Calculate(const AX: Double; out AY: Double);
var
  res: TFpExpressionResult;
begin
  FParser.Identifiers[0] := AX;
  res := FParser.Evaluate;
  case res of
    rtInteger: AY := res.ResInteger;
    rtFloat: AY := res.ResFloat;
  end;
end;
 
Ach ja noch: Die Behandlung von Laufzeitfehlern, die ja bei manueller Eingabe des Funktionsterms sehr leicht vorkommen können, ist mit fpExprParser etwas stiefmütterlich gelöst, da jeder mathematische Fehler das Programm beendet. Ich habe mir daher die Parser-Units in mein Projekt kopiert und so modifiziert, dass auf Divisionen durch Null, Definitionsbereiche von Funktionen etc. geachtet wird -- mache dich auf einige spannende Programmierstunden gefasst... (aber vielleicht geht das mit "symbolic" besser).
Zuletzt geändert von Lori am Mi 12. Dez 2012, 20:41, insgesamt 1-mal geändert.
Grund: Bitte den richtigen Highlighter verwenden

Antworten