[gelöst] Daten in TChart hinzufügen

Für Fragen von Einsteigern und Programmieranfängern...
Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

[gelöst] Daten in TChart hinzufügen

Beitrag von Scurra »

Hallo zusammen,

ich habe zwei Fragen zu TChart. Erst erkläre ich kurz, was ich machen möchte:

Ich möchte ganzzahlige Zufallszahlen erzeugen (z. B. insgesamt 1000 Stück im Bereich von 0 bis 9). Diese Zahlen habe ich mir in einem Array gespeichert. Nun Möchte ich die Zufallszahlen graphisch in einem Balkendiagramm darstellen. Dazu habe ich ein TChart verwendet, welchem ich ein BarSeries hinzugefügt habe. Jetzt habe ich aber das Problem, dass die Daten in meinem Array in zufälliger Reihenfolge auftreten. Es kann also sein, dass z. B. das erste und das letzte Element den Wert 5 haben und alle anderen Zufallszahlen einen anderen Wert haben. Dann möchte ich in meinem Balkendiagramm an der Stelle 5 einen Balken mit Höhe 2 haben. Aus einer anderen Programmiersprache kenne ich Funktionen, die es erlauben, den Wert in einem Balkendiagramm an einer bestimmten Stelle um 1 zu inkrementieren. Gibt es so etwas auch mit Delphi? Ich habe im Quelltext von TACustumSeries (wo z. B. die Funktion AddXY(...) definiert ist, um Datenpunkte in Diagramme einzufügen) leider nichts gefunden.

Für mein Beispiel von oben habe ich noch relativ leicht einen Ausweg gefunden, indem ich mir ein neues Array mit 10 Einträgen anlege und dann mein array, in dem die Zufallszahlen gepseichert sind, durchlaufe und jedes Mal, wenn eine 5 gefunden wird, den 5. Eintrag des neuen Arrays um eins inkrementiere. So liefert mir das neue Array immer Paare von xy-Werten.
Jetzt habe ich aber ein komplizierteres Problem, bei dem die Wertemenge nicht nur von 0 bis 9 reicht, deshalb bin ich auf der Suche nach einer Funktion, die mir das Inkrementieren im Balkendiagramm erlaubt.

Die zweite Frage betrifft die Balken im Diagramm direkt: Ist es möglich, die Balkenbreite größer als 1 zu machen, so dass z. B. Werte von 0-2 in einen Balken bei 1, die Werte 2-4 in einen Balken bei 3 usw. gespeichert werden?
Zuletzt geändert von Scurra am Mo 12. Jan 2015, 12:11, insgesamt 1-mal geändert.

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

Leider ist mir deine Beschreibung im Detail nicht klar...

- Zufallszahlen zwischen 0 und 9: Integer-Werte oder auch Gleitkommazahlen?
- Was willst du darstellen? Wie oft jede Zahl vorkommt? Das geht bei Gleitkommazahlen nur, wenn du ein Intervall definierst, in dem die Zahlen vorkommen müssen. Jeder Treffer in dem Intervall erhöht den Zähler.

Mit TAChart kannst du so gut wie alles machen, allerdings das meiste von den ausgefallenen Sachen nicht "automatisch" (wie sollte es auch?)

Wenn das alles so ist wie ich mir das vorstelle, insbesondere Gleitkommazahlen, würde ich so vorgehen (nicht getestet...):

Code: Alles auswählen

 
const
  INTERVAL = 0.1;  // Breite des Intervalls für jeden Balken
  MIN = 0;  // kleinste Zufallszahl
  MAX = 9;  // höchste Zufallszahl
 
procedure TForm1.AddDataToBarSeries(const AData: array of double; ABarSeries: TBarSeries);
// AData ist das Array mit den Double-Zufallszahlen
var
  myData: array of integer;  // array für die Häufigkeiten
begin
  // Das Häufigkeits-Array so dimensionieren, dass alle Intervalle Platz finden
  SetLength(myData, round((MAX - MIN) / INTERVAL));  
 
  // Alle Zufallszahlen durchlaufen
  for i:=0 to High(AData) do begin
    // Index für das Häufigkeitsintervall finden
    index := Trunc((AData[i] - MIN) / INTERVAL);  // Alle Intervalle müssen gleich groß sein!
    inc(myData[index]);
  end;
 
  // Häufigkeiten in die BarSeries
  ABarSeries.Clear;
  for i:=0 to High(myData) do
    ABarSeries.AddXY((i+0.5)*INTERVAL, myData[i]);
    // +0.5 damit der Balken in der Mitte des Intervalls sitzt
