unit main; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, Spin, Grids, TAGraph, TASources, TASeries, TAChartListbox, TAFuncSeries, TAChartCombos, TACustomSource; type { TMainForm } TMainForm = class(TForm) CbYErrDifferent: TCheckBox; CbYErrShow: TCheckBox; Chart1: TChart; Chart1BSplineSeries1: TBSplineSeries; Chart1CubicSplineSeries1: TCubicSplineSeries; Chart1FitSeries1: TFitSeries; Chart1LineSeries1: TLineSeries; CbRotated: TCheckBox; CbErrPenStyle: TChartComboBox; ChartListbox1: TChartListbox; CbXErrShow: TCheckBox; CbXErrDifferent: TCheckBox; EdXErrConst: TFloatSpinEdit; EdYErrConst: TFloatSpinEdit; EdXErrPercent: TFloatSpinEdit; EdYErrPercent: TFloatSpinEdit; GbXErr: TGroupBox; GbYErr: TGroupBox; GbErrorBarStyle: TGroupBox; Label1: TLabel; LblErrLineWidth: TLabel; ListChartSource1: TListChartSource; Panel1: TPanel; RgChartSource: TRadioGroup; RbYErrChartSource: TRadioButton; RbXErrConst: TRadioButton; RbYErrConst: TRadioButton; RbXErrPercent: TRadioButton; RbXErrChartSource: TRadioButton; RandomChartSource1: TRandomChartSource; RbYErrPercent: TRadioButton; EdErrPenWidth: TSpinEdit; StringGrid1: TStringGrid; UserDefinedChartSource1: TUserDefinedChartSource; procedure CbErrPenStyleChange(Sender: TObject); procedure CbRotatedChange(Sender: TObject); procedure CbXErrShowChange(Sender: TObject); procedure CbYErrShowChange(Sender: TObject); procedure CbXErrDifferentChange(Sender: TObject); procedure CbYErrDifferentChange(Sender: TObject); procedure Chart1AfterPaint(ASender: TChart); procedure EdErrPenWidthChange(Sender: TObject); procedure EdXErrConstChange(Sender: TObject); procedure EdYErrConstChange(Sender: TObject); procedure EdXErrPercentChange(Sender: TObject); procedure EdYErrPercentChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure RbXErrConstChange(Sender: TObject); procedure RbYErrConstChange(Sender: TObject); procedure RbXErrPercentChange(Sender: TObject); procedure RbYErrPercentChange(Sender: TObject); procedure RbXErrChartSourceChange(Sender: TObject); procedure RbYErrChartSourceChange(Sender: TObject); procedure RgChartSourceClick(Sender: TObject); procedure StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer; aState: TGridDrawState); procedure UserDefinedChartSource1GetChartDataItem( ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem); private procedure PopulateListSource; procedure PopulateUserData; procedure SetXErrorBarParams; procedure SetYErrorBarParams; public end; var MainForm: TMainForm; implementation {$R *.lfm} uses Math; type TDataRec = record x, y, dxp, dxn, dyp, dyn: Double; end; var Data: array of TDataRec; type TMySource = class(TCustomChartSource) public property XErrorBarData; property YErrorBarData; end; { TMainForm } procedure TMainForm.CbRotatedChange(Sender: TObject); begin if CbRotated.Checked then begin Chart1LineSeries1.AxisIndexX := 0; Chart1LineSeries1.AxisIndexY := 1; end else begin Chart1LineSeries1.AxisIndexX := 1; Chart1LineSeries1.AxisIndexY := 0; end; Chart1BSplineSeries1.AxisIndexX := Chart1lineSeries1.AxisIndexX; Chart1BSplineSeries1.AxisIndexY := Chart1LineSeries1.AxisIndexY; Chart1CubicSplineSeries1.AxisIndexX := Chart1lineSeries1.AxisIndexX; Chart1CubicSplineSeries1.AxisIndexY := Chart1LineSeries1.AxisIndexY; Chart1FitSeries1.AxisIndexX := Chart1lineSeries1.AxisIndexX; Chart1FitSeries1.AxisIndexY := Chart1LineSeries1.AxisIndexY; end; procedure TMainForm.CbXErrShowChange(Sender: TObject); begin Chart1LineSeries1.XErrorBars.Visible := CbXErrShow.Checked; Chart1BSplineSeries1.XErrorBars.Visible := CbXErrShow.Checked; Chart1CubicSplineSeries1.XErrorBars.Visible := CbXErrShow.Checked; Chart1FitSeries1.XErrorBars.Visible := CbXErrShow.Checked; end; procedure TMainForm.CbXErrDifferentChange(Sender: TObject); begin SetXErrorBarParams; end; procedure TMainForm.CbYErrDifferentChange(Sender: TObject); begin SetYErrorBarParams; end; procedure TMainForm.CbYErrShowChange(Sender: TObject); begin Chart1LineSeries1.YErrorBars.Visible := CbYErrShow.Checked; Chart1BSplineSeries1.YErrorBars.Visible := CbYErrShow.Checked; Chart1CubicSplineSeries1.YErrorBars.Visible := CbYErrShow.Checked; Chart1FitSeries1.YErrorBars.Visible := CbYErrShow.Checked; end; procedure TMainForm.Chart1AfterPaint(ASender: TChart); const EPS = 1E-9; var i: Integer; src: TCustomChartSource; x, y, dxp, dxn, dyp, dyn: Double; fx, fy: Double; sp, sn: String; begin src := Chart1LineSeries1.Source; StringGrid1.RowCount := src.Count + 1; fx := EdXErrPercent.Value * 0.01; fy := EdYErrPercent.Value * 0.01; for i:=1 to StringGrid1.RowCount-1 do begin x := src.Item[i-1]^.X; y := src.Item[i-1]^.Y; src.GetXErrorBarValues(i-1, dxp, dxn); src.GetYErrorBarValues(i-1, dyp, dyn); StringGrid1.Cells[0, i] := Format('%.3f', [x]); StringGrid1.Cells[1, i] := Format('%.3f', [y]); if (dxp = 0) and (dxn = 0) then StringGrid1.Cells[2, i] := '' else if SameValue(dxp, dxn, EPS) then StringGrid1.Cells[2, i] := Format('±%.3f', [dxp]) else StringGrid1.Cells[2, i] := Format('+%.2f/-%.2f', [dxp, dxn]); if (dyp = 0) and (dyn = 0) then StringGrid1.Cells[3, i] := '' else if SameValue(dyp, dyn, EPS) then StringGrid1.Cells[3, i] := Format('±%.3f', [dyp]) else StringGrid1.Cells[3, i] := Format('+%.2f/-%.2f', [dyp, dyn]); end; end; procedure TMainForm.CbErrPenStyleChange(Sender: TObject); begin Chart1LineSeries1.XErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1BSplineSeries1.XErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1CubicSplineSeries1.XErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1FitSeries1.XErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1LineSeries1.YErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1BSplineSeries1.YErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1CubicSplineSeries1.YErrorBars.Pen.Style := CbErrPenStyle.PenStyle; Chart1FitSeries1.YErrorBars.Pen.Style := CbErrPenStyle.PenStyle; end; procedure TMainForm.EdXErrConstChange(Sender: TObject); begin SetXErrorBarParams; end; procedure TMainForm.EdErrPenWidthChange(Sender: TObject); begin Chart1LineSeries1.XErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1BSplineSeries1.XErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1CubicSplineSeries1.XErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1FitSeries1.XErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1LineSeries1.YErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1BSplineSeries1.YErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1CubicSplineSeries1.YErrorBars.Pen.Width := EdErrPenWidth.Value; Chart1FitSeries1.YErrorBars.Pen.Width := EdErrPenWidth.Value; end; procedure TMainForm.StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer; aState: TGridDrawState); var ts: TTextStyle; begin ts := StringGrid1.Canvas.TextStyle; ts.Alignment := taCenter; StringGrid1.Canvas.TextStyle := ts; end; procedure TMainForm.UserDefinedChartSource1GetChartDataItem( ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem); begin AItem.X := Data[AIndex].X; AItem.Y := Data[AIndex].Y; if ASource.XCount > 1 then AItem.XList[0] := Data[AIndex].dxp; if ASource.XCount > 2 then AItem.XList[1] := Data[AIndex].dxn; if ASource.YCount > 1 then AItem.YList[0] := Data[AIndex].dyp; if ASource.YCount > 2 then AItem.YList[1] := Data[AIndex].dyn; end; procedure TMainForm.EdXErrPercentChange(Sender: TObject); begin SetXErrorBarParams; end; procedure TMainForm.EdYErrConstChange(Sender: TObject); begin SetYErrorBarParams; end; procedure TMainForm.EdYErrPercentChange(Sender: TObject); begin SetYErrorBarParams; end; procedure TMainForm.FormCreate(Sender: TObject); begin PopulateUserData; end; procedure TMainForm.PopulateListSource; const N = 10; XMIN = 0; XMAX = 10; var i: Integer; x, y: Double; idx: Integer; fx, fy: Double; begin RandSeed := 1; fx := EdXErrPercent.Value * 0.01 * (XMAX - XMIN); fy := EdYErrPercent.Value * 0.01 * (XMAX - XMIN); ListChartSource1.Clear; // ListChartSource1.XCount := IfThen(CbXErrShow.Checked and RbXErrChartSource.Checked, 2, 1); // ListChartSource1.YCount := IfThen(CbYErrShow.Checked and RbYErrChartSource.Checked, 2, 1); ListChartSource1.BeginUpdate; try for i:=0 to N-1 do begin x := XMIN + (XMAX - XMIN) * i / (N-1); y := sqr(x - 5) / 2.5 + (random*2 - 1) * 0.5; idx := ListChartSource1.Add(x, y); if ListChartSource1.XCount > 1 then ListChartSource1.Item[idx]^.SetX(1, random * fx); if ListChartSource1.XCount > 2 then ListChartSource1.Item[idx]^.SetX(2, random * fx); if ListChartSource1.YCount > 1 then ListChartSource1.Item[idx]^.SetY(1, random * fy); if ListChartSource1.YCount > 2 then ListChartSource1.Item[idx]^.SetY(2, random * fy); end; finally ListChartSource1.EndUpdate; end; end; procedure TMainForm.PopulateUserData; const N = 10; XMIN = 0; XMAX = 10; var i: Integer; x, y: Double; fx, fy: Double; begin RandSeed := 2; fx := EdXErrConst.Value; fy := EdYErrConst.Value; SetLength(Data, N); for i := 0 to N - 1 do begin x := XMIN + (XMAX - XMIN) * i / (N-1); y := 10 - sqr(x - 5) / 2.5 + (random*2 - 1) * 0.5; Data[i].x := x; Data[i].y := y; Data[i].dxp := random*fx; Data[i].dxn := 0.5 * Data[i].dxp; Data[i].dyp := random * fy; Data[i].dyn := 0.5 * Data[i].dyp; end; UserDefinedChartSource1.PointsNumber := N; end; procedure TMainForm.RgChartSourceClick(Sender: TObject); var src: TCustomChartSource; begin case RgChartSource.ItemIndex of 0: begin Chart1LineSeries1.Source := RandomChartSource1; Chart1BSplineSeries1.Source := RandomChartSource1; Chart1CubicSplineSeries1.Source := RandomChartSource1; Chart1FitSeries1.Source := RandomChartSource1; end; 1: begin Chart1LineSeries1.Source := ListChartSource1; Chart1BSplineSeries1.Source := ListChartSource1; Chart1CubicSplineSeries1.Source := ListChartSource1; Chart1FitSeries1.Source := ListChartSource1; end; 2: begin Chart1LineSeries1.Source := UserDefinedChartSource1; Chart1BSplineSeries1.Source := UserDefinedChartSource1; Chart1CubicSplineSeries1.Source := UserDefinedChartSource1; Chart1FitSeries1.Source := UserDefinedChartSource1; end; end; SetXErrorBarParams; SetYErrorBarParams; end; procedure TMainForm.RbXErrConstChange(Sender: TObject); begin EdXErrConst.Show; EdXErrPercent.Hide; SetXErrorBarParams; end; procedure TMainForm.RbYErrConstChange(Sender: TObject); begin EdYErrConst.Show; EdYErrPercent.Hide; SetYErrorBarParams; end; procedure TMainForm.RbXErrPercentChange(Sender: TObject); begin EdXErrConst.Hide; EdXErrPercent.Show; SetXErrorBarParams; end; procedure TMainForm.RbYErrPercentChange(Sender: TObject); begin EdYErrConst.Hide; EdYErrPercent.Show; SetYErrorBarParams; end; procedure TMainForm.RbXErrChartSourceChange(Sender: TObject); begin EdXErrConst.Hide; EdXErrPercent.Hide; SetXErrorBarParams; end; procedure TMainForm.RbYErrChartSourceChange(Sender: TObject); begin EdYErrConst.Hide; EdYErrPercent.Hide; SetYErrorBarParams; end; procedure TMainForm.SetXErrorBarParams; begin if RbXErrConst.Checked then with RandomChartSource1 do begin XErrorBarData.Kind := ebkConst; XErrorBarData.ValuePlus := EdXErrConst.Value; if CbXErrDifferent.Checked then XErrorBarData.ValueMinus := 0.5 * XErrorBarData.ValuePlus else XErrorBarData.ValueMinus := -1; XCount := 1; end else if RbXErrPercent.Checked then with RandomChartSource1 do begin XErrorBarData.Kind := ebkPercent; XErrorBarData.ValuePlus := EdXErrPercent.Value; if CbXErrDifferent.Checked then XErrorBarData.ValueMinus := 0.5 * XErrorBarData.ValuePlus else XErrorBarData.ValueMinus := -1; XCount := 1; end else if RbXErrChartSource.Checked then with RandomChartSource1 do begin XErrorBarData.Kind := ebkChartSource; XErrorBarData.ValuePlus := 20; // 20% of X extent XErrorBarData.IndexPlus := 1; if CbXErrDifferent.Checked then begin XErrorBarData.IndexMinus := 2; XErrorBarData.ValueMinus := XErrorBarData.ValuePlus; XCount := 3; end else begin XErrorBarData.IndexMinus := -1; XErrorBarData.ValueMinus := -1; XCount := 2; end; end else exit; ListChartSource1.XErrorBarData.Assign(RandomChartSource1.XErrorBarData); ListChartSource1.XCount := RandomChartSource1.XCount; PopulateListSource; UserDefinedChartSource1.XErrorBarData.Assign(RandomChartSource1.XErrorBarData); UserDefinedChartSource1.XCount := RandomChartSource1.XCount; UserDefinedChartSource1.Reset; end; procedure TMainForm.SetYErrorBarParams; begin if RbYErrConst.Checked then with RandomChartSource1 do begin YErrorBarData.Kind := ebkConst; YErrorBarData.ValuePlus := EdYErrConst.Value; if CbYErrDifferent.Checked then YErrorBarData.ValueMinus := 0.5 * YErrorBarData.ValuePlus else YErrorBarData.ValueMinus := -1; YCount := 1; end else if RbYErrPercent.Checked then with RandomChartSource1 do begin YErrorBarData.Kind := ebkPercent; YErrorBarData.ValuePlus := EdYErrPercent.Value; if CbYErrDifferent.Checked then YErrorBarData.ValueMinus := 0.5 * YErrorBarData.ValuePlus else YErrorBarData.ValueMinus := -1; YCount := 1; end else if RbYErrChartSource.Checked then with RandomChartSource1 do begin YErrorBarData.Kind := ebkChartSource; YErrorBarData.ValuePlus := 20; // 20% of X extent YErrorBarData.IndexPlus := 1; if CbYErrDifferent.Checked then begin YErrorBarData.IndexMinus := 2; YErrorBarData.ValueMinus := YErrorBarData.ValuePlus; YCount := 3; end else begin YErrorBarData.IndexMinus := -1; YErrorBarData.ValueMinus := -1; YCount := 2; end end else exit; ListChartSource1.YErrorBarData.Assign(RandomChartSource1.YErrorBarData); ListChartSource1.YCount := RandomChartSource1.YCount; PopulateListSource; UserDefinedChartSource1.YErrorBarData.Assign(RandomChartSource1.YErrorBarData); UserDefinedChartSource1.YCount := RandomChartSource1.YCount; UserDefinedChartSource1.Reset; end; end.