TAB-separierte Textdatei in TAChart
TAB-separierte Textdatei in TAChart
eben mühe ich mich ab, simple ASCII Daten aus einer TAB-separierten Textdatei in einen TAChart zu bringen.
Die Dokumentation http://wiki.freepascal.org/TAChart ist dabei nur sehr begrenzt hilfreich.
Bevor ich nun anfange, die Textdatei zeilenweise in Strings einzulesen und von Hand zu zerstückeln und mit Chart1LineSeries1.AddXY(x,y) Punkt für Punkt meine Kurven zu zeichnen,
wollte ich die Spezialisten fragen ob es
1) eleganter geht, so dass man vielleicht mit Hilfe bereits existierender Prozeduren und Packages z.B. einfach Spalte 2 versus Spalte 4 plotten kann?
2) irgendwo einen verständlichen Beispielcode hat?
Danke für Hinweise!
Die Dokumentation http://wiki.freepascal.org/TAChart ist dabei nur sehr begrenzt hilfreich.
Bevor ich nun anfange, die Textdatei zeilenweise in Strings einzulesen und von Hand zu zerstückeln und mit Chart1LineSeries1.AddXY(x,y) Punkt für Punkt meine Kurven zu zeichnen,
wollte ich die Spezialisten fragen ob es
1) eleganter geht, so dass man vielleicht mit Hilfe bereits existierender Prozeduren und Packages z.B. einfach Spalte 2 versus Spalte 4 plotten kann?
2) irgendwo einen verständlichen Beispielcode hat?
Danke für Hinweise!
Re: TAB-separierte Textdatei in TAChart
Genauso geht's.die Textdatei zeilenweise in Strings einzulesen und von Hand zu zerstückeln und mit Chart1LineSeries1.AddXY(x,y) Punkt für Punkt meine Kurven zu zeichnen
Wenn du's vom Plotten her einfacher haben willst, musst du ein fertiges Plotprogramm verwenden, z.B. gnuplot, das du per Kommandozeilenscript steuern und dessen Output du dann als Bitmap in dein Programm einbinden kannst. Generell ist das aber wesentlich umständlicher als TAChart zu verwenden. Textzeilen an den Separatoren in Einzelstrings zu zerlegen ist wirklich keine Kunst. Sieh dir dazu vielleicht die Routine "LoadPopulationData" im Code-Teil meines Tutorials http://wiki.lazarus.freepascal.org/TACh ... hartSource an.
Re: TAB-separierte Textdatei in TAChart
OK, danke wp_xyz, dann muss ich nicht weiter suchen.
Apropos gnuplot:
eine erste Übersicht über die Rohdaten wollte ich in TAChart realisieren. Für weitere Plots hatte ich vor, mit FreePascal den entsprechenden gnuplot-Code zu generieren und dann von FreePascal gnuplot aufzurufen. Es ist nicht nötig, dass das Bitmap in meinem Programm eingebunden und dargestellt wird. Wenn der Plot in einem separaten gnuplot-Fenster ist, ist das auch in Ordnung.
Gnuplot oder generell andere Programme mit Lazarus starten ist zwar ein anderes Thema, aber hast Du da evtl. schnell einen Tipp oder Link wie das geht und gibt es vielleicht noch Besonderheiten, die man ggf. speziell mit gnuplot beachten müsste?
Apropos gnuplot:
eine erste Übersicht über die Rohdaten wollte ich in TAChart realisieren. Für weitere Plots hatte ich vor, mit FreePascal den entsprechenden gnuplot-Code zu generieren und dann von FreePascal gnuplot aufzurufen. Es ist nicht nötig, dass das Bitmap in meinem Programm eingebunden und dargestellt wird. Wenn der Plot in einem separaten gnuplot-Fenster ist, ist das auch in Ordnung.
Gnuplot oder generell andere Programme mit Lazarus starten ist zwar ein anderes Thema, aber hast Du da evtl. schnell einen Tipp oder Link wie das geht und gibt es vielleicht noch Besonderheiten, die man ggf. speziell mit gnuplot beachten müsste?
Re: TAB-separierte Textdatei in TAChart
Ich habe mir, bevor ich es mit TAChart direkt hinbekommen hatte, Contour-Maps mit gnuplot erzeugen lassen. Das Problem war, dass ich es nicht geschafft hatte, Fehlermeldungen von gnuplot (falls das Script fehlerhaft war - das geht mit gnuplot recht leicht...) mitzuschneiden und im eigenen Programm darzustellen. Erst als ich im englischen Forum über den shellscriptrunner gestolpert bin (http://forum.lazarus.freepascal.org/ind ... 15.15.html), hatte ich eine Lösung, mit der ich zufrieden war.
Hier die wesentlichen Punkte aus meinem Programm (es kommen viele programminterne Variablen vor, aber ich denke, du bekommst eine Idee, wie es geht):
Hier die wesentlichen Punkte aus meinem Programm (es kommen viele programminterne Variablen vor, aber ich denke, du bekommst eine Idee, wie es geht):
Code: Alles auswählen
uses
..., shellcommandrunner, ...
type
TMainForm = class(TForm)
procedure FormCloseQuery(Sender:TObject; var CanClose:boolean);
private
FTempPlotScriptFile : string;
FTempPlotOutput : string;
FCmdThread: TShellCommandRunnerThread;
FCmdThreadErrMsg: String;
FCmdThreadAborted: Boolean;
FGnuplotOutput : string;
FSynHighlighter : TSynGnuplotSyn;
....
procedure CmdThreadOutputAvailable(const pBuffer: PByteArray;
const pCount: integer);
procedure CmdThreadTerminate(Sender: TObject);
function DoAnalyzeData(out ErrMsg:string) : boolean;
function DoExecGnuPlot(out ErrMsg:string) : boolean;
...
end;
procedure TMainForm.CmdThreadOutputAvailable(const pBuffer: PByteArray;
const pCount: integer);
begin
FCmdThreadErrMsg := FCmdThreadErrMsg + TShellCommandRunner.BufferToString(pBuffer,pCount)
end;
procedure TMainForm.CmdThreadTerminate(Sender: TObject);
begin
if (FCmdThread.Runner.ExitStatus = 259) then begin
FCmdThreadErrMsg := '';
FCmdThreadAborted := true;
// gnuplot is still running, the errmsg is the gnuplot prompt in this case
end;
if (FCmdThread.Runner.ExitStatus=0) and (FCmdThreadErrMsg = '') then
PlotImage.Picture.LoadFromFile(FTempPlotOutput)
else
PlotImage.Picture.Clear;
AcKillGnuPlot.Visible := false;
FCmdThread := nil;
end;
procedure TMainForm.FormCloseQuery(Sender:TObject; var CanClose:boolean);
begin
if Assigned(FCmdThread) then
FCmdThread.Abort;
// ...
end;
function TMainForm.DoExecGnuPlot(out ErrMsg:string) : boolean;
var
List: TStringList;
crs: TCursor;
res: integer;
begin
result := false;
ErrMsg := '';
if (Settings.GnuPlotExe = '') then begin
ErrMsg := 'Path to gnuplot binary is not specified. Please use settings dialog.';
exit;
end;
if not FileExists(Settings.GnuPlotExe) then begin
ErrMsg := Format('Gnuplot binary is not found, file "%s" does not exist. '+
'Please use settings dialog.', [Settings.GnuPlotexe]);
exit;
end;
if FCmdThread <> nil then begin
ErrMsg := 'Gnuplot still running.';
exit;
end;
crs := Screen.Cursor;
Screen.Cursor := crHourglass;
try
ScriptMemo.Lines.SaveToFile(FTempPlotScriptFile);
AcKillGnuplot.Visible := true;
FCmdThreadErrMsg := '';
FCmdThreadAborted := false;
FCmdThread := TShellCommandRunnerThread.Create;
// Note: the thread has FreeOnTerminate=true --> no Free here.
// Also, see OnTerminate event handler for further actions.
with FCmdThread do begin
OnOutputAvailable := CmdThreadOutputAvailable;
OnTerminate := CmdThreadTerminate;
CommandLine := Format(
'"%s" -e "set terminal %s size %d,%d truecolor enhanced" -e "set output ''%s''" "%s"',
[
Settings.GnuPlotExe,
Settings.OutputFormat,
Settings.OutputWidth,
Settings.OutputHeight,
UseUnixPathDelimiters(FTempPlotOutput),
FTempPlotScriptFile
]
);
Start;
end;
// this is a replacement for "WaitFor" -- system remains responsive.
while (FCmdThread <> nil) do
Application.ProcessMessages;
ErrMsg := FCmdThreadErrMsg;
result := (ErrMsg = '') and (not FCmdThreadAborted);
finally
Screen.Cursor := crs;
end;
end;
Re: TAB-separierte Textdatei in TAChart
Danke für den Code, aber ich tue mich schwer, das nachzuvollziehen und zu reproduzieren.
Ich habe versucht alles entsprechend anzupassen und alles "Unnötige" wegzulassen, damit es beim Kompilieren keine Fehlermeldungen gibt.
Die zentrale Stelle ist doch:
Die Fehlermeldung "wrong numbers of parameters" bekomme ich nicht weg. Welche Parameter soll ich bei einsetzen?
Wenn ich diese und die nächste Zeile auskommentiere, läuft das Programm zwar, aber es hängt und im Taskmanager sind 50% CPU beansprucht. Kein GnuPlot-Fenster geht auf.
Was fehlt, was mache ich falsch?
Mit der anderen Variante, die in Tutorials beschrieben wird und den einfachen Zeilen
geht wenigstens ein GnuPlot-Fenster auf. Aber das bringt mich auch nicht weiter, weil ich nicht weiss wie ich ein Kommando, z.B. "plot sin(x)" oder "load TestPlot.plt" übergeben kann.
Ich habe versucht alles entsprechend anzupassen und alles "Unnötige" wegzulassen, damit es beim Kompilieren keine Fehlermeldungen gibt.
Die zentrale Stelle ist doch:
Code: Alles auswählen
FCmdThread := TShellCommandRunnerThread.Create;
with FCmdThread do
begin
OnOutputAvailable := CmdThreadOutputAvailable; // Fehlermeldung "wrong numbers of parameters"
OnTerminate := CmdThreadTerminate; // Fehlermeldung "wrong numbers of parameters"
CommandLine := 'E:/Programs/gnuplot/bin/wgnuplot.exe';
Start;
end;
Code: Alles auswählen
OnOutputAvailable := CmdThreadOutputAvailable;
Wenn ich diese und die nächste Zeile auskommentiere, läuft das Programm zwar, aber es hängt und im Taskmanager sind 50% CPU beansprucht. Kein GnuPlot-Fenster geht auf.
Was fehlt, was mache ich falsch?
Mit der anderen Variante, die in Tutorials beschrieben wird und den einfachen Zeilen
Code: Alles auswählen
procedure TForm1.Button2Click(Sender: TObject);
var Output: string;
begin
Output:= '';
RunCommand('E:/Programs/gnuplot/bin/wgnuplot.exe',[''],Output);
end;
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: TAB-separierte Textdatei in TAChart
Im objfpc Modus ist zur Angabe einer Methodenadresse "@" notwendig.Theozh hat geschrieben:Code: Alles auswählen
FCmdThread := TShellCommandRunnerThread.Create; with FCmdThread do begin OnOutputAvailable := CmdThreadOutputAvailable; // Fehlermeldung "wrong numbers of parameters"
Code: Alles auswählen
OnOutputAvailable := @CmdThreadOutputAvailable;
Re: TAB-separierte Textdatei in TAChart
Danke, mse! Wieder etwas dazugelernt.
Aber das Programm "hängt" nach wie vor. Da liegt der Hund noch woanders begraben. Hmm, such, such...
Aber das Programm "hängt" nach wie vor. Da liegt der Hund noch woanders begraben. Hmm, such, such...
Re: TAB-separierte Textdatei in TAChart
Sorry wegen des @ - ich hatte das Programm damals im Delphi-kompatiblen Modus geschrieben.
Das RunCommand kannte ich noch nicht, in welcher Unit steht es?
Schau dir wegen der Übergabe der gnuplot-Befehle das gnuplot-Manual an. Du kannst die Befehle direkt in der Kommandozeile angeben, jeweils hinter einen "-e" und mit " eingeschlossen, also z.B.
wobei die Option "-persist" dafür sorgt, dass das gnuplot-Fenster direkt nach dem Aufruf nicht gleich wieder verschwindet.
Spätestens beim Ändern des Achsen-Labels a la
wirst du damit allerdings an die Grenzen stoßen, weil zuviele Anführungsstriche nötig sind.
Daher ist es ratsamer, alle gnuplot-Befehle in einer Script-Datei zusammenzufassen, z.B. "testplot.plt" mit folgendem Inhalt
und diese als letzten Parameter zu übergeben
Übrigens, wenn du nicht möchtest, dass das Eingabefester von wgnuplot zusammen mit dem Plot auf dem Bildschirm erscheint, solltest du statt wgnuplot das gnuplot-Programm selbst (ohne das "w") verwenden.
Das RunCommand kannte ich noch nicht, in welcher Unit steht es?
Schau dir wegen der Übergabe der gnuplot-Befehle das gnuplot-Manual an. Du kannst die Befehle direkt in der Kommandozeile angeben, jeweils hinter einen "-e" und mit " eingeschlossen, also z.B.
Code: Alles auswählen
RunCommand('E:/Programs/gnuplot/bin/wgnuplot.exe', ['-persist', '-e', '"plot sin(x)"'], Output);
Spätestens beim Ändern des Achsen-Labels a la
Code: Alles auswählen
set xlabel "x-Achse"
Daher ist es ratsamer, alle gnuplot-Befehle in einer Script-Datei zusammenzufassen, z.B. "testplot.plt" mit folgendem Inhalt
Code: Alles auswählen
set xlabel "x-Achse"
set ylabel "y-Achse"
plot sin(x), cos(x)
Code: Alles auswählen
RunCommand('E:/Programs/gnuplot/bin/wgnuplot.exe', ['-persist', 'Testplot.plt'], Output);
Re: TAB-separierte Textdatei in TAChart
Danke, wp, für die nötige GnuPlot-Kommandozeile.
Die Funktion 'RunCommand' steht in der unit Process.
Die Parameter können auch am Stück folgendermaßen übergeben werden: Wenn in 'Test.plt' entsprechend korrekter GnuPlot-Code steht wird er ausgeführt und angezeigt
.
Bei mir ist es allerdings so, dass bei 'gnuplot.exe' zusätzlich ein Konsolenfenster erscheint. Bei 'wgnuplot.exe' erscheint nur das Plot-Fenster (so wie ich es bevorzuge).
Der Nachteil mit 'RunCommand' ist, dass das eigene Programm "blockiert" ist. Erst wenn man das GnuPlot-Fenster schliesst, geht das eigene Programm wieder weiter.
Wenn ich Dich recht verstanden habe, kann man bei der Variante mit 'ShellCommandRunner' mit dem eigenen Programm noch agieren. Deshalb würde ich Deine Version gerne noch zum Laufen bringen.
Denn idealerweise würde ich das GnuPlot-Fenster mit dem eigenen Programm starten, auffrischen und beenden.
Die Funktion 'RunCommand' steht in der unit Process.
Die Parameter können auch am Stück folgendermaßen übergeben werden:
Code: Alles auswählen
RunCommand('E:/Programs/gnuplot/bin/wgnuplot.exe -persist Test.plt', Output);

Bei mir ist es allerdings so, dass bei 'gnuplot.exe' zusätzlich ein Konsolenfenster erscheint. Bei 'wgnuplot.exe' erscheint nur das Plot-Fenster (so wie ich es bevorzuge).
Der Nachteil mit 'RunCommand' ist, dass das eigene Programm "blockiert" ist. Erst wenn man das GnuPlot-Fenster schliesst, geht das eigene Programm wieder weiter.
Wenn ich Dich recht verstanden habe, kann man bei der Variante mit 'ShellCommandRunner' mit dem eigenen Programm noch agieren. Deshalb würde ich Deine Version gerne noch zum Laufen bringen.
Denn idealerweise würde ich das GnuPlot-Fenster mit dem eigenen Programm starten, auffrischen und beenden.
Re: TAB-separierte Textdatei in TAChart
Ja. Das bekommt man weg, indem man den Process mit der Option poNoConsole (siehe "Process.pp") startet. An die Prozess-Instanz kommst du allerdings bei der Verwendung von RunCommand nicht ran. Baue dir am besten das Kommando in deiner eigenen Unit nach und setze die entsprechenden Optionen.dass bei 'gnuplot.exe' zusätzlich ein Konsolenfenster erscheint
Das große ABER: Leider ist damit das eigene Programm nicht mehr bedienbar...
Generell wirst du ohne einen eigenen Thread für den Prozess nicht glücklich werden. Das ist genau, was der ShellCommandRunner macht. Ich habe mein Programm auf das nötigste komprimiert und in einem separaten Thread veröffentlicht (http://www.lazarusforum.de/viewtopic.php?f=11&t=7139).