end;
 

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

Zufallszahlen zwischen 0 und 9: Integer-Werte oder auch Gleitkommazahlen?
Ganzzahlige Werte, also Integer-Werte (aber im Prinzip ist mir der Typ erst einmal egal).
Was willst du darstellen? Wie oft jede Zahl vorkommt?
Richtig.
Das geht bei Gleitkommazahlen nur, wenn du ein Intervall definierst, in dem die Zahlen vorkommen müssen. Jeder Treffer in dem Intervall erhöht den Zähler.
Was, wenn ich ein Intervall mit einer Länge >1 haben möchte? Wie kann ich die Balken in der Grafik von TChart größer machen? Im Objektinspektor der TBarSeries gibt es eine Eigenschaft "BarWidthPercent", die ich auf 100 gestellt habe, dann ist die Breite genau 1. Aber höher kann ich es leider nicht einstellen. Gibt es hierfür eine Funktion/Eigenschaft?
Mit TAChart kannst du so gut wie alles machen, allerdings das meiste von den ausgefallenen Sachen nicht "automatisch" (wie sollte es auch?)
Na ja, die Frage ist, was man als ausgefallen betrachtet (ich finde das nicht so ausgefallen und habe es auch schon oft gebraucht, als ich mit C++ bzw. ROOT programmiert habe) und wie die Daten gespeichert werden. Da ich nicht weiß, wie die Daten gespeichert werden, kann ich nicht beurteilen, ob es schwer ist, das zu implementieren oder nicht.

Ich habe mein Programm ähnlich implementiert wie du (abgesehen davon, dass deine Implementierung eleganter aussieht ;)).

Danke jedenfalls schon mal für deine Hilfe.

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

Was, wenn ich ein Intervall mit einer Länge >1 haben möchte? Wie kann ich die Balken in der Grafik von TChart größer machen? Im Objektinspektor der TBarSeries gibt es eine Eigenschaft "BarWidthPercent", die ich auf 100 gestellt habe, dann ist die Breite genau 1. Aber höher kann ich es leider nicht einstellen. Gibt es hierfür eine Funktion/Eigenschaft?
Die Balken-"Höhe" ist der Y-Wert, den du bei BarSeries.AddXY als 2. Parameter angegeben hast. "BarWidthPercent" ist die Breite, ausgedrückt in Prozent des verfügbaren Platzes; bei 100% berühren sich benachbarte Balken, bei 50% ist der Zwischenraum zwischen den Balken genauso groß wie die Balken breit sind (Wenn du zwei Balken-Series, jeweils mit BarWidthPercent=50, hättest, würden sich die Balken aber wieder berühren, weil der Zwischenraum durch die 2. Series belegt ist - ist eigentlich ganz logisch...)

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

[...] genauso groß wie die Balken breit sind
Genau um diese Breite geht es mir. Kann man diese vergrößern, so dass z. B. ein Balken von x=-5 bis x=5 und der nächste Balken von x=5 bis x=10 reicht? D. h. dass alle Datenpunkte mit 5<=x<10, die ich hinzufüge, einem Balken hinzugefügt werden?

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

Ok, ich glaube ich verstehe jetzt: du willst die Breite der Balken über die Koordinaten der Balkenränder steuern. Ich denke, das geht mit TBarSeries nicht, hier hat man nur die Koordinate des Balkenmittelpunkts und die Balkenbreite passt sich nach einem etwas undurchsichtigen Algorithmus an den Abstand zum nächsten Datenpunkt an.

Mehr Kontrolle hast du mit einer Area-Series. Du darfst da aber nicht die x-Werte der Balkenmittelpunkte der Series zuweisen, sondern die der Balkenränder. Jedem x-Wert wird dann der y-Werte des linken und dann der des rechten Balkens zugewiesen Letztendlich müssen die Punkte der Series dem Polygonzug der oberen Balkenränder folgen.

Hier ein Beispiel (getestet...): Es sollen Balken zwischen 0 und 1, 1 und 5, 5 und 10, sowie zwischen 10 und 20 bezeichnet werden, als Balkenhöhe verwende ich Zufallszahlen.

