From f0006708479000585ab660c0af1a7db31aaebffb Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 28 Oct 2020 19:01:05 +0000 Subject: [PATCH] LazStats: Inherit CaplanMeierUnit from TBasicStatsReportAndChartForm. Replace hand-made chart by TAChart. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7822 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- applications/lazstats/source/LazStats.lpi | 4 +- .../analysis/nonparametric/exactunit.lfm | 2 +- .../analysis/nonparametric/exactunit.pas | 38 +- .../nonparametric/kaplanmeierunit.lfm | 374 ++++------ .../nonparametric/kaplanmeierunit.pas | 653 ++++++++++-------- .../lazstats/source/forms/mainunit.pas | 31 +- .../lazstats/source/frames/chartframeunit.pas | 20 +- 7 files changed, 554 insertions(+), 568 deletions(-) diff --git a/applications/lazstats/source/LazStats.lpi b/applications/lazstats/source/LazStats.lpi index b2416e923..5abfc0e2c 100644 --- a/applications/lazstats/source/LazStats.lpi +++ b/applications/lazstats/source/LazStats.lpi @@ -729,7 +729,7 @@ - + @@ -801,7 +801,7 @@ - + diff --git a/applications/lazstats/source/forms/analysis/nonparametric/exactunit.lfm b/applications/lazstats/source/forms/analysis/nonparametric/exactunit.lfm index e0e375ac2..483848bc2 100644 --- a/applications/lazstats/source/forms/analysis/nonparametric/exactunit.lfm +++ b/applications/lazstats/source/forms/analysis/nonparametric/exactunit.lfm @@ -1,4 +1,4 @@ -inherited FisherFrm: TFisherFrm +inherited FisherForm: TFisherForm Left = 535 Height = 524 Top = 234 diff --git a/applications/lazstats/source/forms/analysis/nonparametric/exactunit.pas b/applications/lazstats/source/forms/analysis/nonparametric/exactunit.pas index db9afcdd7..0308a9798 100644 --- a/applications/lazstats/source/forms/analysis/nonparametric/exactunit.pas +++ b/applications/lazstats/source/forms/analysis/nonparametric/exactunit.pas @@ -11,9 +11,9 @@ uses type - { TFisherFrm } + { TFisherForm } - TFisherFrm = class(TBasicStatsReportForm) + TFisherForm = class(TBasicStatsReportForm) AlphaEdit: TEdit; Label2: TLabel; Label5: TLabel; @@ -70,7 +70,7 @@ type end; var - FisherFrm: TFisherFrm; + FisherForm: TFisherForm; implementation @@ -81,9 +81,9 @@ uses Utils, GridProcs; -{ TFisherFrm } +{ TFisherForm } -procedure TFisherFrm.AdjustConstraints; +procedure TFisherForm.AdjustConstraints; begin inherited; ParamsPanel.Constraints.MinWidth := InputGrp.Width; @@ -94,7 +94,7 @@ begin end; -procedure TFisherFrm.ColInClick(Sender: TObject); +procedure TFisherForm.ColInClick(Sender: TObject); var index: integer; begin @@ -108,7 +108,7 @@ begin end; -procedure TFisherFrm.ColOutClick(Sender: TObject); +procedure TFisherForm.ColOutClick(Sender: TObject); begin if ColEdit.Text <> '' then begin @@ -119,7 +119,7 @@ begin end; -procedure TFisherFrm.Compute; +procedure TFisherForm.Compute; var i, j, row, col, caseRow, caseCol, A, B, C, D, largest: integer; N, APlusB, APlusC, BPlusD, CPlusD, NoSelected, dep: integer; @@ -337,7 +337,7 @@ begin end; -procedure TFisherFrm.DepInClick(Sender: TObject); +procedure TFisherForm.DepInClick(Sender: TObject); var index: integer; begin @@ -351,7 +351,7 @@ begin end; -procedure TFisherFrm.DepOutClick(Sender: TObject); +procedure TFisherForm.DepOutClick(Sender: TObject); begin if DepEdit.Text <> '' then begin @@ -362,7 +362,7 @@ begin end; -procedure TFisherFrm.InputGrpClick(Sender: TObject); +procedure TFisherForm.InputGrpClick(Sender: TObject); begin if InputGrp.ItemIndex = 3 then begin @@ -405,7 +405,7 @@ begin end; -procedure TFisherFrm.PrintFisherTable(AList: TStrings; +procedure TFisherForm.PrintFisherTable(AList: TStrings; A, B, C, D: integer; P, SumP: double); begin AList.Add('Contingency Table for Fisher Exact Test'); @@ -420,7 +420,7 @@ begin end; -procedure TFisherFrm.Reset; +procedure TFisherForm.Reset; var i: integer; begin @@ -452,7 +452,7 @@ begin end; -procedure TFisherFrm.RowInClick(Sender: TObject); +procedure TFisherForm.RowInClick(Sender: TObject); var index: integer; begin @@ -466,7 +466,7 @@ begin end; -procedure TFisherFrm.RowOutClick(Sender: TObject); +procedure TFisherForm.RowOutClick(Sender: TObject); begin if RowEdit.Text <> '' then begin @@ -477,7 +477,7 @@ begin end; -function TFisherFrm.Validate(out AMsg: String; out AControl: TWinControl): boolean; +function TFisherForm.Validate(out AMsg: String; out AControl: TWinControl): boolean; var x: Double; n: Integer; @@ -530,7 +530,7 @@ begin end; -procedure TFisherFrm.VarListDblClick(Sender: TObject); +procedure TFisherForm.VarListDblClick(Sender: TObject); var index: Integer; s: String; @@ -551,13 +551,13 @@ begin end; -procedure TFisherFrm.VarListSelectionChange(Sender: TObject; User: boolean); +procedure TFisherForm.VarListSelectionChange(Sender: TObject; User: boolean); begin UpdateBtnStates; end; -procedure TFisherFrm.UpdateBtnStates; +procedure TFisherForm.UpdateBtnStates; begin inherited; diff --git a/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.lfm b/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.lfm index 098aee0c8..e955b9ee2 100644 --- a/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.lfm +++ b/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.lfm @@ -1,127 +1,42 @@ -object KaplanMeierFrm: TKaplanMeierFrm +inherited KaplanMeierForm: TKaplanMeierForm Left = 596 - Height = 406 + Height = 400 Top = 239 - Width = 505 + Width = 879 HelpType = htKeyword HelpKeyword = 'html/Kaplan-MeierSurvivalTest.htm' - AutoSize = True Caption = 'Kaplan-Meier Survival Analysis' - ClientHeight = 406 - ClientWidth = 505 - OnActivate = FormActivate - OnCreate = FormCreate - OnShow = FormShow - Position = poMainFormCenter - LCLVersion = '2.1.0.0' - object ResetBtn: TButton - AnchorSideRight.Control = ComputeBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 288 - Height = 25 - Top = 373 - Width = 54 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 8 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 - Caption = 'Reset' - OnClick = ResetBtnClick - TabOrder = 2 - end - object ComputeBtn: TButton - AnchorSideRight.Control = CloseBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 350 - Height = 25 - Top = 373 - Width = 76 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 8 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 - Caption = 'Compute' - OnClick = ComputeBtnClick - TabOrder = 3 - end - object CloseBtn: TButton - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 438 - Height = 25 - Top = 373 - Width = 55 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 12 - BorderSpacing.Top = 8 - BorderSpacing.Right = 12 - BorderSpacing.Bottom = 8 - Caption = 'Close' - ModalResult = 11 - TabOrder = 4 - end - object HelpBtn: TButton - Tag = 127 - AnchorSideRight.Control = ResetBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 229 - Height = 25 - Top = 373 - Width = 51 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 12 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 - Caption = 'Help' - OnClick = HelpBtnClick - TabOrder = 1 - end - object Bevel1: TBevel - AnchorSideLeft.Control = Owner - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = CloseBtn - Left = 0 - Height = 8 - Top = 357 - Width = 505 - Anchors = [akLeft, akRight, akBottom] - Shape = bsBottomLine - end - object Panel1: TPanel - AnchorSideLeft.Control = Owner - AnchorSideTop.Control = Owner - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = Bevel1 - Left = 8 - Height = 349 - Top = 8 - Width = 489 - Anchors = [akTop, akLeft, akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 8 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - BevelOuter = bvNone - ClientHeight = 349 - ClientWidth = 489 - TabOrder = 0 - object Label1: TLabel - AnchorSideLeft.Control = Panel1 - AnchorSideTop.Control = Panel1 + ClientHeight = 400 + ClientWidth = 879 + inherited ParamsPanel: TPanel + Height = 384 + Width = 363 + ClientHeight = 384 + ClientWidth = 363 + inherited CloseBtn: TButton + Left = 308 + Top = 359 + end + inherited ComputeBtn: TButton + Left = 224 + Top = 359 + end + inherited ResetBtn: TButton + Left = 162 + Top = 359 + end + inherited HelpBtn: TButton + Tag = 127 + Left = 103 + Top = 359 + end + inherited ButtonBevel: TBevel + Top = 343 + Width = 363 + end + object Label1: TLabel[5] + AnchorSideLeft.Control = ParamsPanel + AnchorSideTop.Control = ParamsPanel Left = 0 Height = 15 Top = 0 @@ -129,242 +44,219 @@ object KaplanMeierFrm: TKaplanMeierFrm Caption = 'Available Variables' ParentColor = False end - object Label2: TLabel - AnchorSideLeft.Control = TimeEdit - AnchorSideBottom.Control = TimeEdit - Left = 266 + object TimeVarLabel: TLabel[6] + AnchorSideLeft.Control = TimeVarEdit + AnchorSideBottom.Control = TimeVarEdit + Left = 201 Height = 15 - Top = 25 + Top = 133 Width = 70 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 2 Caption = 'Time Variable' ParentColor = False end - object Label3: TLabel - AnchorSideLeft.Control = EventEdit - AnchorSideBottom.Control = EventEdit - Left = 266 + object EventVarLabel: TLabel[7] + AnchorSideLeft.Control = EventVarEdit + AnchorSideBottom.Control = EventVarEdit + Left = 201 Height = 30 - Top = 108 + Top = 210 Width = 140 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 2 Caption = 'Event vs Censored Variable'#13#10'(Event = 1, Censored = 2)' ParentColor = False end - object Label5: TLabel - AnchorSideLeft.Control = GroupEdit - AnchorSideBottom.Control = GroupEdit - Left = 266 + object GroupVarLabel: TLabel[8] + AnchorSideLeft.Control = GroupVarEdit + AnchorSideBottom.Control = GroupVarEdit + Left = 201 Height = 30 - Top = 194 + Top = 42 Width = 160 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 2 Caption = 'Group Variable (if 2 groups)'#13#10'(Experimental = 1, Control =2)' ParentColor = False end - object VarList: TListBox - AnchorSideLeft.Control = Panel1 + object VarList: TListBox[9] + AnchorSideLeft.Control = ParamsPanel AnchorSideTop.Control = Label1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = TimeInBtn - AnchorSideBottom.Control = Panel1 - AnchorSideBottom.Side = asrBottom + AnchorSideBottom.Control = ButtonBevel Left = 0 - Height = 332 + Height = 326 Top = 17 - Width = 222 + Width = 161 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 2 - BorderSpacing.Right = 8 + BorderSpacing.Right = 6 ItemHeight = 0 + OnDblClick = VarListDblClick OnSelectionChange = VarListSelectionChange - TabOrder = 0 + TabOrder = 4 end - object TimeInBtn: TBitBtn - AnchorSideLeft.Control = Panel1 + object TimeInBtn: TBitBtn[10] + AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = VarList - Left = 230 + AnchorSideTop.Control = GroupOutBtn + AnchorSideTop.Side = asrBottom + Left = 167 Height = 28 - Top = 17 + Top = 125 Width = 28 + BorderSpacing.Top = 24 Images = MainDataModule.ImageList ImageIndex = 1 OnClick = TimeInBtnClick Spacing = 0 - TabOrder = 1 + TabOrder = 5 end - object TimeOutBtn: TBitBtn - AnchorSideLeft.Control = Panel1 + object TimeOutBtn: TBitBtn[11] + AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = TimeInBtn AnchorSideTop.Side = asrBottom - Left = 230 + Left = 167 Height = 28 - Top = 49 + Top = 157 Width = 28 BorderSpacing.Top = 4 Images = MainDataModule.ImageList ImageIndex = 0 OnClick = TimeOutBtnClick Spacing = 0 - TabOrder = 2 + TabOrder = 6 end - object EventInBtn: TBitBtn - AnchorSideLeft.Control = Panel1 + object EventInBtn: TBitBtn[12] + AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = TimeOutBtn AnchorSideTop.Side = asrBottom - Left = 230 + Left = 167 Height = 28 - Top = 105 + Top = 209 Width = 28 - BorderSpacing.Top = 28 + BorderSpacing.Top = 24 Images = MainDataModule.ImageList ImageIndex = 1 OnClick = EventInBtnClick Spacing = 0 - TabOrder = 4 + TabOrder = 7 end - object EventOutBtn: TBitBtn - AnchorSideLeft.Control = Panel1 + object EventOutBtn: TBitBtn[13] + AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = EventInBtn AnchorSideTop.Side = asrBottom - Left = 230 + Left = 167 Height = 28 - Top = 137 + Top = 241 Width = 28 BorderSpacing.Top = 4 Images = MainDataModule.ImageList ImageIndex = 0 OnClick = EventOutBtnClick Spacing = 0 - TabOrder = 5 + TabOrder = 8 end - object GroupInBtn: TBitBtn - AnchorSideLeft.Control = Panel1 + object GroupInBtn: TBitBtn[14] + AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = EventOutBtn - AnchorSideTop.Side = asrBottom - Left = 230 + AnchorSideTop.Control = VarList + Left = 167 Height = 28 - Top = 189 + Top = 41 Width = 28 BorderSpacing.Top = 24 Images = MainDataModule.ImageList ImageIndex = 1 OnClick = GroupInBtnClick Spacing = 0 - TabOrder = 7 + TabOrder = 9 end - object GroupOutBtn: TBitBtn - AnchorSideLeft.Control = Panel1 + object GroupOutBtn: TBitBtn[15] + AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = GroupInBtn AnchorSideTop.Side = asrBottom - Left = 230 + Left = 167 Height = 28 - Top = 221 + Top = 73 Width = 28 BorderSpacing.Top = 4 Images = MainDataModule.ImageList ImageIndex = 0 OnClick = GroupOutBtnClick Spacing = 0 - TabOrder = 8 + TabOrder = 10 end - object TimeEdit: TEdit + object TimeVarEdit: TEdit[16] AnchorSideLeft.Control = TimeInBtn AnchorSideLeft.Side = asrBottom - AnchorSideRight.Control = Panel1 + AnchorSideRight.Control = ParamsPanel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = TimeOutBtn AnchorSideBottom.Side = asrBottom - Left = 266 + Left = 201 Height = 23 - Top = 42 - Width = 223 + Top = 150 + Width = 162 Anchors = [akLeft, akRight, akBottom] - BorderSpacing.Left = 8 + BorderSpacing.Left = 6 BorderSpacing.Bottom = 12 - TabOrder = 3 - Text = 'TimeEdit' + TabOrder = 11 + Text = 'TimeVarEdit' end - object EventEdit: TEdit - AnchorSideLeft.Control = EventInBtn + object EventVarEdit: TEdit[17] + AnchorSideLeft.Control = GroupInBtn AnchorSideLeft.Side = asrBottom - AnchorSideRight.Control = Panel1 + AnchorSideRight.Control = ParamsPanel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = EventOutBtn AnchorSideBottom.Side = asrBottom - Left = 266 + Left = 201 Height = 23 - Top = 140 - Width = 223 + Top = 242 + Width = 162 Anchors = [akLeft, akRight, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Bottom = 2 - TabOrder = 6 - Text = 'EventEdit' + BorderSpacing.Left = 6 + BorderSpacing.Bottom = 4 + TabOrder = 12 + Text = 'EventVarEdit' end - object GroupEdit: TEdit + object GroupVarEdit: TEdit[18] AnchorSideLeft.Control = GroupInBtn AnchorSideLeft.Side = asrBottom - AnchorSideRight.Control = Panel1 + AnchorSideTop.Control = GroupVarLabel + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = ParamsPanel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = GroupOutBtn AnchorSideBottom.Side = asrBottom - Left = 266 + Left = 201 Height = 23 - Top = 226 - Width = 223 + Top = 74 + Width = 162 Anchors = [akLeft, akRight, akBottom] - BorderSpacing.Left = 8 - TabOrder = 9 - Text = 'GroupEdit' - end - object GroupBox1: TGroupBox - AnchorSideLeft.Control = GroupOutBtn - AnchorSideTop.Control = GroupOutBtn - AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = Panel1 - AnchorSideRight.Side = asrBottom - Left = 230 - Height = 72 - Top = 273 - Width = 213 - AutoSize = True - BorderSpacing.Top = 24 - Caption = 'Options:' - ChildSizing.LeftRightSpacing = 12 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.VerticalSpacing = 2 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 52 - ClientWidth = 209 - TabOrder = 10 - object PlotChk: TCheckBox - Left = 12 - Height = 19 - Top = 6 - Width = 185 - Caption = 'Graph Survival Probabilities (%)' - TabOrder = 0 - end - object PrintChk: TCheckBox - Left = 12 - Height = 19 - Top = 27 - Width = 185 - AutoSize = False - Caption = 'Show Computation Results' - TabOrder = 1 - end + BorderSpacing.Left = 6 + BorderSpacing.Bottom = 4 + TabOrder = 13 + Text = 'GroupVarEdit' end end + inherited ParamsSplitter: TSplitter + Left = 375 + Height = 400 + end + inherited PageControl: TPageControl + Left = 384 + Height = 384 + Width = 487 + ActivePage = ReportPage + TabIndex = 0 + TabOrder = 1 + end end diff --git a/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.pas b/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.pas index 14a9d82e4..fd0d1ea84 100644 --- a/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.pas +++ b/applications/lazstats/source/forms/analysis/nonparametric/kaplanmeierunit.pas @@ -5,55 +5,47 @@ unit KaplanMeierUnit; interface uses - Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons, Clipbrd, - MainUnit, Globals, FunctionsLib, OutputUnit, ContextHelpUnit; + TASources, TAChartAxis, + MainUnit, Globals, FunctionsLib, BasicStatsReportAndChartFormUnit; type - { TKaplanMeierFrm } + { TKaplanMeierForm } - TKaplanMeierFrm = class(TForm) - Bevel1: TBevel; - HelpBtn: TButton; - Panel1: TPanel; - ResetBtn: TButton; - ComputeBtn: TButton; - CloseBtn: TButton; - PlotChk: TCheckBox; - PrintChk: TCheckBox; - GroupBox1: TGroupBox; + TKaplanMeierForm = class(TBasicStatsReportAndChartForm) TimeInBtn: TBitBtn; TimeOutBtn: TBitBtn; EventInBtn: TBitBtn; EventOutBtn: TBitBtn; GroupInBtn: TBitBtn; GroupOutBtn: TBitBtn; - TimeEdit: TEdit; + TimeVarEdit: TEdit; Label1: TLabel; - Label2: TLabel; - Label3: TLabel; - Label5: TLabel; - EventEdit: TEdit; - GroupEdit: TEdit; + TimeVarLabel: TLabel; + EventVarLabel: TLabel; + GroupVarLabel: TLabel; + EventVarEdit: TEdit; + GroupVarEdit: TEdit; VarList: TListBox; - procedure ComputeBtnClick(Sender: TObject); procedure EventInBtnClick(Sender: TObject); procedure EventOutBtnClick(Sender: TObject); - procedure FormActivate(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); procedure GroupInBtnClick(Sender: TObject); procedure GroupOutBtnClick(Sender: TObject); - procedure HelpBtnClick(Sender: TObject); - procedure ResetBtnClick(Sender: TObject); procedure TimeInBtnClick(Sender: TObject); procedure TimeOutBtnClick(Sender: TObject); + procedure VarListDblClick(Sender: TObject); procedure VarListSelectionChange(Sender: TObject; User: boolean); private - { private declarations } - FAutoSized: Boolean; - procedure PlotXY(var Xpoints : IntDyneVec; + FExperimentalAxis: TChartAxis; + FControlAxis: TChartAxis; + FExperimentalSource: TListChartSource; + FControlSource: TListChartSource; + procedure PlotXY(const XPoints: IntDyneVec; const Y1Points, Y2Points: DblDyneVec; + const Dropped, Dropped2: IntDyneVec; N: Integer); + { + procedure PlotXY(var Xpoints : DblDyneVec; var Ypoints : DblDyneVec; var Dropped : IntDyneVec; var Dropped2 : IntDyneVec; @@ -61,187 +53,205 @@ type N : integer; XEdit : string; YEdit : string; - curveno : integer); - procedure UpdateBtnStates; + curveno : integer); } + protected + procedure AdjustConstraints; override; + procedure Compute; override; + procedure UpdateBtnStates; override; + public - { public declarations } + constructor Create(AOwner: TComponent); override; + procedure Reset; override; end; var - KaplanMeierFrm: TKaplanMeierFrm; + KaplanMeierForm: TKaplanMeierForm; + implementation +{$R *.lfm} + uses - Math, BlankFrmUnit; + Math, + TAChartUtils, TAChartAxisUtils, TACustomSeries, + GridProcs, {BlankFrmUnit, } MatrixUnit, ChartFrameUnit; -{ TKaplanMeierFrm } +const + EXPERIMENTAL_CAPTION = 'Experimental'; + CONTROL_CAPTION = 'Control'; -procedure TKaplanMeierFrm.ResetBtnClick(Sender: TObject); -var - i: integer; + +{ TKaplanMeierForm } + +constructor TKaplanMeierForm.Create(AOwner: TComponent); begin - VarList.Clear; - for i := 1 to NoVariables do - VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); - TimeEdit.Text := ''; - EventEdit.Text := ''; - GroupEdit.Text := ''; - UpdateBtnStates; - PlotChk.Checked := false; - PrintChk.Checked := false; -end; - -procedure TKaplanMeierFrm.TimeInBtnClick(Sender: TObject); -var - i: integer; -begin - i := VarList.ItemIndex; - if (i > -1) and (TimeEdit.Text = '') then - begin - TimeEdit.Text := VarList.Items[i]; - VarList.Items.Delete(i); - end; - UpdateBtnStates; -end; - -procedure TKaplanMeierFrm.TimeOutBtnClick(Sender: TObject); -begin - if TimeEdit.Text <> '' then - begin - VarList.Items.Add(TimeEdit.Text); - TimeEdit.Text := ''; - end; - UpdateBtnStates; -end; - -procedure TKaplanMeierFrm.FormActivate(Sender: TObject); -var - w: Integer; -begin - if FAutoSized then - exit; - - Panel1.Constraints.MinWidth := 2 * GroupBox1.Width + VarList.BorderSpacing.Left; - - w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]); - HelpBtn.Constraints.MinWidth := w; - ResetBtn.Constraints.MinWidth := w; - ComputeBtn.Constraints.MinWidth := w; - CloseBtn.Constraints.MinWidth := w; - - Constraints.MinWidth := Width; - Constraints.MinHeight := Height; - - FAutoSized := true; -end; - -procedure TKaplanMeierFrm.FormCreate(Sender: TObject); -begin - Assert(OS3MainFrm <> nil); + inherited; + { if BlankFrm = nil then Application.CreateForm(TBlankFrm, BlankFrm); + } + + FChartFrame.SetTitle('SURVIVAL CURVE'); + FChartFrame.SetXTitle('Time'); + FChartFrame.SetYTitle('Probability'); + FChartFrame.Chart.BottomAxis.Margin := 20; + + FControlSource := TListChartSource.Create(FChartFrame.Chart); + FControlAxis := FChartFrame.Chart.AxisList.Add; + with FControlAxis do + begin + Alignment := calBottom; + Marks.Source := FControlSource; + Marks.Style := smsValue; + Marks.LabelFont.Color := DATA_COLORS[1]; + Title.Caption := CONTROL_CAPTION; + Title.Visible := true; + Title.LabelFont.Color := DATA_COLORS[1]; + AxisPen.Color := DATA_COLORS[1]; + AxisPen.Visible := true; + Grid.Visible := false; + TickLength := 0; + Index := 0; + end; + + FExperimentalSource := TListChartSource.Create(FChartFrame.Chart); + FExperimentalAxis := FChartFrame.Chart.AxisList.Add; + with FExperimentalAxis do + begin + Alignment := calBottom; + Marks.Source := FExperimentalSource; + Marks.Style := smsValue; + Marks.LabelFont.Color := DATA_COLORS[0]; + Title.Caption := EXPERIMENTAL_CAPTION; + Title.Visible := true; + Title.LabelFont.Color := DATA_COLORS[0]; + AxisPen.Color := DATA_COLORS[0]; + AxisPen.Visible := true; + Grid.Visible := false; + TickLength := 0; + Margin := 20; + Index := 1; + end; + + PageControl.ActivePageIndex := 0; end; -procedure TKaplanMeierFrm.FormShow(Sender: TObject); + +procedure TKaplanMeierForm.AdjustConstraints; begin - ResetBtnClick(self); + inherited; + ParamsPanel.Constraints.MinWidth := Max( + 4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left, + GroupVarLabel.Width*2 + GroupInBtn.Width + 2*VarList.BorderSpacing.Right + ); + ParamsPanel.Constraints.MinHeight := EventOutBtn.Top + EventOutBtn.Height + + VarList.BorderSpacing.Bottom + + ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height; end; -procedure TKaplanMeierFrm.GroupInBtnClick(Sender: TObject); + +procedure TKaplanMeierForm.GroupInBtnClick(Sender: TObject); var i: integer; begin i := VarList.ItemIndex; - if (i > -1) and (GroupEdit.Text = '') then + if (i > -1) and (GroupVarEdit.Text = '') then begin - GroupEdit.Text := VarList.Items[i]; + GroupVarEdit.Text := VarList.Items[i]; VarList.Items.Delete(i); end; UpdateBtnStates; end; -procedure TKaplanMeierFrm.GroupOutBtnClick(Sender: TObject); + +procedure TKaplanMeierForm.GroupOutBtnClick(Sender: TObject); begin - if GroupEdit.Text <> '' then + if GroupVarEdit.Text <> '' then begin - VarList.Items.Add(GroupEdit.Text); - GroupEdit.Text := ''; + VarList.Items.Add(GroupVarEdit.Text); + GroupVarEdit.Text := ''; end; UpdateBtnStates; end; -procedure TKaplanMeierFrm.HelpBtnClick(Sender: TObject); -begin - if ContextHelpForm = nil then - Application.CreateForm(TContextHelpForm, ContextHelpForm); - ContextHelpForm.HelpMessage((Sender as TButton).tag); -end; -procedure TKaplanMeierFrm.EventInBtnClick(Sender: TObject); +procedure TKaplanMeierForm.EventInBtnClick(Sender: TObject); var i: integer; begin i := VarList.ItemIndex; - if (i > -1) and (EventEdit.Text = '') then + if (i > -1) and (EventVarEdit.Text = '') then begin - EventEdit.Text := VarList.Items[i]; + EventVarEdit.Text := VarList.Items[i]; VarList.Items.Delete(i); end; UpdateBtnStates; end; -procedure TKaplanMeierFrm.EventOutBtnClick(Sender: TObject); +procedure TKaplanMeierForm.EventOutBtnClick(Sender: TObject); begin - if EventEdit.Text <> '' then + if EventVarEdit.Text <> '' then begin - VarList.Items.Add(EventEdit.Text); - EventEdit.Text := ''; + VarList.Items.Add(EventVarEdit.Text); + EventVarEdit.Text := ''; end; UpdateBtnStates; end; -procedure TKaplanMeierFrm.ComputeBtnClick(Sender: TObject); +procedure TKaplanMeierForm.Compute; var - TwoGroups : boolean; - Size1, Size2, TotalSize, NoDeaths, ThisTime: integer; - mintime, maxtime, tempint, nopoints, tempvalue : integer; - NoCensored, nocats, i, j, k, icase, oldtime, pos, first, last : integer; - noinexp, noincntrl, count, TimeCol, DeathsCol: integer; - GroupCol : integer; - cumprop, proportion, term1, term2, term3 : double; - E1, E2, O1, O2, Chisquare, ProbChi, Risk, LogRisk, SELogRisk : double; - HiConf, LowConf, HiLogLevel, LowLogLevel, lastexp, lastctr : double; - TimePlot, Dropped, Dropped2, Time, AtRisk, Dead, SurvivalTimes : IntDyneVec; - ExpCnt, CntrlCnt, TotalatRisk, ExpatRisk, CntrlatRisk : IntDyneVec; - Deaths, Group, Censored : IntDyneVec; - ProbPlot, ProbPlot2, CondProb, ExpProp, CntrlProp : DblDyneVec; - CumPropExp, CumPropCntrl : DblDyneVec; - TimeLabel, GroupLabel, DeathsLabel : string; - lReport: TStrings; + TwoGroups : boolean; + Size1, Size2, TotalSize, NoDeaths, ThisTime: integer; + minTime, maxTime, tempInt, noPoints, tempValue: integer; + NoCensored, noCats, i, j, k, icase, oldtime, pos, first, last : integer; + noinexp, noincntrl, count, TimeCol, DeathsCol: integer; + GroupCol : integer; + cumprop, proportion, term1, term2, term3 : double; + E1, E2, O1, O2, Chisquare, ProbChi, Risk, LogRisk, SELogRisk : double; + HiConf, LowConf, HiLogLevel, LowLogLevel, lastexp, lastctr : double; + TimePlot: IntDyneVec = nil; + Dropped: IntDyneVec = nil; + Dropped2: IntDyneVec = nil; + Time: IntDyneVec = nil; + AtRisk: IntDyneVec = nil; + Dead: IntDyneVec = nil; + SurvivalTimes: IntDyneVec = nil; + ExpCnt: IntDyneVec = nil; + CntrlCnt: IntDyneVec = nil; + TotalatRisk: IntDyneVec = nil; + ExpatRisk: IntDyneVec = nil; + CntrlatRisk: IntDyneVec = nil; + Deaths: IntDyneVec = nil; + Group: IntDyneVec = nil; + Censored: IntDyneVec = nil; + ProbPlot: DblDyneVec = nil; + ProbPlot2: DblDyneVec = nil; + CondProb: DblDyneVec = nil; + ExpProp: DblDyneVec = nil; + CntrlProp: DblDyneVec = nil; + CumPropExp: DblDyneVec = nil; + CumPropCntrl: DblDyneVec = nil; + TimeLabel, GroupLabel, DeathsLabel: string; + lReport: TStrings; begin // get variable columns and labels - TimeLabel := TimeEdit.Text; - GroupLabel := GroupEdit.Text; - DeathsLabel := EventEdit.Text; - TimeCol := 0; - DeathsCol := 0; - GroupCol := 0; - for i := 1 to NoVariables do - begin - if (TimeLabel = OS3MainFrm.DataGrid.Cells[i,0]) then TimeCol := i; - if (DeathsLabel = OS3MainFrm.DataGrid.Cells[i,0]) then DeathsCol := i; - if (GroupLabel = OS3MainFrm.DataGrid.Cells[i,0]) then GroupCol := i; - end; + TimeLabel := TimeVarEdit.Text; + GroupLabel := GroupVarEdit.Text; + DeathsLabel := EventVarEdit.Text; - if (TimeCol = 0) or (DeathsCol = 0) then + TimeCol := GetVariableIndex(OS3MainFrm.DataGrid, TimeVarEdit.Text); + DeathsCol := GetVariableIndex(OS3MainFrm.DataGrid, EventVarEdit.Text); + GroupCol := GetVariableIndex(OS3MainFrm.DataGrid, GroupVarEdit.Text); + + if (TimeCol = -1) or (DeathsCol = -1) then begin MessageDlg('One or more variables not selected.', mtError, [mbOK], 0); exit; end; - if (GroupEdit.Text = '') then + if (GroupVarEdit.Text = '') then begin TwoGroups := false; Size1 := NoCases; @@ -255,7 +265,8 @@ begin begin if (StrToInt(OS3MainFrm.DataGrid.Cells[GroupCol,i]) = 1) then Size1 := Size1 + 1 - else Size2 := Size2 + 1; + else + Size2 := Size2 + 1; end; end; @@ -321,23 +332,17 @@ begin begin if (SurvivalTimes[i] > SurvivalTimes[j]) then begin - tempint := SurvivalTimes[i]; - SurvivalTimes[i] := SurvivalTimes[j]; - SurvivalTimes[j] := tempint; - tempint := Censored[i]; - Censored[i] := Censored[j]; - Censored[j] := tempint; - tempint := Deaths[i]; - Deaths[i] := Deaths[j]; - Deaths[j] := tempint; + Exchange(SurvivalTimes[i], SurvivalTimes[j]); + Exchange(Censored[i], Censored[j]); + Exchange(Deaths[i], Deaths[j]); end; end; end; // get number censored in each time slot nopoints := maxtime + 1; - SetLength(Dropped,nopoints+2); - SetLength(Dropped2,nopoints+2); + SetLength(Dropped, nopoints+2); + SetLength(Dropped2, nopoints+2); for j := 0 to nopoints do begin Dropped[j] := 0; @@ -452,6 +457,13 @@ begin Dropped[0] := 0; CondProb[0] := 0.0; + for i := 1 to nocats do + begin + AtRisk[i] := AtRisk[i-1] - Dead[i-1] - Dropped[i-1]; + CondProb[i-1] := 1.0 - Dead[i-1] / AtRisk[i-1]; + end; + + (* lReport := TStringList.Create; try lReport.Add(' Time Censored Dead At Risk Probability'); @@ -461,11 +473,12 @@ begin CondProb[i-1] := 1.0 - Dead[i-1] / AtRisk[i-1]; end; for i := 0 to nocats do - lReport.Add(' %3d %3d %3d %3d %6.3f', [Time[i],Dropped[i],Dead[i],AtRisk[i],CondProb[i]]); + lReport.Add(' %3d %3d %3d %3d %6.3f', [Time[i], Dropped[i], Dead[i], AtRisk[i], CondProb[i]]); DisplayReport(lReport); finally lReport.Free; end; + *) // Get cumulative proportions for i := 0 to nocats do @@ -489,33 +502,35 @@ begin lReport.Add(' %4d %4d %4d %4d %7.4f %7.4f', [ Time[i], AtRisk[i], Dropped[i], Deaths[i], CondProb[i], CumPropExp[i] ]); - DisplayReport(lReport); + + lReport.Add(''); + lReport.Add(DIVIDER_AUTO); + lReport.Add(''); + lReport.Add(' Time Censored Dead At Risk Probability'); + for i := 0 to nocats do + lReport.Add(' %3d %3d %3d %3d %6.3f', [Time[i], Dropped[i], Dead[i], AtRisk[i], CondProb[i]]); + + FReportFrame.DisplayReport(lReport); + finally lReport.Free; end; - if PlotChk.Checked then // plot Y := cumulative proportion surviving, x := time + // Plot X = Time, Y = cumulative proportion surviving + // Get points to plot + nopoints := maxtime + 1; + SetLength(TimePlot,nocats+2); + SetLength(ProbPlot,nocats+2); + ProbPlot[0] := 1.0; + for j := 0 to nocats do begin - // Get points to plot - nopoints := maxtime + 1; - SetLength(TimePlot,nocats+2); - SetLength(ProbPlot,nocats+2); - ProbPlot[0] := 1.0; - for j := 0 to nocats do - begin - TimePlot[j] := Time[j]; - ProbPlot[j] := CumPropExp[j]; - end; - BlankFrm.Show; - PlotXY(TimePlot, ProbPlot, Dropped, Dropped2, maxtime, 0, 1.0, 0.0, nocats, 'TIME', 'PROBABILITY', 1); - end; // end if graph1 + TimePlot[j] := Time[j]; + ProbPlot[j] := CumPropExp[j]; + end; + PlotXY(TimePlot, ProbPlot, nil, Dropped, Dropped, NoCats); +// BlankFrm.Show; +// PlotXY(TimePlot, ProbPlot, Dropped, Dropped2, maxtime, 0, 1.0, 0.0, nocats, 'TIME', 'PROBABILITY', 1); - ProbPlot := nil; - TimePlot := nil; - CondProb := nil; - Dead := nil; - AtRisk := nil; - Time := nil; end // end if not two groups //============================================================================// else // Experimental and control groups @@ -558,18 +573,10 @@ begin begin if (SurvivalTimes[i] > SurvivalTimes[j]) then begin - tempint := SurvivalTimes[i]; - SurvivalTimes[i] := SurvivalTimes[j]; - SurvivalTimes[j] := tempint; - tempint := Censored[i]; - Censored[i] := Censored[j]; - Censored[j] := tempint; - tempint := Deaths[i]; - Deaths[i] := Deaths[j]; - Deaths[j] := tempint; - tempint := Group[i]; - Group[i] := Group[j]; - Group[j] := tempint; + Exchange(SurvivalTimes[i], SurvivalTimes[j]); + Exchange(Censored[i], Censored[j]); + Exchange(Deaths[i], Deaths[j]); + Exchange(Group[i], Group[j]); end; end; end; @@ -595,15 +602,9 @@ begin begin if (Deaths[j] < Deaths[k] ) then // swap begin - tempint := Censored[j]; - Censored[j] := Censored[k]; - Censored[k] := tempint; - tempint := Deaths[j]; - Deaths[j] := Deaths[k]; - Deaths[k] := tempint; - tempint := Group[j]; - Group[j] := Group[k]; - Group[k] := tempint; + Exchange(Censored[j], Censored[k]); + Exchange(Deaths[j], Deaths[k]); + Exchange(Group[j], Group[k]); end; end; // next k end; // next j @@ -782,7 +783,7 @@ begin end; // Print Results - if (TwoGroups and PrintChk.Checked) then // both experimental and control groups + if TwoGroups then // both experimental and control groups begin lReport := TStringList.Create; try @@ -837,9 +838,10 @@ begin // Plot data output lReport.Add(''); - lReport.Add('============================================================================'); + lReport.Add(DIVIDER_AUTO); lReport.Add(''); lReport.Add('EXPERIMENTAL GROUP CUMULATIVE PROBABILITY'); + lReport.Add(''); lReport.Add('CASE TIME DEATHS CENSORED CUM.PROB.'); for i := 1 to NoCases do if (Group[i] = 1) then @@ -847,9 +849,10 @@ begin i, SurvivalTimes[i], Deaths[i], Censored[i], CumPropExp[i] ]); lReport.Add(''); - lReport.Add('============================================================================'); + lReport.Add(DIVIDER_AUTO); lReport.Add(''); lReport.Add('CONTROL GROUP CUMULATIVE PROBABILITY'); + lReport.Add(''); lReport.Add('CASE TIME DEATHS CENSORED CUM.PROB.'); for i := 1 to NoCases do if (Group[i] = 2) then @@ -858,96 +861,110 @@ begin ]); lReport.Add(''); - DisplayReport(lReport); + FReportFrame.DisplayReport(lReport); finally lReport.Free; end; end; // if 2 groups and printit - if PlotChk.Checked then // plot cumulative proportion surviving (Y) against time (X) + // Plot cumulative proportion surviving (Y) against time (X) + nopoints := maxtime + 1; + SetLength(TimePlot, nopoints+2); + SetLength(ProbPlot, nopoints+2); + SetLength(ProbPlot2, nopoints+2); + ProbPlot[0] := 1.0; + ProbPlot2[0] := 1.0; + lastexp := 1.0; + lastctr := 1.0; + for i := 0 to nopoints do begin - nopoints := maxtime + 1; - SetLength(TimePlot,nopoints+2); - SetLength(ProbPlot,nopoints+2); - SetLength(ProbPlot2,nopoints+2); - ProbPlot[0] := 1.0; - ProbPlot2[0] := 1.0; - lastexp := 1.0; - lastctr := 1.0; - for i := 0 to nopoints do + TimePlot[i] := 0; + ProbPlot[i] := 1.0; + ProbPlot2[i] := 1.0; + end; + TimePlot[0] := 0; + mintime := 0; + for i := 1 to nopoints do + begin + TimePlot[i] := i; + for j := 1 to NoCases do begin - TimePlot[i] := 0; - ProbPlot[i] := 1.0; - ProbPlot2[i] := 1.0; - end; - TimePlot[0] := 0; - mintime := 0; - for i := 1 to nopoints do - begin - TimePlot[i] := i; - for j := 1 to NoCases do + if (SurvivalTimes[j] = i) then begin - if (SurvivalTimes[j] = i) then + if (Group[j] = 1) then begin - if (Group[j] = 1) then - begin - ProbPlot[i] := CumPropExp[j]; // ExpProp[j]; - lastexp := CumPropExp[j]; // ExpProp[j]; - end; - if (Group[j] = 2) then - begin - ProbPlot2[i] := CumPropCntrl[j]; //CntrlProp[j]; - lastctr := CumPropCntrl[j]; // CntrlProp[j]; - end; - end - else - begin - if (Group[j] = 1) then ProbPlot[i] := lastexp; - if (Group[j] = 2) then ProbPlot2[i] := lastctr; + ProbPlot[i] := CumPropExp[j]; // ExpProp[j]; + lastexp := CumPropExp[j]; // ExpProp[j]; end; + if (Group[j] = 2) then + begin + ProbPlot2[i] := CumPropCntrl[j]; //CntrlProp[j]; + lastctr := CumPropCntrl[j]; // CntrlProp[j]; + end; + end + else + begin + if (Group[j] = 1) then ProbPlot[i] := lastexp; + if (Group[j] = 2) then ProbPlot2[i] := lastctr; end; end; + end; - BlankFrm.Image1.Canvas.Clear; - BlankFrm.Show; - PlotXY(TimePlot, ProbPlot, Dropped, Dropped2, maxtime, 0, 1.0, 0.0, nopoints, 'TIME', 'PROBABILITY', 1); - PlotXY(TimePlot, ProbPlot2, Dropped, Dropped2, maxtime, 0, 1.0, 0.0, nopoints, 'TIME', 'PROBABILITY', 2); - - ProbPlot2 := nil; - ProbPlot := nil; - TimePlot := nil; - end; // if graph plot := 1 - - Dropped2 := nil; - Dropped := nil; - - // clean up memory - Dropped2 := nil; - Dropped := nil; - CumPropCntrl := nil; - CumPropExp := nil; - Censored := nil; - Group := nil; - Deaths := nil; - CntrlProp := nil; - ExpProp := nil; - CntrlatRisk := nil; - ExpatRisk := nil; - TotalatRisk := nil; - CntrlCnt := nil; - ExpCnt := nil; - SurvivalTimes := nil; + PlotXY(TimePlot, ProbPlot, ProbPlot2, Dropped, Dropped2, NoPoints); + // BlankFrm.Image1.Canvas.Clear; + // BlankFrm.Show; + // PlotXY(TimePlot, ProbPlot, Dropped, Dropped2, maxtime, 0, 1.0, 0.0, nopoints, 'TIME', 'PROBABILITY', 1); + // PlotXY(TimePlot, ProbPlot2, Dropped, Dropped2, maxtime, 0, 1.0, 0.0, nopoints, 'TIME', 'PROBABILITY', 2); end; -procedure TKaplanMeierFrm.PlotXY(var Xpoints: IntDyneVec; + +procedure TKaplanMeierForm.PlotXY(const XPoints: IntDyneVec; + const Y1Points, Y2Points: DblDyneVec; const Dropped, Dropped2: IntDyneVec; N: Integer); +var + i: Integer; + ser: TChartSeries; +begin + // do not call FChartFrame.Clear which will delete the axis titles + FChartFrame.Chart.ClearSeries; + FExperimentalSource.Clear; + FControlSource.Clear; + + if Y1Points <> nil then + begin + ser := FChartFrame.PlotXY(ptStairsYX, nil, nil, nil, nil, EXPERIMENTAL_CAPTION, DATA_COLORS[0]); + // add points manually due to overdimensioned data arrays... + for i := 0 to N-1 do + ser.AddXY(XPoints[i], Y1Points[i]); + end; + + if Y2Points <> nil then + begin + ser := FChartFrame.PlotXY(ptStairsYX, nil, nil, nil, nil, CONTROL_CAPTION, DATA_COLORS[1]); + for i := 0 to N-1 do + ser.AddXY(XPoints[i], Y2Points[i]); + end; + + if Dropped <> nil then + for i := 0 to N do + if Dropped[i] <> 0 then + FExperimentalSource.Add(XPoints[i], Dropped[i]); + + if Dropped2 <> nil then + for i := 0 to N do + if Dropped2[i] <> 0 then + FControlSource.Add(XPoints[i], Dropped2[i]); +end; + +(* +procedure TKaplanMeierForm.PlotXY(var Xpoints: DblDyneVec; var Ypoints: DblDyneVec; var Dropped: IntDyneVec; var Dropped2: IntDyneVec; Xmax, Xmin, Ymax, Ymin: double; N: integer; XEdit: string; YEdit: string; curveno: integer); var i, xpos, ypos, hleft, hright, vtop, vbottom, imagewide : integer; vhi, hwide, offset, strhi, imagehi : integer; - noxvalues, digitwidth, Xvalue, xvalincr, oldxpos : integer; - valincr, Yvalue, value, oldypos, term1, term2, term3 : double; + noxvalues, digitwidth, xvalincr, oldxpos : integer; + valincr, XValue, Yvalue, value, oldypos, term1, term2, term3 : double; Title, outline : string; label again, second; @@ -1119,12 +1136,57 @@ second: xpos := hleft; BlankFrm.Image1.Canvas.TextOut(xpos,ypos,Title); end; end; +*) -procedure TKaplanMeierFrm.UpdateBtnStates; +procedure TKaplanMeierForm.Reset; +var + i: integer; +begin + inherited; + + VarList.Clear; + for i := 1 to NoVariables do + VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); + TimeVarEdit.Clear; + EventVarEdit.Clear; + GroupVarEdit.Clear; + + UpdateBtnStates; +end; + + +procedure TKaplanMeierForm.TimeInBtnClick(Sender: TObject); +var + i: integer; +begin + i := VarList.ItemIndex; + if (i > -1) and (TimeVarEdit.Text = '') then + begin + TimeVarEdit.Text := VarList.Items[i]; + VarList.Items.Delete(i); + end; + UpdateBtnStates; +end; + + +procedure TKaplanMeierForm.TimeOutBtnClick(Sender: TObject); +begin + if TimeVarEdit.Text <> '' then + begin + VarList.Items.Add(TimeVarEdit.Text); + TimeVarEdit.Text := ''; + end; + UpdateBtnStates; +end; + + +procedure TKaplanMeierForm.UpdateBtnStates; var lSelected: Boolean; i: Integer; begin + inherited; + lSelected := false; for i := 0 to VarList.Count-1 do if VarList.Selected[i] then @@ -1132,21 +1194,42 @@ begin lSelected := true; break; end; - TimeInBtn.Enabled := lSelected and (TimeEdit.Text = ''); - EventInBtn.Enabled := lSelected and (EventEdit.Text = ''); - GroupInBtn.Enabled := lSelected and (GroupEdit.Text = ''); - TimeOutBtn.Enabled := (TimeEdit.Text <> ''); - EventOutBtn.Enabled := (EventEdit.Text <> ''); - GroupOutBtn.Enabled := (GroupEdit.Text <> ''); + + TimeInBtn.Enabled := lSelected and (TimeVarEdit.Text = ''); + EventInBtn.Enabled := lSelected and (EventVarEdit.Text = ''); + GroupInBtn.Enabled := lSelected and (GroupVarEdit.Text = ''); + TimeOutBtn.Enabled := (TimeVarEdit.Text <> ''); + EventOutBtn.Enabled := (EventVarEdit.Text <> ''); + GroupOutBtn.Enabled := (GroupVarEdit.Text <> ''); end; -procedure TKaplanMeierFrm.VarListSelectionChange(Sender: TObject; User: boolean); + +procedure TKaplanMeierForm.VarListDblClick(Sender: TObject); +var + index: Integer; + s: String; +begin + index := VarList.ItemIndex; + if index > -1 then + begin + s := VarList.Items[index]; + if GroupVarEdit.Text = '' then + GroupVarEdit.Text := s + else if TimeVarEdit.Text = '' then + TimeVarEdit.Text := s + else if EventVarEdit.Text = '' then + EventVarEdit.Text := s; + VarList.Items.Delete(index); + UpdateBtnStates; + end; +end; + + +procedure TKaplanMeierForm.VarListSelectionChange(Sender: TObject; User: boolean); begin UpdateBtnStates; end; -initialization - {$I kaplanmeierunit.lrs} end. diff --git a/applications/lazstats/source/forms/mainunit.pas b/applications/lazstats/source/forms/mainunit.pas index 551f76b40..a420c04eb 100644 --- a/applications/lazstats/source/forms/mainunit.pas +++ b/applications/lazstats/source/forms/mainunit.pas @@ -1805,6 +1805,17 @@ begin PolyDIFFrm.ShowModal; end; +// Menu "Analysis" > "Financial" > "Loan Amortization Schedule" +procedure TOS3MainFrm.mnuAnalysisFinancial_LoanAmortClick(Sender: TObject); +begin + if LoanItForm = nil then + Application.CreateForm(TLoanItForm, LoanItForm); + LoanItForm.Show; +end; + + +{ "Nonparametric" commands } + // Menu "Analysis" > "Nonparametric" > "Contingency Chi Square" procedure TOS3MainFrm.mnuAnalysisNonPar_ContingChiSqClick(Sender: TObject); begin @@ -1832,9 +1843,9 @@ end; // Menu "Analysis" > "Nonparametric" > "Fisher's Exact Text" procedure TOS3MainFrm.mnuAnalysisNonPar_FisherClick(Sender: TObject); begin - if FisherFrm = nil then - Application.CreateForm(TFisherFrm, FisherFrm); - FisherFrm.ShowModal; + if FisherForm = nil then + Application.CreateForm(TFisherForm, FisherForm); + FisherForm.Show; end; // Menu "Analysis" > "Nonparametric" > "Kendall's Coefficient of Concordance" @@ -1861,14 +1872,6 @@ begin WilcoxonForm.Show; end; -// Menu "Analysis" > "Financial" > "Loan Amortization Schedule" -procedure TOS3MainFrm.mnuAnalysisFinancial_LoanAmortClick(Sender: TObject); -begin - if LoanItForm = nil then - Application.CreateForm(TLoanItForm, LoanItForm); - LoanItForm.Show; -end; - // Menu "Analysis" > "Nonparametric" > "Cochran Q Test" procedure TOS3MainFrm.mnuAnalysisNonPar_CochranClick(Sender: TObject); begin @@ -1912,9 +1915,9 @@ end; // Menu "Analysis" > "Nonparametric" > "Kaplan-Meier Survival Analysis" procedure TOS3MainFrm.mnuAnalysisNonPar_SurvivalClick(Sender: TObject); begin - if KaplanMeierFrm = nil then - Application.CreateForm(TKaplanMeierFrm, KaplanMeierFrm); - KaplanMeierFrm.ShowModal; + if KaplanMeierForm = nil then + Application.CreateForm(TKaplanMeierForm, KaplanMeierForm); + KaplanMeierForm.Show; end; diff --git a/applications/lazstats/source/frames/chartframeunit.pas b/applications/lazstats/source/frames/chartframeunit.pas index a53dbdfc1..1433dde76 100644 --- a/applications/lazstats/source/frames/chartframeunit.pas +++ b/applications/lazstats/source/frames/chartframeunit.pas @@ -24,7 +24,7 @@ const type TPlotType = (ptLines, ptSymbols, ptLinesAndSymbols, ptBars, - ptArea); + ptArea, ptStairsYX, ptStairsXY); { TChartFrame } @@ -182,17 +182,25 @@ var xval: Double; begin case AType of - ptLines, ptSymbols, ptLinesAndSymbols: + ptLines, ptSymbols, ptLinesAndSymbols, ptStairsXY, ptStairsYX: begin Result := TLineSeries.Create(self); TLineSeries(Result).ShowPoints := AType in [ptSymbols, ptLinesAndSymbols]; TLineSeries(Result).ShowLines := AType in [ptLines, ptLinesAndSymbols]; TLineSeries(Result).SeriesColor := AColor; - if AType in [ptSymbols, ptLinesAndSymbols] then - begin - TLineSeries(Result).Pointer.Brush.Color := AColor; - TLineSeries(Result).Pointer.Style := ASymbol; + + case AType of + ptSymbols, ptLinesAndSymbols: + begin + TLineSeries(Result).Pointer.Brush.Color := AColor; + TLineSeries(Result).Pointer.Style := ASymbol; + end; + ptStairsXY: + TLineSeries(Result).LineType := ltStepXY; + ptStairsYX: + TLineSeries(Result).LineType := ltStepYX; end; + if yErrorBars <> nil then begin TLineSeries(Result).YErrorBars.Visible := true;