#!/bin/sh
# \
exec oagwish "$0" "$@"
set auto_path [linsert $auto_path 0 /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath

#
# Program to provide easy interface to SDDS statistical analysis tools
#

APSRenameExecToAPSBGExec

proc setStatus {text} {
    global status
    set status "[clock format [clock seconds] -format %H:%M:%S]: $text"
    update
}

APSApplication . -name quickSDDSStatistics \
    -version 1.0 -overview "Allows applying SDDS tools to statistical analysis of datasets."

setStatus Ready...
APSScrolledStatus .status -parent .userFrame -textVariable status -width 65 -packOption "-fill x"

set filename ""
if [llength $argv] {
    set args $argv
    APSParseArguments {filename}
}

# Creates windows to allow user to select the columns for indep. and dep. variables

proc varSelect {args} {
    set arrayName ""
    set filenameVariable ""
    set slot ""
    set label Independent
    set multiItem 0
    set label ""
    APSParseArguments {arrayName filenameVariable slot label multiItem label}

    global $arrayName 
    global [os editstring S/(/Z) $filenameVariable]
    set $filenameVariable [string trim [string trimright [set $filenameVariable]]]

    if ![string length [set $filenameVariable]] {
        setStatus "Give a filename!"
        return
    }
    if [catch {APSGetSDDSNames -class column -fileName [set $filenameVariable]} varList] {
        setStatus "$varList"
        return
    }
    set choiceList [APSChooseItemFromList -name "$label variable" \
                      -itemList $varList -returnList $varList -returnIndices 0 \
                      -multiItem $multiItem]
    set $arrayName\($slot\) [join $choiceList ,]
}

# Makes entry box and buttons for variable selection	

proc makeVariableFrame {widget args} {
    set filenameVariable ""
    set arrayName ""
    set parent ""
    set includex 1
    set includey 1
    set yMultiItem 1
    set xLabel Independent
    set yLabel Dependent
    APSStrictParseArguments {filenameVariable arrayName parent includex yMultiItem xLabel yLabel includey}
    APSFrame $widget -parent $parent -label Variables
    set vf $parent$widget.frame

    if $includex {
        APSFrame .x -parent $vf -relief flat
        set w $vf.x.frame
        APSFrame .f1 -parent $w -relief flat
        global $arrayName
        APSLabeledEntry .xVar -width 30 -label "$xLabel variable:" \
          -textVariable $arrayName\(xVar\) -parent $w.f1.frame \
          -packOption "-side left" -contextHelp "Enter the name of the $xLabel variable here \
	    or call up selection box with the button."
        APSButton .xselect -parent $w.f1.frame -packOption "-side right" -text "Select..." -command \
          "varSelect -arrayName $arrayName -slot xVar -filenameVariable $filenameVariable -label $xLabel -multiItem 0" \
          -contextHelp "Press to call up $xLabel variable selection box."
    }

    if $includey {
        APSFrame .y -parent $vf -relief flat
        APSLabeledEntry .yVar -width 30 -label "$yLabel variables:" \
          -textVariable $arrayName\(yVar\) -parent $vf.y.frame \
          -packOption "-side left" -contextHelp "Enter the names of the dependent variables here or call up \
	    selection box with the button."
        APSButton .yselect -parent $vf.y.frame -packOption "-side right" -text "Select..." -command \
          "varSelect -arrayName $arrayName -slot yVar -filenameVariable $filenameVariable -label $yLabel -multiItem $yMultiItem" \
          -contextHelp "Press to call up $yLabel variable selection box."
    }
}

proc AddCorrelateOptions {args} {
    set parent ""
    APSStrictParseArguments {parent}
    global Correlate
    set Correlate(rankOrder) "-rankOrder"
    set Correlate(stDevOutlier) 0
    set Correlate(outlierLimit) 1
    set Correlate(outlierPasses) 1
    set Correlate(make2DHistograms) 0
    set Correlate(ditherEnable) 1
    set Correlate(ditherAmount) 0.005
    set Correlate(plotLimit) 0.5

    APSLabeledEntry .output -parent $parent -label "Output file: " -width 90 \
      -commandButton 1 -textVariable Correlate(outputFile) 
    APSRadioButtonFrame .rankOrder -parent $parent -orientation horizontal \
      -variable Correlate(rankOrder) -label "Rank-order correlation: " \
      -buttonList "Yes No" \
      -valueList {"-rankOrder" ""} -contextHelp \
      "Choose whether to use rank-order correlations or standard correlations of values. The former is considered more robust."

    APSRadioButtonFrame .outlier -parent $parent -orientation horizontal \
      -variable Correlate(stDevOutlier) -label "Remove outliers: " \
      -buttonList "Yes No" -valueList "1 0" \
      -commandList [list "APSEnableWidget $parent.outlierOpts" "APSDisableWidget $parent.outlierOpts"] \
      -contextHelp \
      "Choose whether to remove outliers prior to correlation analysis."
    APSFrame .outlierOpts -parent $parent -relief flat -label "" -packOption "-fill x"
    set w1 $parent.outlierOpts.frame
    APSLabeledEntry .limit -parent $w1 -label "St. dev. limit: " -textVariable Correlate(outlierLimit) \
      -width 10 -type real
    APSLabeledEntry .passes -parent $w1 -label "Passes: " -textVariable Correlate(outlierPasses) \
      -width 10 -type real
    APSDisableWidget $parent.outlierOpts 

    APSLabeledEntry .dither -parent $parent -label "Dither amount for scatter plots: " \
      -textVariable Correlate(ditherAmount) -enableVariable Correlate(ditherEnable) \
      -width 10 -type real -contextHelp \
      "Choose whether to dither the values for scatter plots in order to get a better idea of the density of points when points are closely spaced (as when you are near the digitizer resolution limit).  This is a faster alternative to using 2D histograms.  The value is a fraction of the range of the data."
    APSLabeledEntry .limit -parent $parent -label "Correlation limit for scatter plots: " \
      -textVariable Correlate(plotLimit) -width 10 -type real -contextHelp \
      "Enter the minimum correlation for which plots will be made."

    set Correlate(plotLayout) -layout=1,1
    APSRadioButtonFrame .layout -parent $parent -label "Plot layout: " \
      -orientation horizontal -variable Correlate(plotLayout) \
      -buttonList "1x1 1x2 2x1 2x2 3x3 4x4 5x5 6x6" \
      -valueList "-layout=1,1 -layout=1,2 -layout=2,1 -layout=2,2 -layout=3,3 -layout=4,4 -layout=5,5 -layout=6,6" \
      -contextHelp \
      "Selected the plot layout, which gives the number of plots horizontally and vertically on each panel."

    APSRadioButtonFrame .hist2d -parent $parent -label "Make 2D Histograms:" \
      -orientation horizontal -variable Correlate(make2DHistograms) \
      -buttonList "Yes No" -valueList "1 0" -contextHelp \
      "Choose whether to make and plot 2d histograms.  Takes extra time."

    APSButton .copy -parent $parent -text "Copy..." -command "CopySettings -to Correlate"
    APSButton .correlate -parent $parent -text "Run" -command "RunCorrelate" 
    APSButton .disp -parent $parent -text "Redisplay" -command "DisplayCorrelate" 
    set Correlate(outputFile) ""
}

proc RunCorrelate {} {
    global Correlate
    if ![string length $Correlate(inputFile)] {
        setStatus "Supply an input filename"
        return
    }
    if ![string length $Correlate(outputFile)] {
        setStatus "Supply an output filename"
        return
    }
    if ![string length $Correlate(yVar)] {
        setStatus "Choose one or more dependent variables"
        return
    }
    APSAddToRecentFileList -filename $Correlate(inputFile)
    APSAddToRecentFileList -filename $Correlate(outputFile)

    set command "sddscorrelate -columns=[join $Correlate(yVar) ,] "
    foreach item {inputFile rankOrder} {
        if [string length [set Correlate\($item\)]] {
            append command "[set Correlate\($item\)] "
        }
    }
    if $Correlate(stDevOutlier) {
        append command "-stDevOutlier=limit=$Correlate(outlierLimit),passes=$Correlate(outlierPasses) "
    }
    if {[string length $Correlate(xVar)]} {
        append command "-withOnly=$Correlate(xVar) "
    }
    append command " -pipe=out | sddsprocess -pipe \"-define=column,AbsCC,CorrelationCoefficient abs\" -match=col,Correlate1Name=Correlate2Name,! | sddssort -pipe=in $Correlate(outputFile) -column=AbsCC,decreasing "
    setStatus "$command"
    if [catch {eval exec $command} result] {
        setStatus "$result"
        return
    }
    setStatus "Done."
    DisplayCorrelate
}

proc DisplayCorrelate {} {
    global Correlate
    set tmpFile /tmp/[APSTmpString]
    exec sddsprintout $Correlate(outputFile) $tmpFile \
      -column=CorrelationCoefficient,format=%12.3f,label=Corr.Coef. \
      -column=CorrelationSignificance,format=%12.3f,label=Corr.Signif. \
      -column=CorrelatePair,format=%60s -width=110
    APSFileDisplayWindow [APSUniqueName .] -width 120 -height 20 \
      -fileName $tmpFile -deleteOnClose 1 -sddsExportableFile $Correlate(outputFile) \
      -contextHelp "Shows the results of correlation analysis for $Correlate(inputFile).  The correlation significance is the probability of the observed correlation happening by chance when the variables are actually uncorrelated.  Hence, a smaller value means the correlation is more likely to be real."

    if [catch {sdds load $Correlate(outputFile) data} result] {
        return -code error "$result"
    }
    set rows [llength [lindex $data(Column.Correlate1Name) 0]]
    set correlate1List [lindex $data(Column.Correlate1Name) 0]
    set correlate2List [lindex $data(Column.Correlate2Name) 0]
    set coefList [lindex $data(Column.CorrelationCoefficient) 0]
    set sigList [lindex $data(Column.CorrelationSignificance) 0]
    set plotOptionList ""
    file delete $Correlate(outputFile).h2d
    set index 0
    foreach name1 $correlate1List name2 $correlate2List coef $coefList sig $sigList {
        if [expr abs($coef)<$Correlate(plotLimit)] continue
        set coef [format %10.4g $coef]
        set sig [format %10.4g $sig]
        lappend plotOptionList -column=$name1,$name2 
        lappend plotOptionList "-title=Corr. Coef.: $coef    Signif.: $sig"
        if $Correlate(make2DHistograms) {
            exec sddshist2d $Correlate(inputFile) $Correlate(outputFile).h2d.$index \
              -column=$name1,$name2 -xparam=$rows -yparam=$rows -minimumScale=1e-12
            lappend h2dList $Correlate(outputFile).h2d.$index
            incr index
        }
    }
    if ![llength $plotOptionList] {
        setStatus "No correlations greater than $Correlate(plotLimit) found"
        return
    }
    set dither [expr $Correlate(ditherAmount)*$Correlate(ditherEnable)]
    eval exec sddsplot $Correlate(inputFile) -dither=xrange=$dither,yrange=$dither \
      -separate -graph=dot $plotOptionList $Correlate(plotLayout) &
    if $Correlate(make2DHistograms) {
        eval exec sddscombine $h2dList $Correlate(outputFile).h2d -overWrite
        exec sddscontour -shade $Correlate(outputFile).h2d &
        eval file delete -force $h2dList 
    }
}

proc AddHistogramOptions {args} {
    set parent ""
    APSStrictParseArguments {parent}
    global Histogram

    set Histogram(outputFile) ""
    APSLabeledEntry .output -parent $parent -label "Output file: " -width 90 \
      -commandButton 1 -textVariable Histogram(outputFile) 

    set Histogram(bins) 20
    APSLabeledEntry .bins -parent $parent -label "Number of bins: " -textVariable Histogram(bins) \
      -width 10 -type integer
    set Histogram(sizeOfBins) 0.0
    APSLabeledEntry .sizeofbins -parent $parent -label "Size of bins: " -textVariable Histogram(sizeOfBins) \
      -width 10 -type real

    set Histogram(lowerLimitGiven) 0
    set Histogram(lowerLimit) 0.0
    set Histogram(lowerLimitGiven) 0
    APSLabeledEntry .lowerLimit -parent $parent -label "Lower limit: " -textVariable Histogram(lowerLimit) \
      -enableVariable Histogram(lowerLimitGiven) -width 10 -type real 

    set Histogram(upperLimitGiven) 0
    set Histogram(upperLimit) 0.0
    set Histogram(upperLimitGiven) 0
    APSLabeledEntry .upperLimit -parent $parent -label "Upper limit: " -textVariable Histogram(upperLimit) \
      -enableVariable Histogram(upperLimitGiven) -width 10 -type real

    set Histogram(cdf) no
    APSRadioButtonFrame .cdf -parent $parent -label "CDF: " \
        -orientation horizontal -variable Histogram(cdf) \
        -buttonList "No Yes Only" \
        -valueList "0 1 2" -contextHelp \
        "Select whether to include the CDF (Cumulative Distribution Function)"

    set Histogram(plotLayout) -layout=1,1
    APSRadioButtonFrame .layout -parent $parent -label "Plot layout: " \
        -orientation horizontal -variable Histogram(plotLayout) \
        -buttonList "1x1 1x2 2x1 2x2 2x2 3x3 4x4 5x5 6x6" \
        -valueList "-layout=1,1 -layout=1,2 -layout=2,1 -layout=2,2 -layout=3,3 -layout=4,4 -layout=5,5 -layout=6,6" \
        -contextHelp \
        "Select the plot layout, which gives the number of plots horizontally and vertically on each panel."
    
    APSButton .copy -parent $parent -text "Copy..." -command "CopySettings -to Histogram"
    APSButton .histogram -parent $parent -text "Run" -command "RunHistogram" 
    APSButton .disp -parent $parent -text "Redisplay" -command "DisplayHistogram" 
}

proc RunHistogram {} {
    global Histogram
    if ![string length $Histogram(inputFile)] {
        setStatus "Supply an input filename"
        return
    }
    if ![string length $Histogram(outputFile)] {
        setStatus "Supply an output filename"
        return
    }
    if ![string length $Histogram(yVar)] {
        setStatus "Choose one or more dependent variables"
        return
    }
    APSAddToRecentFileList -filename $Histogram(inputFile)
    APSAddToRecentFileList -filename $Histogram(outputFile)
    
    set command "sddsmultihist -expand=0.001 -separate -sides -columns=[join $Histogram(yVar) ,] "
    foreach item {inputFile outputFile} {
        if [string length [set Histogram\($item\)]] {
            append command "[set Histogram\($item\)] "
        }
    }
    if [expr $Histogram(sizeOfBins)>0] {
        append command "-sizeOfBins=$Histogram(sizeOfBins) "
    } else {
        if $Histogram(bins)>0 {
            append command "-bins=$Histogram(bins) "
        } else {
            setStatus "You must have positive value for size of bins or number of bins."
            return
        }
    }

    set number [llength [split $Histogram(yVar) ,]]
    if $Histogram(lowerLimitGiven) {
        append command "-lowerLimit=[join [APSReplicateItem -item $Histogram(lowerLimit) -number $number ] ,] "
    }
    if $Histogram(upperLimitGiven) {
        append command "-upperLimit=[join [APSReplicateItem -item $Histogram(upperLimit) -number $number ] ,] "
    }
    switch $Histogram(cdf) {
        1 {
            append command "-cdf"
        } 
        2 {
            append command "-cdf=only"
        }
    }

    setStatus "$command"
    if [catch {eval exec $command} result] {
        setStatus "$result"
        return
    }
    setStatus "Done."
    DisplayHistogram
}

proc DisplayHistogram {} {
    global Histogram
    set plotArguments "-column=*,%sFrequency -graph=impulse"
    switch $Histogram(cdf) {
        0 {
            set plotArguments "-column=*,%sFrequency -graph=impulse"
        }
        1 {
            set plotArguments "-column=*,%sFrequency -graph=impulse -end -column=*,%sCdf -graph=line"
        }
        2 {
            set plotArguments "-column=*,%sCdf -graph=line"
        }
    }
    APSExec -unixCommand "sddsplot $Histogram(plotLayout) -separate $Histogram(outputFile) $plotArguments"

}

proc AddStatisticsOptions {args} {
    set parent ""
    APSStrictParseArguments {parent}
    global Statistics

    set Statistics(outputFile) ""
    APSLabeledEntry .output -parent $parent -label "Output file: " -width 90 \
      -commandButton 1 -textVariable Statistics(outputFile) 

    set Statistics(average) 1
    set Statistics(median) 1
    set Statistics(standarddeviation) 1
    set Statistics(sigma) 1
    set Statistics(qrange) 1
    set Statistics(drange) 1

    APSCheckButtonFrame .compute -parent $parent -label "Compute: " -orientation horizontal \
      -limitPerRow 3 \
      -buttonList [list Mean Median "Standard Deviation" Sigma "Quartile Range" "Decile Range"] \
      -variableList [list Statistics(average) Statistics(median) Statistics(standarddeviation) \
                     Statistics(sigma) Statistics(qrange) Statistics(drange)] \
      -contextHelp \
      "Select the statistics you wish to compute."

    set Statistics(sortBy) StDev
    APSRadioButtonFrame .sort -parent $parent -label "Sort by: " -orientation horizontal \
      -limitPerRow 3 -variable Statistics(sortBy) \
      -buttonList [list Name Mean Median "Standard Deviation" Sigma "Quartile Range" "Decile Range"] \
      -valueList [list Rootname Mean Median StDev Sigma QRange DRange] \
      -contextHelp \
      "Select the statistic or quantity you wish to sort the results by."

    APSButton .copy -parent $parent -text "Copy..." -command "CopySettings -to Statistics"
    APSButton .statistics -parent $parent -text "Run" -command "RunStatistics" 
    APSButton .disp -parent $parent -text "Redisplay" -command "DisplayStatistics" 
}

proc RunStatistics {} {
    global Statistics
    if ![string length $Statistics(inputFile)] {
        setStatus "Supply an input filename"
        return
    }
    if ![string length $Statistics(outputFile)] {
        setStatus "Supply an output filename"
        return
    }
    if ![string length $Statistics(yVar)] {
        setStatus "Choose one or more dependent variables"
        return
    }
    APSAddToRecentFileList -filename $Statistics(inputFile)
    APSAddToRecentFileList -filename $Statistics(outputFile)

    set command "sddsprocess -nowarning $Statistics(inputFile) -pipe=out "
    foreach mode [list average median standarddeviation sigma qrange drange] \
      tag [list Mean Median StDev Sigma QRange DRange ] {
          if !$Statistics($mode) continue
          lappend collectOptList -collect=suffix=$tag
          foreach column [split $Statistics(yVar) ,] {
              append command "-process=$column,$mode,%s$tag "
          }
    }
    if ![llength $collectOptList] {
        setStatus "No statistics selected."
        return
    }
    append command "| sddscollapse -pipe | sddsconvert -pipe -delete=column,OriginalPage -delete=parameter,OriginalPage | sddscollect -nowarning -pipe "
    foreach opt $collectOptList {
        append command "$opt "
    }
    append command "| sddssort -pipe=in $Statistics(outputFile) -column=$Statistics(sortBy),decreasing "
    setStatus "$command"
    if [catch {eval exec $command} result] {
        setStatus "$result"
        return
    }
    setStatus "Done."
    DisplayStatistics
}

proc DisplayStatistics {} {
    global Statistics

    lappend printOptList -column=Rootname,format=%32s,label=Data 
    set count 0
    foreach mode [list average median standarddeviation sigma qrange drange] \
      tag [list Mean Median StDev Sigma QRange DRange] {
          if !$Statistics($mode) continue
          incr count
          lappend printOptList -column=$tag,format=%13.6g
      }
    set tmpFile /tmp/[APSTmpString]
    lappend printOptList -column=Units,format=%8s
    if [catch {eval exec sddsprintout -width=135 $Statistics(outputFile) $tmpFile $printOptList} result] {
        setStatus "$result"
        return
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile -deleteOnClose 1 \
      -width 140 -height 20 \
      -comment "Statistics for $Statistics(inputFile)" \
      -sddsExportableFile $Statistics(outputFile)  \
      -contextHelp \
      "Shows statistical analysis for $Statistics(inputFile).  The \"sigma\" value is the error bar for the mean.  The \"QRange\" and \"DRange\" are, respectively, the quartile and decile ranges, which contain, respectively, the middle 50% and 80% of the data."
}


proc AddOutlierOptions {args} {
    set parent ""
    APSStrictParseArguments {parent}
    global Outlier

    set Outlier(outputFile) ""
    APSLabeledEntry .output -parent $parent -label "Output file: " -width 90 \
      -commandButton 1 -textVariable Outlier(outputFile) 

    set Outlier(stDevLimit) 3.0
    set Outlier(stDevLimitOn) 0
    set Outlier(absLimit) 1e300
    set Outlier(absLimitOn) 0
    set Outlier(absDeviationLimit) 1e300
    set Outlier(absDeviationLimitOn) 0
    set Outlier(minimumLimit) -1e300
    set Outlier(minimumLimitOn) 0
    set Outlier(maximumLimit) 1e300
    set Outlier(maximumLimitOn) 0
    set Outlier(passes) 1
    set Outlier(invert) 0
    set Outlier(markOnly) 0
    set Outlier(replaceOnly) 0

    APSFrame .limits -parent $parent -label "Limits to impose"
    foreach item {stDevLimit absLimit absDeviationLimit minimumLimit maximumLimit} \
      label {"Standard deviation:" "Absolute value:" "Absolute deviation from mean:" \
               "Minimum:" "Maximum:"} {
        APSLabeledEntry .$item -parent $parent.limits.frame -label $label -textVariable Outlier($item) \
          -type real -enableVariable Outlier(${item}On) -width 10 \
          -contextHelp "Enter limit for [string tolower $label]"
    }
    APSLabeledEntry .passes -parent $parent -label "Passes: " -textVariable Outlier(passes) \
      -type real -width 10 -contextHelp "Enter the number of times to apply outlier elimination successively."
    APSCheckButtonFrame .invert -parent $parent -label "Options:" \
      -buttonList {Invert "Mark Only" "Replace Only"} \
      -variableList {Outlier(invert) Outlier(markOnly) Outlier(replaceOnly)} \
      -orientation horizontal -contextHelp "Choose invert to keep outliers and discard inliers.  Choose mark-only if you only want to mark the outliers, not remove them; the mark is record in a column named IsOutlier in the output file.  Choose replaceOnly if you want to replace the outlier with a value interpolated from the surrounding values."

    APSButton .copy -parent $parent -text "Copy..." -command "CopySettings -to Outlier"
    APSButton .outlier -parent $parent -text "Run" -command "RunOutlier" 
}

proc RunOutlier {} {
    global Outlier
    if ![string length $Outlier(inputFile)] {
        setStatus "Supply an input filename"
        return
    }
    if ![string length $Outlier(outputFile)] {
        setStatus "Supply an output filename"
        return
    }
    if ![string length $Outlier(yVar)] {
        setStatus "Choose one or more dependent variables"
        return
    }
    APSAddToRecentFileList -filename $Outlier(inputFile)
    APSAddToRecentFileList -filename $Outlier(outputFile)

    set command "sddsoutlier -nowarning $Outlier(inputFile) $Outlier(outputFile) -column=[join $Outlier(yVar) ,] -passes=$Outlier(passes) "
    foreach item {stDevLimit absLimit absDeviationLimit minimumLimit maximumLimit} {
        if [set Outlier(${item}On)] {
            append command "-$item=[set Outlier\($item\)] "
        }
    }
    foreach item {invert markOnly}  {
        if [set Outlier\($item\)] {
            append command "-$item "
        }
    }
    if $Outlier(replaceOnly) {
        append command "-replaceOnly=interpolate "
    }
    setStatus "$command"
    if [catch {eval exec $command} result] {
        setStatus "$result"
        return
    }
    set origRows [exec sdds2stream -rows=bare,total $Outlier(inputFile)]
    set newRows  [exec sdds2stream -rows=bare,total $Outlier(outputFile)]
    setStatus "Input: $origRows rows"
    setStatus "Output: $newRows rows"
    setStatus "Done."
}

proc CopySettings {args} {
    set to ""
    APSStrictParseArguments {to}

    if ![string length $to] return
    global $to
    global tabLabelList
    set fromList ""
    foreach item $tabLabelList {
        if [string compare $item $to]==0 continue
        lappend fromList $item
    }
    set from [APSChooseItemFromList -name "Copy from where?" \
                -itemList $fromList -returnIndices 0 \
                -multiItem 0]
    if ![string length $from] return
    global $from
    foreach item {inputFile xVar yVar} {
        if ![info exists $to\($item\)] {
            continue
        }
        if ![info exists $from\($item\)] {
            continue
        }
        set $to\($item\) [set $from\($item\)]
    }
}

proc FillTabFrame {widget args} {
    set type ""
    set filename ""
    set includex 1
    set includey 1
    set yMultiItem 1
    set xLabel Independent
    set yLabel Dependent
    APSStrictParseArguments {type filename includex yMultiItem includey xLabel yLabel}
    APSLabeledEntry .file -parent $widget -textVariable $type\(inputFile\) \
      -width 70 -commandButton 1 -label "Filename: " 
    if {$includex || $includey} {
        makeVariableFrame .vf -parent $widget -filenameVariable $type\(inputFile\) \
          -arrayName $type -includex $includex -yMultiItem $yMultiItem -includey $includey \
          -xLabel $xLabel -yLabel $yLabel
    }
    if [string length $filename] {
        global $type
        set $type\(inputFile\) $filename
    }
    Add${type}Options -parent $widget
}

proc SelectRunningStatsColumns {args} {
    set type ""
    APSStrictParseArguments {type}
    global RunningStats
    if ![string length $RunningStats(inputFile)] {
        setStatus "Supply an input file."
        return
    }
    if ![file exists $RunningStats(inputFile)] {
        setStatus "$RunningStats(inputFile) doesn't exist."
        return
    }
    if [catch {APSGetSDDSNames -class column -fileName $RunningStats(inputFile)} varList] {
        setStatus "$varList"
        return
    }
    set choiceList [APSChooseItemFromList -name "$type choices" \
                      -itemList $varList -returnList $varList -returnIndices 0 \
                      -multiItem 1]
    set RunningStats($type,columnList) [join $choiceList ,]
}

proc FillRunningStatsSelectionWidget {widget args} {
    set type ""
    set help ""
    set label ""
    APSStrictParseArguments {type help label}
    global RunningStats apsContextHelp
    set apsContextHelp($widget) "$help"
    APSFrame .leframe -parent $widget -label "" -relief flat
    APSLabeledEntry .list -parent $widget.leframe.frame -width 50 -packOption "-side left" \
      -label "Columns: " -textVariable RunningStats($type,columnList) \
      -contextHelp "Enter the names of the columns for which to compute \"$label\". $help"
    APSButton .sele -parent $widget.leframe.frame -text "Select..." -packOption "-side right" \
      -command "SelectRunningStatsColumns -type $type" \
      -contextHelp "Press to select the names of the columns for which to compute \"$label\". $help"
    set RunningStats($type,lowerLimitGiven) 0
    set RunningStats($type,lowerLimit) 0.0
    APSLabeledEntry .lowerLimit -parent $widget \
      -label "Lower limit: " -textVariable RunningStats($type,lowerLimit) \
      -enableVariable RunningStats($type,lowerLimitGiven) \
      -packOption "-side left" -type real \
      -contextHelp "Provide lower limit for the values to include in computations."
    set RunningStats($type,upperLimitGiven) 0
    set RunningStats($type,upperLimit) 0.0
    APSLabeledEntry .upperLimit -parent $widget \
      -label "Upper limit: " -textVariable RunningStats($type,upperLimit) \
      -enableVariable RunningStats($type,upperLimitGiven) \
      -packOption "-side right" -type real \
      -contextHelp "Provide upper limit for the values to include in computations."
}

proc FillRunningStatsTabFrame {widget} {
    global RunningStats
    APSLabeledEntry .file -parent $widget -textVariable RunningStats(inputFile) \
      -width 70 -commandButton 1 -label "Filename: " 
    set typeList {sample mean minimum maximum standardDeviation sigma sum}
    set RunningStats(typeList) $typeList
    set labelList {Sample Mean Minimum Maximum "Stand. Dev." "Sigma" "Sum"}
    set helpList {"first sample value in the window that is inside the limits." \
                    "mean of the values in the window that are inside the limits." \
                    "minimum of the values in the window that are inside the limits." \
                    "maximum of the values in the window that are inside the limits." \
                    "standard deviation of the values in the window that are inside the limits." \
                    "standard deviation of the values in the window that are inside the limits, divided by the square-root of the number of values." \
                    "sum of the values in the window that are inside the limits." }
    set widgetList [APSTabFrame .main -parent $widget -label "Statistics" \
                      -labelList $labelList -width 700 -height 100]
    foreach type $typeList label $labelList help $helpList widget1 $widgetList {
        FillRunningStatsSelectionWidget $widget1 -help "This statistic provides the $help" \
          -type $type -label $label
    }
    set RunningStats(points) 10
    APSLabeledEntry .points -parent $widget -label "Points in window: " \
      -textVariable RunningStats(points) -type integer -width 10 \
      -contextHelp "Enter the number of points in the statistics window."
    set RunningStats(noOverlap) 0
    APSRadioButtonFrame .overlap -parent $widget -label "Overlapping window: " \
      -buttonList "Yes No" -valueList "0 1" -orientation horizontal \
      -variable RunningStats(noOverlap) -contextHelp \
      "By default, the statistics window is a sliding window, so that the first row is removed and a new row added at the other end.  If No is selected for this option, then successive statistics are for non-overlapping but adjacent sets of rows."
    APSLabeledEntry .output -parent $widget -textVariable RunningStats(outputFile) \
      -width 60 -commandButton 1 -label "Output filename: " 
    APSButton .copy -parent $widget -text "Copy..." -command "CopySettings -to RunningStats"
    APSButton .run -parent $widget -text "Run" -command "RunRunningStats"
}

proc RunRunningStats {} {
    global RunningStats
    if ![string length $RunningStats(inputFile)] {
        setStatus "Supply an input filename"
        return
    }
    if ![string length $RunningStats(outputFile)] {
        setStatus "Supply an output filename"
        return
    }

    set optionList ""
    foreach type $RunningStats(typeList) {
        if [string length $RunningStats($type,columnList)]==0 continue
        set option -$type=
        if $RunningStats($type,lowerLimitGiven) {
            append option bottomLimit=$RunningStats($type,lowerLimit),
        }
        if $RunningStats($type,upperLimitGiven) {
            append option topLimit=$RunningStats($type,upperLimit),
        }
        append option [join $RunningStats($type,columnList) ,]
        lappend optionList $option
    }
    if ![llength $optionList] {
        setStatus "Supply some columns to process under the individual statistics tabs."
        return
    }
    APSAddToRecentFileList -filename $RunningStats(inputFile)
    APSAddToRecentFileList -filename $RunningStats(outputFile)
    
    set command "sddsrunstats $optionList "
    foreach item {inputFile outputFile} {
        if [string length [set RunningStats\($item\)]] {
            append command "[set RunningStats\($item\)] "
        }
    }
    setStatus "$command"
    if [catch {eval exec $command} result] {
        setStatus "$result"
        return
    }
    setStatus "Done."
}


set tabLabelList [list Histogram Correlate Statistics Outlier RunningStats]
set tabWidgetList [APSTabFrame .main -parent .userFrame -label "" \
                     -labelList $tabLabelList -width 700 -height 500]
foreach label $tabLabelList widget $tabWidgetList {
    set tabWidget(${label}) $widget
}

FillTabFrame $tabWidget(Histogram) \
 -includex 0 -includey 1 -yLabel "Data" \
  -type Histogram -filename $filename

FillTabFrame $tabWidget(Correlate) -type Correlate \
  -filename $filename

FillTabFrame $tabWidget(Statistics) -type Statistics \
  -includex 0 -yLabel "Data"  -filename $filename

FillTabFrame $tabWidget(Outlier) -type Outlier \
  -includex 0 -yLabel "Data"  -filename $filename

FillRunningStatsTabFrame $tabWidget(RunningStats) 