Code: Alles auswählen

 
procedure TForm1.FormCreate(Sender: TObject);
const
  N = 5;
  barBorders: array[0..N] of double = (0, 1, 5, 6, 10, 20);
  // Balken zwischen 0..1, 1..5, 5..6, 6..10, 10..20
var
  i: Integer;
  xlinks, xrechts,y: Double;
begin
  for i := 0 to N-1 do begin     // wichtig: N-1 !!!
    xlinks := barBorders[i];
    xrechts := barBorders[i+1];
    y := random;    // (zufällige) Balkenhöhe - gilt für den linken und rechten Punkt als y-Wert
    Chart1AreaSeries1.AddXY(xlinks, y);       
    Chart1AreaSeries1.AddXY(xrechts, y);
  end;
end;  
Damit entsteht das angehängte Bild. Die vertikalen Linien zeichnet TAreaSeries an jedem Datenpunkt standardmäßig (können aber auch ausgeblendet werden).

Falls du zwischen Balken eine Lücke lassen willst, musst du zwischen den Balken jeweils zur Null-Linie heruntergehen.
Dateianhänge
VarBarWidth.png

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

Danke für den Hinweis und das Beispiel mit TAreaSeries. Mir würde es schon genügen, wenn alle Balken die gleiche Breite haben, aber eben eine Breite größer als eins. Dafür sollte ich auch TAreaSeries verwenden, oder?

Ich habe noch eine Frage bzgl. TChart: Gibt es eine Möglichkeit, den Wertebereich der x-Achse zu verändern. Hier mal ein Beispiel:

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
const
  N = 1000; // Anzahl berechneter Punkte
  MIN = -10; // minimaler x-Wert für Berechnung
  MAX = 10; // maximaler x-Wert für Berechnung
var
  i: Integer;
  x: Double;
begin
  for i:=0 to N-1 do begin
    x := MIN + (MAX - MIN) * i/(N - 1);
    SinSeries.AddXY(x, sin(x));
    CosSeries.AddXY(x, cos(x));
    SinCosSeries.AddXY(x, sin(x)*cos(x));
  end;
end;
Das Ergebnis sieht so aus wie in dem Bild im Anhang.

Was mir aber nicht so gut daran gefällt, ist, dass man am linken und rechten Rand das "Ende" der Funktionsgraphen sieht. Es ist klar, dass die Graphen nur von x = -10 bis x = 10 gehen, denn so habe ich es programmiert. Aber hat man die Möglichkeit, die Grafik so zu verändern, dass die x-Achse nur von x=-9 bis x=9 (oder so ähnlich) gezeichnet wird? Ich habe im Objektinspektor die Eigenschaft "Range" gefunden, bei der man den minimalen und den maximalen Wert eingeben kann und noch Sub-Eigenschaften, "UseMin" und "UseMax", die ich auf "True" gesetzt habe. Dann sehe ich in der Formularansicht auch, dass sich der Bereich der x-Achse verändert. Aber wenn ich das Programm ausführe und mir die Graphen anzeigen lasse, dann hat man wieder eine x-Achse wie im Anhang mit einem Bereich von x=-10,... bis x=10,...

Gibt es andersherum auch die Möglichkeit, den Bereich der x-Achse zu vergrößern, in meinem Beispiel also etwas wie von x=-12 bis x=12?
Dateianhänge
delphiGraph.png

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

Wenn ich den Bereich der Achsen verändern will, nehme ich üblicherweise Chart.Extent (Axis.Range schränkt den beschrifteten Bereich bei mehrfachen Achsen ein).

Deine andere Anfrage wegen der Balken ist ganz schön verwirrend: einmal sollen die Balken unterschiedlich breit sein, einmal gleich... Mit dem Punkt "breiter als 1" meinst du wahrscheinlich nicht, dass die Balken überlappen sollen, sondern auf der x-Achse z.B. zwei Achsen-Einheiten breit sein sollen. Das hat nichts mit TAChart zu tun, sondern wie du die Rohdaten in Gruppen einteilst. Insbesondere ist bei konstanter Balkenbreite die BarSeries ausreichend.

