#=============================================== # TkFittingAppBase #=============================================== package TkFittingAppBase; use clib::TkFittingCommon2; @ISA = qw(TkFittingCommon2); use strict; use Utils; use IniFile; use CSV; use MyTk::GraphFrameArray; use GraphData; use Sci::Science; use Sci::PES; use Sci::Ellipsometry; use Sci::Optimize; #============================================================ # コンストラクタ、デストラクタ #============================================================ #呼び出されることはない sub new { my ($module, $app) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; $this->SUPER::DESTROY(@_); } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ sub CreateLeftFrame { my ($this, $ConfigSide, @args) = @_; # return $this->SUPER::CreateLeftFrame(); return undef; } sub CreateSelectFilePane { my ($this) = @_; # return $this->SUPER::CreateSelectFilePane(); return undef; } sub CreateFileContentPane { return undef; } sub CreateWidgets { my ($this, $DoSuperOnly) = @_; my $mw = $this->mw(); $this->{ini} = new IniFile(undef, 0, 0); $this->{dini} = new IniFile(undef, 0, 0); $this->InitializeParameters($this->{ini}, $this->{dini}); $this->SUPER::CreateWidgets(); $mw->SetTitle("$this->{ProgramName} / TkPlot"); $this->App()->SetProgram("$this->{ProgramName} / TkPlot"); #=================================================== # ペインを作製 #=================================================== my $EntryWidth = $this->{EntryWidth}; $this->{pNoteBookTabs} = [qw(Main ViewRange LSQ Common Setup)] if(!defined $this->{pNoteBookTabs}); my $NoteBook = $this->MakeNotebookPanes( $this->{pNoteBookTabs}, [], ); my $MainFrame = $NoteBook->{MainPaneFrame}->{LastFrame}; $this->ConfigureOpenButton( sub { $this->{Sample1CSV} = $this->ChooseFile( "open", $this->{Sample1FileMask}, "ChooseSampleFile", "Sample1CSV", $this->{Sample1FileFrame} ); } ); my $pArray = $this->{pParameterConfigArray}; $this->AddFittingParameters( $this->{ParameterFrameLabel}, @$pArray ); $this->BuildFooter($MainFrame, $this->{EntryWidth}); $this->UpdateParameters(); } sub ConfigureOpenButton { my ($this, $func) = @_; return if(!$this->mw()->{OpenButton}); $this->mw()->{OpenButton}->configure( -command => sub { $this->{Sample1CSV} = &$func(@_); }, ); } sub SetnSampleFiles { my ($this, $nSampleFiles, $SampleFileMask, $pAxes, $pDataLabelArray) = @_; $this->{pChooseFileArray} = [ # $VarName, $Label, $FileName, $FrameName, # $FileMask, $pButtons, $pAxes, $pDataLabels ["Param", "Param:", "ParameterFile", "ParameterFileFrame", "*.prm", ["save", "edit"], [], [], ], ]; for(my $i = 0 ; $i < $nSampleFiles ; $i++) { my $i1 = $i + 1; my $pArray = [ "Sample${i1}CSV", "Sample${i1}:", "Sample${i1}CSVFile", "Sample${i1}FileFrame", $SampleFileMask, ["edit"], $pAxes, $pDataLabelArray ]; $this->{pChooseFileArray}->[$i+1] = $pArray; } return $this->{pChooseFileArray}; } sub BuildFooter { my ($this, $MainFrame) = @_; my $Frame1 = $MainFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); my $pArray = $this->{pFooterButtonsArray}; $pArray = $this->{pFooterButtonsArray} = ["RePlot", "RestoreScale", "Re&calc", "&Fit"] if(!defined $pArray); my $ButtonFrame = $this->MakeFittingButtons($Frame1, @$pArray); $ButtonFrame->pack(-anchor => 'nw', -expand => 'yes', -fill => 'x'); return $ButtonFrame; } sub MakeNotebookPanes { my ($this, $pPageListArray, $pNumbersListArray) = @_; my $mw = $this->mw(); my $EntryWidth = $this->{EntryWidth}; $mw->{NoteBook} = $this->SUPER::MakeNotebookPanes($mw, $EntryWidth, $this->{ini}->pVariable("nFilmLayers", 1), $this->{ini}->pVariable("nLorentz", 3), $this->{ini}->pVariable("nDrude", 0), $this->{ini}->pVariable("nStepBG", 2), $this->{ini}->pVariable("nGL", 6), $pPageListArray, $pNumbersListArray, ); $mw->{NoteBook}->pack(-fill => 'both', -expand => 'yes'); return $mw->{NoteBook}; } sub BuildMainPane { my ($this, $MainPaneFrame, $EntryWidth) = @_; my $pChooseFileArray = $this->{pChooseFileArray}; for(my $i = 0 ; $i < @$pChooseFileArray ; $i++) { my $pArray = $pChooseFileArray->[$i]; my ($VarName, $Label, $FileName, $FrameName, $FileMask, $pButtons, $pAxes, $pDataLabels) = @$pArray; my %ButtonHash; for(my $j = 0 ; $j < @$pButtons ; $j++) { $ButtonHash{$pButtons->[$j]} = 1; } if($VarName eq 'Param') { my $Frame = $MainPaneFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{$FrameName} = $this->MakeChooseFileEntry( $Frame, $VarName, $Label, $this->{ini}->pVariable($FileName, ""), '&Choose', sub { $this->ChooseFile("save", $FileMask, "ChooseParameterFile", @_); }, $ButtonHash{save}, sub { $this->SaveParameterFile("SaveParam", '', @_); }, $ButtonHash{edit}, sub { $this->EditFile('EditParam', @_); }, $pAxes, ); $this->{$FrameName}->pack(-anchor => 'nw', -fill => 'x'); } else { my $Frame = $MainPaneFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{$FrameName} = $this->MakeChooseFileEntry( $Frame, $VarName, $Label, $this->{ini}->pVariable($FileName, ""), '&Choose', sub { $this->{$VarName} = $this->ChooseFile("open", $FileMask, "ChooseSample1File", @_); $this->RePlot(1); }, $ButtonHash{save}, sub {}, $ButtonHash{edit}, sub { $this->EditFile("Edit$VarName", @_); }, $pAxes, ); $this->{$FrameName}->pack(-anchor => 'nw', -fill => 'x'); for(my $j = 0 ; $j < @$pDataLabels ; $j++) { my $key = $pAxes->[$j]; my $Label = $pDataLabels->[$j]; $this->{$FrameName}->{"p${key}DataLabel"} = $Label; } } } my $Frame = $MainPaneFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->mw()->{LSQFrame2} = $this->MakeLSQPanes( $Frame, $EntryWidth, 'Fitting', [qw(FittingRange)], [], [], ['FitXMin', 'Emin:', 'FitXMax', 'Emax:', 'nSkipData', 'nSkip:'], ['EPS', 'EPS:', 'nMaxIter', 'MaxIter:', 'nSaveSpectraInterval', 'SaveIntvl:'], ); $this->mw()->{LSQFrame2}->pack(-anchor => 'nw', -expand => 'yes', -fill => 'x'); $MainPaneFrame->{LastFrame} = $MainPaneFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->UpdateParameters(); } sub BuildCommonPane { my ($this, $MainPaneFrame, $EntryWidth) = @_; $MainPaneFrame->{LastFrame} = $MainPaneFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->BuildFooter($MainPaneFrame, $EntryWidth); } sub BuildLSQPane { my ($this, $MainPaneFrame, $EntryWidth) = @_; my $Frame = $MainPaneFrame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->mw()->{LSQFrame} = $this->MakeLSQPanes( $Frame, $EntryWidth, 'Fitting', [qw(LSQMethod FitTo FittingRange FittingConditions)], ['Amoeba::Simplex', 'PDL::Simplex', 'ModifiedNewton'], ['PES'], ['FitXMin', 'Emin:', 'FitXMax', 'Emax:', 'nSkipData', 'nSkip:'], ['EPS', 'EPS:', 'nMaxIter', 'MaxIter:', 'nSaveSpectraInterval', 'SaveIntvl:'], ); $this->mw()->{LSQFrame}->pack(-anchor => 'nw', -expand => 'yes', -fill => 'x'); # $this->mw()->{LSQFrame}->{FitToListBox}->SetText('alpha'); $this->BuildFooter($MainPaneFrame, $EntryWidth); } sub BuildViewRangePane { my ($this, $MainFrame, $EntryWidth) = @_; my $pPlotTypeArray = $this->{pPlotTypeArray}; $pPlotTypeArray = $this->{pPlotTypeArray} = [ [ ['x'], ['x'] ] ] if(!defined $pPlotTypeArray); my (@XAxisPlotArray, @YAxisPlotArray); for(my $i = 0 ; $i < @$pPlotTypeArray ; $i++) { my $pXYArray = $pPlotTypeArray->[$i]; $XAxisPlotArray[$i] = $pXYArray->[0]; $YAxisPlotArray[$i] = $pXYArray->[1]; } $this->SUPER::BuildViewRangePane($MainFrame, $EntryWidth, \@XAxisPlotArray, \@YAxisPlotArray, ); $this->BuildFooter($MainFrame, $EntryWidth); } sub Initialize { my ($this, $InitializeParameterFile, $InitializeData) = @_; $this->{DataFile} = new Ellipsometry; if($InitializeParameterFile) { $this->{ini}->{ParameterFile} = ''; $this->{ini}->{Sample1CSVFile} = ''; $this->{ini}->{FitXMin} = ''; $this->{ini}->{FitXMax} = ''; } if($InitializeData) { delete $this->{pObsX}; delete $this->{pObsY}; delete $this->{pCalY}; } } sub InitializeParameters { my ($this, $ini, $dini) = @_; # $this->AddParameters($ini, $dini, "EF", 0.0, 1, 1.0, '', ''); } sub BuildOptimize { my ($this) = @_; my $ini = $this->{ini}; my $dini = $this->{dini}; $this->{Optimize} = new Optimize; my $pVarConfigs = $this->{pVarConfigs}; for(my $i = 0 ; $i < @$pVarConfigs ; $i++) { my $pConf = $pVarConfigs->[$i]; my ($VarName, $VarLabel, $Value, $Format, $Unit, $ForOptimize, $Check, $Scale, $Min, $Max) = @$pConf; if(!defined $Max) { ($VarName, $Value, $Check, $Scale, $Min, $Max) = @$pConf; $ForOptimize = 1; $Scale = 1; $Min = $Max = ''; } if($ForOptimize) { $this->{Optimize}->AddParameters( $VarName, \$ini->{$VarName}, $dini->{"${VarName}check"}, $dini->{"${VarName}scale"}, $dini->{"${VarName}min"}, $dini->{"${VarName}max"}, sub { $ini->{$VarName} = $_[0]; } ); } } return $this->{Optimize}; } sub AddFittingParameters { my ($this, $MainLabel, @VarConfigs) = @_; my $EntryWidth = $this->{EntryWidth}; my $nVarColumn = $this->{nVarColumn}; $EntryWidth = $this->{EntryWidth} = 12 if(!defined $EntryWidth); $nVarColumn = $this->{nVarColumn} = 3 if(!defined $nVarColumn); $MainLabel = 'Common parameters' if(!defined $MainLabel); if(defined $this->{pVarConfigs}) { my $pVarConfigs = $this->{pVarConfigs}; my @AllConfigs = (@$pVarConfigs, @VarConfigs); $this->{pVarConfigs} = \@AllConfigs; } else { $this->{pVarConfigs} = \@VarConfigs; } my $ini = $this->{ini}; my $dini = $this->{dini}; my $mw = $this->mw(); my $NoteBook = $mw->{NoteBook}; my $MainPaneFrame = $NoteBook->{MainPaneFrame}->{LastFrame}; my $CommonPaneFrame = $NoteBook->{CommonPaneFrame}->{LastFrame}; my $MainPaneFrame1 = $MainPaneFrame->MyLabFrame( -label => $MainLabel, -labelside => 'acrosstop', )->pack(-anchor => 'nw'); my $CommonPaneFrame1 = $CommonPaneFrame->MyLabFrame( -label => $MainLabel, -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeParameterConditionHeading($CommonPaneFrame1, 0, 0); for(my $i = 0 ; $i < @VarConfigs ; $i++) { my $pConf = $VarConfigs[$i]; my ($VarName, $VarLabel, $Value, $Format, $Unit, $ForOptimize, $Check, $Scale, $Min, $Max) = @$pConf; if(!defined $Max) { ($VarName, $Value, $Check, $Scale, $Min, $Max) = @$pConf; $VarLabel = $VarName; $Format = '%12.6g'; $Unit = ''; $ForOptimize = 1; $Scale = 1; $Min = $Max = ''; } if($ForOptimize) { $this->AddParameters($ini, $dini, $VarName, $Value, $Check, $Scale, $Min, $Max); $this->MakeCheckEntry($MainPaneFrame1, $VarName, "$VarLabel:", $this->{dini}->pVariable("${VarName}check", $Check), $this->{ini}->pVariable($VarName, $Value), $Format, $EntryWidth, $Unit, int($i / $nVarColumn), $i % $nVarColumn); $this->MakeParameterConditionColumn($CommonPaneFrame1, $VarName, "$VarLabel:", $Format, $Value, $Check, $Scale, $Min, $Max, $EntryWidth, $i+1); } else { $this->MakeLabelEntry($MainPaneFrame1, $VarName, "$VarLabel:", $this->{ini}->pVariable($VarName, $Value), $Format, $EntryWidth, $Unit, int($i / $nVarColumn), $i % $nVarColumn); } } } #=================================================== # データ処理 #=================================================== sub Recalc { my ($this) = @_; return if(!defined $this->{DataFile}); my $ini = $this->{ini}; my $X1Label = $this->{Sample1FileFrame}->{X1ListBox}->GetText(); my $Y1Label = $this->{Sample1FileFrame}->{Y1ListBox}->GetText(); my $XMin = $ini->{FitXMin}; my $XMax = $ini->{FitXMax}; my $nSkipData = $ini->{nSkipData}; my $pX1 = $this->{Sample1CSV}->GetData($X1Label) if($X1Label); my $pY1 = $this->{Sample1CSV}->GetData($Y1Label) if($Y1Label); my $nData = @$pX1; my (@X, @Y, @CalY); my $S2 = 0.0; my $c = 0; for(my $i = 0 ; $i < $nData ; $i++) { my $x = $pX1->[$i]; next if($x < $XMin or $XMax < $x); next if($nSkipData > 0 and $i % $nSkipData != 0); $X[$c] = $x; $Y[$c] = $pY1->[$i]; $CalY[$c] = $this->CalY($x); my $d = $Y[$c] - $CalY[$c]; $S2 += $d * $d; $c++; } $S2 = sqrt($S2 / $c) if($c > 0); print "Recalc: S2=$S2\n"; $this->{pCalX} = \@X; $this->{pCalY} = \@CalY; $this->RePlot(1); } sub Fit { my ($this) = @_; return if(!defined $this->{DataFile}); my $ini = $this->{ini}; $this->UpdateParameters(); my $Method = $this->mw()->{LSQFrame}->{LSQMethodListBox}->GetText(); my $optimize = $this->BuildOptimize(); print "Method: $Method\n"; print "nMaxIter: $ini->{nMaxIter}\n"; my $X1Label = $this->{Sample1FileFrame}->{X1ListBox}->GetText(); my $Y1Label = $this->{Sample1FileFrame}->{Y1ListBox}->GetText(); my $XMin = $ini->{FitXMin}; my $XMax = $ini->{FitXMax}; my $nSkipData = $ini->{nSkipData}; my $pX1 = $this->{Sample1CSV}->GetData($X1Label) if($X1Label); my $pY1 = $this->{Sample1CSV}->GetData($Y1Label) if($Y1Label); #========================================================= # 最適化の実行 #========================================================= $optimize->SetnS2Calculation(0); my ($OptVars, $MinVal) = $optimize->Optimize( $Method, undef, undef, undef, $ini->{EPS}, $ini->{nMaxIter}, $ini->{iPrintLevel}, sub { $this->CalS2($pX1, $pY1, $XMin, $XMax, $nSkipData, @_); }, undef, sub { Optimize::BuildDifferentialMatrixes(@_); }, ); print "\nOptimized at:\n"; $optimize->RecoverParameters($OptVars); $optimize->PrintParameters(1, $OptVars, $MinVal, 1); $this->SetS2($MinVal); $this->UpdateParameters(); $this->Recalc(); $this->RePlot(); } sub CalDiff { my ($this, $i, $pX, $pY) = @_; my $d = $pY->[$i] - $this->CalY($pX->[$i]); return $d * $d; } sub CalS2 { my ($this, $pX, $pY, $XMin, $XMax, $nSkipData, $pVars, $iPrintLevel) = @_; my $optimize = $this->{Optimize}; my $ini = $this->{ini}; $optimize->RecoverParameters($pVars); my $nData = @$pX; my $S2 = 0.0; my $c = 0; for(my $i = 0 ; $i < $nData ; $i++) { my $x = $pX->[$i]; next if($x < $XMin or $XMax < $x); next if($nSkipData > 0 and $i % $nSkipData != 0); $S2 += $this->CalDiff($i, $pX, $pY); $c++; } $S2 = sqrt($S2 / $c) if($c > 0); $optimize->IncrementnS2(); my $nS2 = $optimize->nS2Calculation(); my $nS2Interval = $ini->{nSaveSpectraInterval}; print "S2[$nS2] = $S2 / "; $S2 += $optimize->CalPenalty(1.0e10, $pVars, 1); print "$S2\n"; $optimize->PrintParameters(1, $pVars, $S2, 0); if($nS2Interval > 0 and $nS2 % $nS2Interval == 0) { $this->SetS2($S2); $this->Recalc(); $this->RePlot(); } $this->UpdateParameters(); $this->mw()->update(); return $S2; } sub GetChooseFileInfo { my ($this, $i, $key) = @_; my $pChooseFileArray = $this->{pChooseFileArray}; return undef if(!defined $pChooseFileArray); my $pArray = $pChooseFileArray->[$i]; return undef if(!defined $pArray); my ($VarName, $Label, $FileName, $FrameName, $FileMask, $pButtons, $pAxes, $pDataLabels) = @$pArray; return $pArray if($key eq 'Array'); return $VarName if($key eq 'VarName'); return $FileName if($key eq 'FileName'); return $FrameName if($key eq 'FrameName'); return $FileMask if($key eq 'FileMask'); return $pButtons if($key eq 'pButtons'); return $pAxes if($key eq 'pAxes'); return $pDataLabels if($key eq 'pDataLabels'); return ''; } sub GetPlotTypeInfo { my ($this, $i, $key) = @_; my $pPlotTypeArray = $this->{pPlotTypeArray}; return undef if(!defined $pPlotTypeArray); my $pArray = $pPlotTypeArray->[$i]; return if(!defined $pArray); return $pArray if($key eq 'Array'); } sub SaveParameterFile { my ($this, $Option, $filepath, $name, $Frame) = @_; $filepath = $Frame->{PathEntry}->GetText() if($filepath eq ''); for(my $i = 1 ; ; $i++) { my $VarName = $this->GetChooseFileInfo($i, 'VarName'); my $FrameName = $this->GetChooseFileInfo($i, 'FrameName'); my $pAxes = $this->GetChooseFileInfo($i, 'pAxes'); last if(!defined $VarName); #print "VarName = $VarName pAxes=$pAxes\n"; # for(my $j = 0 ; $j < @$pAxes ; $j++) { # my $Axis = $pAxes->[$j]; #print "i=$i,$j: $Axis save to [$VarName$Axis]\n"; # $this->{ini}->{"$VarName$Axis"} = $this->{$FrameName}->{"${Axis}ListBox"}->GetText(); ## $this->{ini}->{Sample1Y1} = $this->{Sample1FileFrame}->{Y1ListBox}->GetText(); ## $this->{ini}->{YAxisPlotType} = $this->mw()->{NoteBook}->{ViewRangePaneFrame}->{GraphFrame1YAxisListBox}->GetText(); # } } if(!defined $filepath or $filepath eq '') { my $SampleFileName = $this->GetChooseFileInfo(1, 'FileName'); $filepath = $this->{ini}->{$SampleFileName}; $filepath = 'save.prm' if(!defined $filepath or $filepath eq ''); $filepath =~ s/\.csv$/\.prm/i; $filepath = Deps::ExtractFileName($filepath); my $ParameterFileMask = $this->GetChooseFileInfo(0, 'FileMask'); $filepath = $this->ChooseSaveFile($filepath, $ParameterFileMask); if($filepath) { my ($DefExt) = ($ParameterFileMask =~ /(\.[^\*]+)/); my $ext = Deps::ExtractExtention($filepath); if(!defined $ext or $ext eq '') { $filepath = Deps::ReplaceExtension($filepath, $DefExt); } $this->{ini}->{ParameterFile} = $filepath; } else { return; } } $this->{ini}->SetIniFile($filepath, undef, 1); $this->ComposeParameters($this->{dini}, $this->{ini}); if($this->{ini}->WriteAll()) { $this->App()->print("\nSucceeded to save ParameterFile to [$filepath].\n"); } else { $this->App()->print("\nFailed to save ParameterFile to [$filepath].\n"); } $this->DecomposeParameters($this->{ini}, $this->{dini}); } sub ReadParameterFile { my ($this, $filepath) = @_; my $ini = $this->{ini}; my $dini = $this->{dini}; $this->Initialize(1, 1); $this->App()->print("\nRead paramter from [$filepath].\n"); $this->{ini}->{FitXMin} = ''; $this->{ini}->{FitXMax} = ''; $this->{ini}->ReadAll($filepath); $this->DecomposeParameters($ini, $dini); # $this->RefreshMainPane($this->{EntryWidth}); my $ParameterFileName = $this->GetChooseFileInfo(0, 'FileName'); for(my $i = 1 ; ; $i++) { my $VarName = $this->GetChooseFileInfo($i, 'VarName'); my $FrameName = $this->GetChooseFileInfo($i, 'FrameName'); my $pAxes = $this->GetChooseFileInfo($i, 'pAxes'); last if(!defined $VarName); my $DataFrame = $this->{$FrameName}; # for(my $j = 0 ; $j < @$pAxes ; $j++) { # my $Axis = $pAxes->[$j]; # $DataFrame->{"${Axis}ListBox"}->SetText($this->{ini}->{"$VarName$Axis"}) if($this->{ini}->{"$VarName$Axis"}); ## $DataFrame->{Y1ListBox}->SetText($this->{ini}->{Sample1Y1}) if($this->{ini}->{Sample1Y1}); # } my $FileName = $this->GetChooseFileInfo($i, 'FileName'); my $path = $this->{ini}->{$FileName}; next if($path eq ''); $this->{ini}->{$FileName} = $this->GetValidDataPath($path, $filepath, $this->{ini}->{$ParameterFileName}); $this->{$VarName} = $this->ReadSampleDataFile($this->{ini}->{$FileName}, 1, $DataFrame, 0, 0); return undef unless($this->{$VarName}); } $this->{ini}->{$ParameterFileName} = $filepath; $this->RePlot(0, 1, 0, 0); # $this->RefreshViewRangePane($this->{EntryWidth}); $this->RePlot(1, 0, 1, 1); return 1; } sub ReadSampleDataFile { my ($this, $filepath, $IsPrint, $Frame, $UpdateRange, $IsPlot) = @_; $UpdateRange = 1 if(!defined $UpdateRange); $IsPlot = 0 if(!defined $IsPlot); $Frame = $this->{Sample1FileFrame} if(!defined $Frame); my $App = $this->App(); my $pX1DataLabel = $Frame->{pX1DataLabel}; my $pY1DataLabel = $Frame->{pY1DataLabel}; $this->Initialize(0, 1); my $pData = new Ellipsometry; $this->{Path} = $filepath; my ($nData, $pLabelArray, @pDataArray) = $pData->Read($filepath); if(!defined $nData) { $App->print("Error: Can not read [$filepath].\n"); return $this->{Path} = undef; } my $nDataArray = $pData->nDataArray(); $Frame->{X1ListBox}->DeleteAllItem() if(defined $Frame->{X1ListBox}); $Frame->{Y1ListBox}->DeleteAllItem() if(defined $Frame->{Y1ListBox}); for(my $i = 0 ; $i < $nDataArray ; $i++) { $Frame->{X1ListBox}->AddItem($pLabelArray->[$i]) if(defined $Frame->{X1ListBox}); $Frame->{Y1ListBox}->AddItem($pLabelArray->[$i]) if(defined $Frame->{Y1ListBox}); } $Frame->{X1ListBox}->SetCurSel(@$pX1DataLabel) if(defined $Frame->{X1ListBox}); $Frame->{Y1ListBox}->SetCurSel(@$pY1DataLabel) if(defined $Frame->{Y1ListBox}); $pData->GetXData(@$pX1DataLabel); $pData->GetYData(@$pY1DataLabel); $pData->CalMinMax(); if($UpdateRange or $this->{ini}->{FitXMin} eq '') { ($this->{ini}->{FitXMin}, $this->{ini}->{FitXMax}) = Utils::CalMinMax($pDataArray[0]); } if($IsPlot) { $this->RePlot($UpdateRange); } else { $this->CreateGraphFrame() if(!$this->GetGraphFrameArray()); $this->AssignGraphData(); } return $pData; } sub CreateGraphFrame { my ($this, $canvas, $TargetData) = @_; return if($this->GetGraphFrameArray()); $canvas = $this->Canvas() if(!defined $canvas); my $App = $this->App(); my $w = $canvas->width(); my $h = $canvas->height(); my $RefreshGraphScaleFrame = (defined $this->{GraphFrameArray})? 0 : 1; my $GraphFrameArray = $this->{GraphFrameArray} = new GraphFrameArray($this->mw()); $GraphFrameArray->SetCanvasSize($w, $h); my @GraphFrames; my $pPlotTypeArray = $this->{pPlotTypeArray}; for(my $i = 0 ; $i < @$pPlotTypeArray ; $i++) { $GraphFrameArray->AddGraphFrame(); $GraphFrames[$i] = $GraphFrameArray->GetGraphFrame($i); my $FramePosStr = $App->{"GraphFrame${i}Position"}; $GraphFrames[$i]->SetPositionByStr($FramePosStr); my $XScale = $GraphFrames[$i]->GetXScale(0); my $YScale = $GraphFrames[$i]->GetYScale(0); $XScale->SetScaleStringVisible(1); $XScale->SetCaptionVisible(1); } if($RefreshGraphScaleFrame) { $this->RefreshViewRangePane($this->{EntryWidth}); } } sub AssignGraphData { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); return if(!defined $this->{ini}->{Sample1CSVFile} or !defined $this->{Sample1CSV}); my $GraphFrameArray = $this->GetGraphFrameArray(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); $GraphFrame0->ClearAllData(); my $X1Label = $this->{Sample1FileFrame}->{X1ListBox}->GetText(); my $Y1Label = $this->{Sample1FileFrame}->{Y1ListBox}->GetText(); my $pObsX = $this->{Sample1CSV}->GetData($X1Label); my $pObsY = $this->{Sample1CSV}->GetData($Y1Label); $this->{Sample1CSV}->CalMinMax(); if($pObsX) { $GraphFrame0->AddGraphData($pObsX, $pObsY, 2, "black", "", 6, "red", 0, "red", "XAutoSkip", $X1Label, "$Y1Label (obs)"); } my $pCalX = $this->{pCalX}; my $pCalY = $this->{pCalY}; if($pCalX) { $GraphFrame0->AddGraphData($pCalX, $pCalY, 0, "", "circle", 3, "", 1, "red", "XAutoSkip", $X1Label, "$Y1Label (cal)"); } $GraphFrame0->SetXCaption($X1Label); $GraphFrame0->SetYCaption($Y1Label); $this->SetViewRange($ResetViewRange); } 1;