Hier ein Beispiel, wie du es meinen könntest. Es werden 1000 ganzzahlige Zufallszahlen zwischen 0 und 10 erzeugt, und es wird gezählt, wieviele davon in die Intervalle zwischen 0 und 2, 2 und 4, 4 und 6, 6 und 8, 8 und 10 fallen. Das Beispiel verwendet ein einfaches Formular mit Chart und BarSeries, sowie folgendem Code im FormCreate Event. Der Code ist so allgemein, dass du einfach die Intervallbreite, sowie den durch die Zufallszahlen überstrichenen Bereich ändern kannst:

Code: Alles auswählen

 
procedure TForm1.FormCreate(Sender: TObject);
const
  INTERVAL = 2;
  MIN = 0;
  MAX = 10;
var
  i: Integer;
  RandomData: Array[1..1000] of Integer;
  Counters: Array of Integer;
  CounterIndex: Integer;
begin
  // 1000 ganzzahlige Zufallszahlen zwischen MIN und MAX erzeugen
  for i:=Low(RandomData) to High(RandomData) do
    RandomData[i] := MIN + random(MAX-MIN);
 
  // Zufallszahlen in Gruppen einsortieren: 1.Gruppe MIN ... MIN+INTERVAL,
  // 2.Gruppe MIN+INTERVAL ... MIN+2*INTERVAL, etc.
  // BITTE VERSUCHE, DIESEN TEIL ZU VERSTEHEN!
  SetLength(Counters, Round((MAX - MIN) / INTERVAL));
  for i:=Low(RandomData) to High(RandomData) do
  begin
    CounterIndex := trunc((RandomData[i] - MIN) / INTERVAL);
    inc(Counters[CounterIndex]);
  end;
 
  // Das Array Counters in die BarSeries übertragen
  for i:=0 to High(Counters) do
    Chart1BarSeries1.AddXY(MIN+(i+0.5)*INTERVAL, Counters[i]);
    // VERSUCHE ZU VERSTEHEN, WARUM HIER +0.5 STEHT.
 
  // Aneinander angrenzende Balken
  Chart1BarSeries1.BarWidthPercent := 100;
end;                        

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

Deine andere Anfrage wegen der Balken ist ganz schön verwirrend: einmal sollen die Balken unterschiedlich breit sein, einmal gleich...
Wahrscheinlich habe ich mich nur undeutlich ausgedrückt. Ich wollte in meinem ersten Beitrag schon sagen, dass die Balken gleiche Breite haben:
so dass z. B. Werte von 0-2 in einen Balken bei 1, die Werte 2-4 in einen Balken bei 3 usw. gespeichert werden
Hier ein Beispiel, wie du es meinen könntest. [...]
Nur um zu überprüfen, ob ich es richtig verstehe: Die Balkenbreite bei TChart wird automatisch an den x-Abstand der Datenpunkte angepasst. Sehe ich das richtig? Ich hätte nämlich einen Befehl wie BarSeries.SetBarWidth(...) erwartet.

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

TBarSeries funktioniert so: Es gibt einen Satz von Datenpunkten (x,y). Nehmen wir an, dass die x-Werte äquidistant sind. Dann wird an jedem x-Wert ein Balken gezeichnet, genauer: die Balkenmitte liegt bei x. Die Balkenbreite definiert sich über BarWidthPercent: Ist das 100 (%), reicht der Balken links bis zur Hälfte des Abstands zum vorigen x[i-1], und nach rechts bis zur Hälfte des Abstands zum nächsten Datenpunkt x[i+1]. Insgesamt ist die Balkenbreite so groß wie der x-Abstand (x[i+1] - x = x - x[i-1]). Wäre BarWidthPercent 50, würde ein Balken 25% des Abstands nach links und 25% nach rechts reichen, insgesamt wären die Breite dann 50% des x-Abstands. (Wie weiter oben erwähnt, ist es komplizierter, wenn die x-Werte unterschiedlichen Abstand haben.) Sollen sich berührende Balken von x=0 bis x=2 und von x=2 bis x=4 erstrecken, muss man Datenpunkte bei x=1 (die Mitte des 1.Balkens) und x=3 (die Mitte des 2.Balkens) setzten, und BarWidthPercent muss 100 sein. Die Balkenbreite (in Achseneinheiten) entspricht daher dem Abstand der x-Werte (bei äquidistanten Werten).

In meinem Code sind alle Daten >= 0 und <2 im 0.Element des Arrays Counters gezählt, die Daten >=2 und <4 sind im 1.Element, etc. Um den Array-Index in einen x-Wert an der Balkenmitte zu verwandeln, muss also der Array-Index 0 zu x=1, der Index 1 zu x=3 werden. Dies kann man machen, indem man den Index mit dem x-Intervall (2) multipliziert und das halbe Intervall addiert, also x = index*INTERVAL + 0.5*INTERVAL = (index+0.5)*INTERVAL

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

Danke für die Ausführungen und für deine Hilfe. Ich denke, ich habe es schon richtig verstanden.

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

Jetzt muss ich mich noch einmal melden. Dieses Mal geht es um das Löschen der Daten aus einer BarSeries. Du hast dafür (weiter oben) den Befehl

BarSeries.Clear

verwendet. So habe ich es in meinem Programm auch gemacht. Allerdings wird dabei bei mir in manchen Fällen eine Exception mit folgender Meldung ausgelöst:
Projekt Projektname hat Exception-Klasse >>External: SIGSEGV<< ausgelöst.

Bei Adresse 77338E19
Dass es am Befehl BarSeries.Clear liegt, habe ich herausgefunden, indem ich mir einmal vor und einmal nach dem Befehl eine Message ausgeben lasse. Ich poste mal den relevanten Quelltext:

Code: Alles auswählen

 
type
  TDoubleArray = Array of Double;
 
...
 
(******************************************************************************)
function evaluate(const k: Integer; const exp: Integer; const INTERVAL: Double): TDoubleArray;
(******************************************************************************)
 
...
 
(******************************************************************************)
procedure TForm1.BtnStartClick(Sender: TObject);
(******************************************************************************)
 
var
  i: Integer; // Iterator
  k: Integer; // Number of random numbers
  exp: Integer; // Number of experiments
  interval: Double;
  ChartArray: TDoubleArray; // Array with y-Values for the Chart
  min: Double;
 
begin
  SBarRndNumbers.Enabled := false;
  SBarNumberExperiments.Enabled := false;
  k := SBarRndNumbers.Position;
  exp := SBarNumberExperiments.Position;
  interval := 5;
  ChartArray := evaluate(k, exp, interval);
  min := ChartArray[High(ChartArray)];
  BarSeries.Clear; // HIER WIRD IN MANCHEN FÄLLEN DIE EXCEPTION AUSGELÖST
  i := 1;
  for i:=1 to High(ChartArray)-1 do
  begin
    // add datapoints to BarSeries
    BarSeries.AddXY((i-0.5)*interval + min, ChartArray[i]);
  end;
  SBarRndNumbers.Enabled := true;
  SBarNumberExperiments.Enabled := true;
 
end; 
Ich hatte diese Exception schon einmal, als ich versehentlich durch 0 geteilt habe, aber daran kann es hier wohl kaum liegen. Hast du eine Idee, woran es liegen könnte, dass die Exception ausgelöst wird? Oder habe ich noch nicht genügend Informationen gepostet?

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

Ferndiagnose ohne das ganze Programm ist natürlich schwierig, aber BarSeries.Clear ist es definitiv nicht, das löscht nur die interne Datenliste. Ich denke, dass du BarSeries auch irgendwo außerhalb dieser Routine verwendest, wo dann der Fehler erzeugt wird. Durchsuche einmal alle Programmunits nach "BarSeries" ("Suchen" / "In Dateien suchen") und schau dir jede Fundstelle an, was da genau passiert.

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Daten in TChart hinzufügen

Beitrag von Scurra »

Ich verwende es nur in diesem Teil. Ich schreibe einfach mal das ganze Programm (ist ja nicht sehr komplex):

Datei unit1.pas:

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, TAGraph, TASeries, Forms, Controls, Graphics,
  Dialogs, StdCtrls;
 
type
 
  TDoubleArray = Array of Double;
 
  { TForm1 }
 
  TForm1 = class(TForm)
    BtnStart: TButton;
    BtnDefault: TButton;
    BtnQuit: TButton;
    Chart1: TChart;
    BarSeries: TBarSeries;
    LblRndNumbers: TLabel;
    LblNumberExperiments: TLabel;
    SBarRndNumbers: TScrollBar;
    SBarNumberExperiments: TScrollBar;
    procedure BtnDefaultClick(Sender: TObject);
    procedure BtnQuitClick(Sender: TObject);
    procedure BtnStartClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure SBarNumberExperimentsChange(Sender: TObject);
    procedure SBarRndNumbersChange(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
(******************************************************************************)
function evaluate(const k: Integer; const exp: Integer; const INTERVAL: Double): TDoubleArray;
(******************************************************************************)
 
const
  EXPECTATION = 49.5;
 
var
  // Iterators
  iterExp: Integer;
  iterNbr: Integer;
  x: Integer;
 
  // variables for calculations
  sum: Integer;
  variance: Double;
  index: Integer;
 
  min: Double; // minimum of stdRndVar
  max: Double; // maximum of stdRndVar
 
 
  // Arrays
  stdRndVarArrayTmp: Array of Double; // Unsorted values of stdRndVar
  stdRndVarArray: Array of Double; // Sorted values of stdRndVar
 
 
begin
 
  // Initial calculations
  // Variance
  variance := 0;
  x := 0;
  for x:=0 to 100 do
  begin
    variance := variance + sqr(x-EXPECTATION)/100.0;
  end;
 
  // Main part
  SetLength(stdRndVarArrayTmp, exp);
  Randomize;
  iterExp := 1;
  for iterExp:=1 to exp do
  begin
    sum := 0;
 
    iterNbr := 1;
    for iterNbr:=1 to k do
    begin
      sum := sum + Round(random(100));
    end;
    if(variance = 0)
    then begin
      ShowMessage('Variance = 0');
    end;
    stdRndVarArrayTmp[iterExp] := (sum -k*EXPECTATION)/sqrt(variance);
  end;
 
  // find min and max value of stdRndVar to define the intervals for Chart
  min := stdRndVarArrayTmp[1];
  max := stdRndVarArrayTmp[1];
  iterExp := 2;
  for iterExp:=2 to exp do
  begin
    if (stdRndVarArrayTmp[iterExp] < min)
    then begin
      min := stdRndVarArrayTmp[iterExp];
    end;
    if (stdRndVarArrayTmp[iterExp] > max)
    then begin
      max := stdRndVarArrayTmp[iterExp];
    end;
  end;
 
  // create sorted array
  SetLength(stdRndVarArray, Round((max-min)/INTERVAL+1)); // +1 to save min
  stdRndVarArray[High(stdRndVarArray)] := min;
 
  iterExp := 1;
  for iterExp:=1 to exp do
  begin
    index := Trunc((stdRndVarArrayTmp[iterExp]-min)/INTERVAL +1); // +1 such that index >= 1
    stdRndVarArray[index] := stdRndVarArray[index] + 1;
  end;
 
  result:= stdRndVarArray;
 
end;
 
 
(******************************************************************************)
procedure TForm1.BtnDefaultClick(Sender: TObject);
(******************************************************************************)
 
begin
  SBarRndNumbers.Position := 500;
  SBarNumberExperiments.Position := 100;
end;
 
 
(******************************************************************************)
procedure TForm1.BtnQuitClick(Sender: TObject);
(******************************************************************************)
 
begin
  Application.Terminate;
end;
 
(******************************************************************************)
procedure TForm1.BtnStartClick(Sender: TObject);
(******************************************************************************)
 
var
  i: Integer; // Iterator
  k: Integer; // Number of random numbers
  exp: Integer; // Number of experiments
  interval: Double;
  ChartArray: TDoubleArray; //array of Double; // Array with y-Values for the Chart
  min: Double;
 
begin
  SBarRndNumbers.Enabled := false;
  SBarNumberExperiments.Enabled := false;
  k := SBarRndNumbers.Position;
  exp := SBarNumberExperiments.Position;
  interval := 5;
  ChartArray := evaluate(k, exp, interval);
  min := ChartArray[High(ChartArray)];
  BarSeries.Clear;
  i := 1;
  for i:=1 to High(ChartArray)-1 do
  begin
    // add datapoints to BarSeries
    BarSeries.AddXY((i-0.5)*interval + min, ChartArray[i]);
  end;
  SBarRndNumbers.Enabled := true;
  SBarNumberExperiments.Enabled := true;
 
end;
 
(******************************************************************************)
procedure TForm1.FormShow(Sender: TObject);
(******************************************************************************)
 
begin
  SBarRndNumbers.Position := 500;
  SBarNumberExperiments.Position := 100;
  LblNumberExperiments.Caption := 'Experiments: ' +
                                  IntToStr(SBarNumberExperiments.Position);
  LblRndNumbers.Caption := 'Random numbers: ' +
                           IntToStr(SBarRndNumbers.Position);
end;
 
(******************************************************************************)
procedure TForm1.SBarNumberExperimentsChange(Sender: TObject);
(******************************************************************************)
 
begin
  LblNumberExperiments.Caption := 'Experiments: ' +
                                  IntToStr(SBarNumberExperiments.Position);
end;
 
(******************************************************************************)
procedure TForm1.SBarRndNumbersChange(Sender: TObject);
(******************************************************************************)
 
begin
  LblRndNumbers.Caption := 'Random numbers: ' +
                           IntToStr(SBarRndNumbers.Position);
end;
 
 
 
 
// Main program
begin
 
end.
 
Die Datei unit1.lfm habe ich als Anhang hochgeladen, da im Forum immer ein Fehler erschien, wenn ich es geschrieben habe. Außerdem habe ich noch die Datei fehlermeldung.lpr hochgeladen. Habe ich noch wichtige Dateien vergessen?

Der Fehler tritt manchmal auf, wenn ich auf den "Start"-Button klicke. Meistens erst, nachdem ich die Prozedur schon ein paar mal gemacht habe (z. B. ca. 10 Mal auf den Start-Button klicken). Da der Fehler nicht immer auftritt, manchmal schon nach 3 Mal auf den Start-Button klicken, manchmal auch später, vermute ich, dass es mit den Zufallszahlen zusammenhängen könnte, die ich mir erzeugt habe.

Aber bei der Suche nach dem Fehler habe ich mir - wie oben schon geschrieben - Fenster mit Textnachrichten erscheinen lassen. Einmal unmittelbar vor der Zeile "BarSeries.Clear;" und einmal unmittelbar danach. Im ersten Fall musste ich immer noch die Textmeldung wegklicken, bevor die Exception ausgelöst wurde, im zweiten Fall wurde die Textnachricht gar nicht mehr angezeigt, weil vorher schon die Exception ausgelöst wurde. Deshalb ist meine Vermutung eben, dass es mit BarSeries.Clear zusammen hängt.
Dateianhänge
unit1.lfm
(1.98 KiB) 81-mal heruntergeladen
fehlermeldung.lpr
(406 Bytes) 75-mal heruntergeladen

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

Re: Daten in TChart hinzufügen

Beitrag von wp_xyz »

Ich habe jetzt deine "evaluate"-Routine im Detail nicht durchgearbeitet, aber folgendes ist auffällig:
  • "IterExp" als Index in ein dynamisches Array beginnt bei 1. Das ist falsch. Die Indices in dynamischen Arrays beginnen immer mit 0. Da du das Arrayelement mit dem Index 0 nicht beschreibst, steht da Blödsinn, und es könnte sein, dass dadurch der Absturz entsteht.
  • Dasselbe in BtnStartClick: hier beginnt i ebenfalls bei 1; auch die obere Grenze, High(ChartArray)-1, erscheint mir falsch: warum -1? Die Schleife muss doch nur alle Werte im ChartArray durchlaufen, und das geht von 0 bis High(ChartArray) (oder Length(ChartArray)-1).
  • Und was soll "min := ChartArray[High(ChartArray)]"? "min" und "High" erscheint mir ein Widerspruch...
Generelle Bemerkungen noch:
  • Bei "Application.Terminate" in einem GUI-Programm bekomme ich Bauchweh... Kann sein, dass das richtig ist, aber ich rufe lieber "Close" im Hauptformular auf, damit alles richtig heruntergefahren wird.
  • Das "begin" vor dem abschließenden "end." ist ungewöhnlich und habe ich in Units noch nie gesehen.
  • Du wiederholst den ersten Wert der Schleifen-Variablen vor der Schleife: "i:=1; for i:=1 to ..." Das ist unnötig.
Ach ja noch: Du erleichterst den Leuten hier im Forum, die deinen Code prüfen wollen, die Arbeit, indem du von dem kompletten Projekt die .lpi, .lpr, .pas und .lfm-Dateien in ein zip-Archiv packst und dieses hochlädst. Die zip-Endung wird von der Forums-Software akzeptiert. Dann kann man gleich loslegen und muss nicht erst ein Projekt erzeugen. Und auch in den lpr/lpi-Dateien können Fehler stecken.

Antworten