#!/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)]

set CVSRevisionAuthor "\$Revision: 1.30 $ \$Author: soliday $"

set screenheight [winfo screenheight .]
set apsttk 1

set small 0
set args $argv
APSStrictParseArguments {small}
if {$small} {
    set screenheight 900
}
APSApplication . -name DataLoggerViewer -version $CVSRevisionAuthor

set thisPlatform $::tcl_platform(platform)
if {$thisPlatform eq "unix" && [tk windowingsystem] eq "aqua"} {
    set thisPlatform "macosx"
}

proc InitTheme {} {
 
    #TButton Options
    #.border -background -borderwidth -relief
    #.focus -focuscolor -focusthickness
    #.padding -padding -relief -shiftrelief
    #.label -compound -space -text -font -foreground -underline -width 
    #       -anchor -justify -wraplength -embossed -image -stipple -background

    ttk::style configure Tight.TButton -padding 2 -shiftrelief 0 -focusthickness 0 -width 0


    #TSpinbox Options
    #.field -fieldbackground -borderwidth
    #.uparrow -background -relief -borderwidth -arrowcolor -arrowsize
    #.downarrow -background -relief -borderwidth -arrowcolor -arrowsize
    #.padding -padding -relief -shiftrelief
    #.textarea -font -width
    #puts [ttk::style layout TSpinbox]
    #puts [ttk::style element options Spinbox.textarea]
    ttk::style configure Tall.TSpinbox -arrowsize 12
}
 
InitTheme 


package require treectrl
#option add *TreeCtrl.useTheme 1
switch -- $::thisPlatform {
    macosx -
    unix {
	option add *TreeCtrl.columnResizeMode realtime
    }
    windows {
	if {$::tcl_platform(os) eq "Windows NT"} {
	    option add *TreeCtrl.columnResizeMode realtime
	}
    }
}

set tmpPrefix [APSTmpDir]
set stderrFile $tmpPrefix/[APSTmpString]
APSAddToTempFileList $stderrFile
# Create some photo images on demand
proc InitPics {args} {
    global env
    foreach pattern $args {
	if {[lsearch [image names] $pattern] == -1} {
	    if {[file exists /usr/local/oag/apps/images]} {
	      foreach file [glob -directory /usr/local/oag/apps/images $pattern.gif] {
		set imageName [file root [file tail $file]]
		# I created an image called "file", which clobbered the
		# original Tcl command "file". Then I got confused.
		if {[llength [info commands $imageName]]} {
		    error "don't want to create image called \"$imageName\""
		}
		image create photo $imageName -file $file

		# Hack -- Create a "selected" version too
		image create photo ${imageName}Sel
		${imageName}Sel copy $imageName
#		imagetint ${imageName}Sel $::SystemHighlight 128
	      }
	    }
	    if {[info exists env(TK_IMAGES)]} {
	      foreach file [glob -directory $env(TK_IMAGES) $pattern.gif] {
		set imageName [file root [file tail $file]]
		# I created an image called "file", which clobbered the
		# original Tcl command "file". Then I got confused.
		if {[llength [info commands $imageName]]} {
		    error "don't want to create image called \"$imageName\""
		}
		image create photo $imageName -file $file

		# Hack -- Create a "selected" version too
		image create photo ${imageName}Sel
		${imageName}Sel copy $imageName
#		imagetint ${imageName}Sel $::SystemHighlight 128
	      } 
	    }
	}
    }
    return
}

proc CreateDataLoggerTree {frame} {
    global timeSeriesConfig SampleInterval MonitorDataReview

    APSScrolledStatus .status \
      -parent $frame \
      -textVariable status \
      -width 40 \
      -noPack 1
    bind $frame.status.frame.fg.top.text <Button-4> "%W yview scroll -2 unit"
    bind $frame.status.frame.fg.top.text <Button-5> "%W yview scroll 2 unit"

    set T $frame.t

    grid columnconfigure $frame 0 -weight 1
    grid rowconfigure $frame 1 -weight 1

    global screenheight
    if {$screenheight < 960} {
        treectrl $T \
          -background white \
          -selectmode multiple \
          -showroot no \
          -showbuttons yes \
          -showlines 1 \
          -width 300 \
          -height 150 \
          -font TkDefaultFont \
          -xscrollincrement 1
    } else {
        treectrl $T \
          -background white \
          -selectmode multiple \
          -showroot no \
          -showbuttons yes \
          -showlines 1 \
          -width 300 \
          -height 300 \
          -font TkDefaultFont \
          -xscrollincrement 1
    }

    ttk::scrollbar $frame.sh -orient horizontal -command "$T xview"
    $T notify bind $frame.sh <Scroll-x> { %W set %l %u }
    bind $frame.sh <ButtonPress-1> "focus $T"

    ttk::scrollbar $frame.sv -orient vertical -command "$T yview"
    $T notify bind $frame.sv <Scroll-y> { %W set %l %u }
    bind $frame.sv <ButtonPress-1> "focus $T"

    grid configure $frame.status -row 0 -column 0 -sticky news -columnspan 2
    
    grid configure $T -row 1 -column 0 -sticky news
    grid configure $frame.sh -row 2 -column 0 -sticky we
    grid configure $frame.sv -row 1 -column 1 -sticky ns

    $T column create \
      -expand yes \
      -text "Data Loggers" \
      -tag 0
    $T configure \
      -treecolumn 0

    $T state define check
    $T state define on

    InitPics check-on check-off
    $T element create elemImg image -image {
        check-on {check on}
        check-off {check}
    }
    $T element create elemTxt text
    $T element create elemRectSel rect \
      -fill [list grey {selected focus}] \
      -showfocus yes

    set S [$T style create STYLE]
    $T style elements $S {elemRectSel elemImg elemTxt}
    $T style layout $S elemImg \
      -padx {0 4} \
      -expand ns
    $T style layout $S elemTxt \
      -expand ns
    $T style layout $S elemRectSel \
      -union [list elemTxt] \
      -iexpand ns \
      -ipadx 2

    foreach TabName [lindex $timeSeriesConfig(Column.TabName) 0] \
      monitorProgram [lindex $timeSeriesConfig(Column.monitorProgram) 0] \
      GroupName [lindex $timeSeriesConfig(Column.GroupName) 0] \
      sampleInterval [lindex $timeSeriesConfig(Column.sampleInterval) 0] \
      doRun [lindex $timeSeriesConfig(Column.doRun) 0] \
      doOnePvPerFileRun [lindex $timeSeriesConfig(Column.doOnePvPerFileRun) 0] {
          if {($monitorProgram != "sddslogger") && ($monitorProgram != "sddspvalogger") && ($monitorProgram != "sddsstatmon")} { continue }
          if {$TabName == ""} {continue}
          lappend TabNameList $TabName
          lappend sublevel($TabName) $GroupName

          set sampleInterval [expr {round($sampleInterval)}]
          if {$sampleInterval < 2} {
              set sampleInterval 1
          } elseif {$sampleInterval < 4} {
              set sampleInterval 2
          } elseif {$sampleInterval < 8} {
              set sampleInterval 4
          } elseif {$sampleInterval < 16} {
              set sampleInterval 8
          } elseif {$sampleInterval < 29.9} {
              set sampleInterval 16
          } elseif {$sampleInterval < 59.9} {
              set sampleInterval 32
          } elseif {$sampleInterval < 119.9} {
              set sampleInterval 64
          } elseif {$sampleInterval < 256} {
              set sampleInterval 128
          } else {
              set sampleInterval 256
          }
          set SampleInterval($GroupName) $sampleInterval
          if {($doOnePvPerFileRun == 0) && ($doRun == 1)} {
              set MonitorDataReview($GroupName) 1
          } else {
              set MonitorDataReview($GroupName) 0
          }
    }

    set toplevel [lsort -unique -dictionary $TabNameList]

    set TabName "Old PVs"
    set GroupName "All Old PVs"
    set sampleInterval "0"
    lappend toplevel $TabName
    lappend sublevel($TabName) $GroupName
    set SampleInterval($GroupName) $sampleInterval

    foreach t $toplevel {
        set sublevel($t) [lsort -dictionary $sublevel($t)]
    }

    foreach l1 $toplevel {
        append buttons "0 off \"$l1\" "
        foreach l2 $sublevel($l1) {
            append buttons "1 off \"$l2\" "
        }
    }

    set parentList [list root {} {} {} {} {} {}]
    foreach {depth setting text} $buttons {
        set item [$T item create]
        $T item style set $item 0 STYLE
        $T item element configure $item 0 elemTxt \
          -text $text
        $T item element configure $item 0 elemImg \
          -image check-$setting
        if {$depth == 0} {
            $T item configure $item \
              -button yes
            $T item collapse $item
        }

        $T item lastchild [lindex $parentList $depth] $item
        incr depth
        set parentList [lreplace $parentList $depth $depth $item]
    }

    bind DataLoggerOptions <ButtonPress-1> {
        ::TreeCtrl::ButtonPress1 %W %x %y
        DataLoggerClicked %W %x %y ""
        break
    }
    bind DataLoggerOptions <Button-4> {
        %W yview scroll -2 unit
        break
    }
    bind DataLoggerOptions <Button-5> {
        %W yview scroll 2 unit
        break
    }

    bindtags $T [list $T DataLoggerOptions TreeCtrl [winfo toplevel $T] all]
    
    return $T
}

proc DataLoggerClicked {T x y id} {
    global PVtreectrl PresetTreectrl timeSeriesConfig 
    global PlotOptions timeSeriesSDDS timeSeriesOldPVsSDDS PVtreesort status includefilter excludefilter
    global SelectedDataLoggers

    focus $T
    if {$id == ""} {
        set id [$T identify $x $y]
    }
    #Click outside of any item
    if {$id eq ""} {
        #Click in header
    } elseif {[lindex $id 0] eq "header"} {
        #Click in item
    } else {
        set item [lindex $id 1]
        if {[lindex $id 2] == "button"} {
            #Click on expand button
        } else {
            #$T selection modify $item all
            $T activate $item
            if {[$T item element cget $item 0 elemImg -image] == "check-on"} {
                set setting off
            } else {
                set setting on
            }
            $T item element configure $item 0 elemImg \
              -image check-$setting
            if {[$T depth $item] == 1} {
                foreach child [$T item children $item] {
                    set groupname [$T item element cget $child 0 elemTxt -text]
                    if {($groupname == "SR DCPS: 100Hz statistics for correctors") || \
                        ($groupname == "SR DCPS: 100Hz statistics for multipoles") || \
                        ($groupname == "SR Injection Waveforms") || \
                        ($groupname == "SR rf Fast") || \
                        ($groupname == "Weather") || \
                        ($groupname == "Booster Injection Waveforms") || \
                        ($groupname == "SR Feedback Corrector Errors")} {
                            continue
                        }
                    $T item element configure $child 0 elemImg \
                      -image check-$setting
                    if {$setting == on} {
                        $T selection add $child
                    } else {
                        $T selection clear $child
                    }
                }
            } elseif {$setting == "off"} {
                $T item element configure [$T item parent $item] 0 elemImg \
                  -image check-$setting
                $T selection clear [$T item parent $item]
            } elseif {$setting == "on"} {
                set parent [$T item parent $item]
                set allselected 1
                foreach child [$T item children $parent] {
                    if {[$T item element cget $child 0 elemImg -image] != "check-on"} {
                        set allselected 0
                        break
                    }
                }

                if {$allselected} {
                    $T item element configure $parent 0 elemImg \
                      -image check-$setting
                    $T selection add $parent
                }
            }
            update
            if {[catch {$PVtreectrl item count} count]} {
                set count [$PVtreectrl numitems]
            }
            set previouslyselectedX ""
            set previouslyselectedY ""
            for {set i 1} {$i < $count} {incr i} {
                if {[$PVtreectrl item element cget $i 0 elemImg -image] == "check-on"} {
                    append previouslyselectedX "[$PVtreectrl item element cget $i 2 elemTxt -text] "
                }
                if {[$PVtreectrl item element cget $i 1 elemImg -image] == "check-on"} {
                    append previouslyselectedY "[$PVtreectrl item element cget $i 2 elemTxt -text] "
                }
            }
            $PVtreectrl item delete all
            $PresetTreectrl item delete all
            set PlotOptions(timeXaxis) 1
            update
            
            set categories [$T item numchildren root]
            set parent 1
            set found 0
            set SelectedDataLoggers ""
            global MonitorDataReview extraLoggers
            set extraLoggers ""
            for {set i 0} {$i < $categories} {incr i} {
                set children [$T item children $parent]
                foreach child $children {
                    if {[$T item element cget $child 0 elemImg -image] == "check-on"} {
                        set groupname [$T item element cget $child 0 elemTxt -text]
#                        if {[info exists MonitorDataReview($groupname)] && $MonitorDataReview($groupname)} {
#                            APSSetVarAndUpdate status "$groupname must be plotted from MonitorDataReview"
#                            continue
#                        }
                        if {$groupname == "All Old PVs"} {
                            set index [lsearch -exact $timeSeriesOldPVsSDDS(Parameter.GroupName) $groupname]
                        } else {
                            set index [lsearch -exact $timeSeriesSDDS(Parameter.GroupName) $groupname]
                        }
                        if {$index == -1} {
                            bell
                            APSSetVarAndUpdate status "Found problem with $groupname"
                            continue
                        }
                        lappend SelectedDataLoggers $groupname
                        if {$groupname == "All Old PVs"} {
                            set cnList [lindex $timeSeriesOldPVsSDDS(Column.ControlName) $index]
                        } else {
                            set cnList [lindex $timeSeriesSDDS(Column.ControlName) $index]
                        }
                        if {[info exists MonitorDataReview($groupname)] && $MonitorDataReview($groupname)} {
                            lappend extraLoggers $groupname
                            if {($groupname == "SR DCPS: 100Hz statistics for correctors") || ($groupname == "SR DCPS: 100Hz statistics for multipoles")} {
                                foreach cn $cnList {
                                    append ControlNameList "${cn}Mean ${cn}Min ${cn}Max "
                                }
                            } elseif {$groupname == "SR Feedback Corrector Errors"} {
                                foreach cn $cnList {
                                    append ControlNameList "${cn}Mean "
                                }
                            } else {
                                foreach cn $cnList {
                                    append ControlNameList "$cn "
                                }
                            }
                        } else {
                            foreach cn $cnList {
                                if {[string range $cn end-3 end] == ".VAL"} {
                                    append ControlNameList "[string range $cn 0 end-4] "
                                } else {
                                    append ControlNameList "$cn "
                                }
                            }
                        }
                        if {$groupname == "All Old PVs"} {
                            append ReadbackNameList "[lindex $timeSeriesOldPVsSDDS(Column.ReadbackName) $index] "
                        } else {
                            if {($groupname == "SR DCPS: 100Hz statistics for correctors") || ($groupname == "SR DCPS: 100Hz statistics for multipoles")} {
                                set rbList [lindex $timeSeriesSDDS(Column.ReadbackName) $index]
                                foreach rb $rbList {
                                    append ReadbackNameList "${rb}Mean ${rb}Min ${rb}Max "
                                }
                            } elseif {$groupname == "SR Feedback Corrector Errors"} {
                                set rbList [lindex $timeSeriesSDDS(Column.ReadbackName) $index]
                                foreach rb $rbList {
                                    append ReadbackNameList "${rb}Mean "
                                }
                            } else {
                                append ReadbackNameList "[lindex $timeSeriesSDDS(Column.ReadbackName) $index] "
                            }
                        }
                        set found 1

                        if {$groupname != "All Old PVs"} {
                            foreach gn [lindex $timeSeriesConfig(Column.GroupName) 0] rn [lindex $timeSeriesConfig(Column.rootname) 0] mp [lindex $timeSeriesConfig(Column.monitorProgram) 0] {
                                if {($mp == "sddslogger") && ($gn == $groupname)} {
                                    if {[file exists /home/helios/oagData/monitoring/MonitorDataReviewFiles/${rn}.sdds]} {
                                        sdds load /home/helios/oagData/monitoring/MonitorDataReviewFiles/${rn}.sdds data
                                        foreach pd [lindex $data(Column.PlotDescription) 0] command [lindex $data(Column.sddsplotOptions) 0] {
                                            set item [$PresetTreectrl item create]
                                            $PresetTreectrl item style set $item X CHECKSTYLE 
                                            $PresetTreectrl item style set $item Preset TEXTSTYLE Logger TEXTSTYLE Command TEXTSTYLE
                                            $PresetTreectrl item element configure $item X elemImg -image check-off
                                            $PresetTreectrl item element configure $item Preset elemTxt -text "$pd"
                                            $PresetTreectrl item element configure $item Logger elemTxt -text "$gn"
                                            $PresetTreectrl item element configure $item Command elemTxt -text "$command"
                                            $PresetTreectrl item lastchild root $item
                                        }
                                    }
                                    break
                                }
                            }
                        }
                    }
                }
                set parent [$T item nextsibling $parent]
            }
            if {$found} {
                APSSetVarAndUpdate status "Displaying PVs..."
                foreach rbn $ReadbackNameList cn $ControlNameList {
                    append nameList "{$rbn $cn} "
                }
                set nameList [lsort -unique $nameList]
                set nameList [lsort -dictionary -index [expr {[lindex $PVtreesort 0] - 2}] -[lindex $PVtreesort 1] $nameList]
                foreach name $nameList {
                    set rbn [lindex $name 0]
                    set cn [lindex $name 1]
                    set item [$PVtreectrl item create]
                    $PVtreectrl item style set $item X CHECKSTYLE Y CHECKSTYLE
                    $PVtreectrl item style set $item ReadbackName TEXTSTYLE ControlName TEXTSTYLE
                    if {[lsearch $previouslyselectedX $rbn] == -1} {
                        $PVtreectrl item element configure $item X elemImg -image check-off
                    } else {
                        $PVtreectrl item element configure $item X elemImg -image check-on
                        set PlotOptions(timeXaxis) 0
                    }
                    if {[lsearch $previouslyselectedY $rbn] == -1} {
                        $PVtreectrl item element configure $item Y elemImg -image check-off
                    } else {
                        $PVtreectrl item element configure $item Y elemImg -image check-on
                    }
                    $PVtreectrl item element configure $item ReadbackName elemTxt -text "$rbn"
                    $PVtreectrl item element configure $item ControlName elemTxt -text "$cn"
                    set visible no
                    foreach filter [split $includefilter ,] {
                        if {([string match -nocase $filter $cn]) || ([string match -nocase $filter $rbn])} {
                            set visible yes
                            break
                        }
                    }
                    foreach filter [split $excludefilter ,] {
                        if {([string match -nocase $filter $cn]) || ([string match -nocase $filter $rbn])} {
                            set visible no
                            break
                        }
                    }
                    $PVtreectrl item configure $item -visible $visible
                    $PVtreectrl item lastchild root $item
                }
                APSSetVarAndUpdate status "Done"
            }
        }
    }
    return
}

proc FilterPVs {args} {
    global PVtreectrl includefilter excludefilter

    if {[catch {$PVtreectrl item count} count]} {
        set count [$PVtreectrl numitems]
    }
    for {set i 1} {$i < $count} {incr i} {
        set visible no
        foreach filter [split $includefilter ,] {
            if {[string match -nocase $filter [$PVtreectrl item element cget $i 2 elemTxt -text]] || [string match -nocase $filter [$PVtreectrl item element cget $i 3 elemTxt -text]]} {
                set visible yes
                break
            }
        }
        foreach filter [split $excludefilter ,] {
            if {[string match -nocase $filter [$PVtreectrl item element cget $i 2 elemTxt -text]] || [string match -nocase $filter [$PVtreectrl item element cget $i 3 elemTxt -text]]} {
                set visible no
                break
            }
        }
        $PVtreectrl item configure $i -visible $visible
    }
}

proc CreatePVTree {frame} {
    global PVtreesort includefilter excludefilter

    set T $frame.t

    grid columnconfigure $frame 0 -weight 1
    grid rowconfigure $frame 0 -weight 1

    global screenheight
    if {$screenheight < 960} {
        treectrl $T \
          -background white \
          -selectmode multiple \
          -showroot no \
          -showbuttons no \
          -showlines 0 \
          -width 620 \
          -height 150 \
          -font TkDefaultFont \
          -xscrollincrement 1
    } else {
        treectrl $T \
          -background white \
          -selectmode multiple \
          -showroot no \
          -showbuttons no \
          -showlines 0 \
          -width 620 \
          -height 300 \
          -font TkDefaultFont \
          -xscrollincrement 1
    }

    ttk::scrollbar $frame.sh -orient horizontal -command "$T xview"
    $T notify bind $frame.sh <Scroll-x> { %W set %l %u }
    bind $frame.sh <ButtonPress-1> "focus $T"

    ttk::scrollbar $frame.sv -orient vertical -command "$T yview"
    $T notify bind $frame.sv <Scroll-y> { %W set %l %u }
    bind $frame.sv <ButtonPress-1> "focus $T"

    grid configure $T -row 0 -column 0 -sticky news
    grid configure $frame.sh -row 1 -column 0 -sticky we
    grid configure $frame.sv -row 0 -column 1 -sticky ns

    $T column create -text "X" -tag X -itembackground "white \#dddddd"
    $T column create -text "Y" -tag Y -itembackground "white \#dddddd"
    $T column create -text "PV ReadBack Names" -expand yes -tag ReadbackName -itembackground "white \#dddddd"
    $T column create -text "PV Control Names" -expand yes -tag ControlName -arrow down -itembackground "white \#dddddd"
    set PVtreesort "3 increasing"


    $T state define check

    InitPics check-on check-off
    $T element create elemImg image -image {
        check-on {check}
        check-off {}
    }
    $T element create elemTxt text

    set S [$T style create CHECKSTYLE]
    $T style elements $S {elemImg}
    $T style layout $S elemImg -padx {4 4} -expand ns

    set S [$T style create TEXTSTYLE]
    $T style elements $S {elemTxt}
    $T style layout $S elemTxt -padx {6 0} -expand ns

    bind PVTreeOptions <ButtonPress-1> {
        ::TreeCtrl::ButtonPress1 %W %x %y
        PVTreeClicked %W %x %y press ""
        break
    }
    bind PVTreeOptions <Button1-Motion> {
        TreeCtrl::Motion1 %W %x %y
        PVTreeClicked %W %x %y motion ""
        break
    }
    bind PVTreeOptions <Button-4> {
        %W yview scroll -4 unit
        break
    }
    bind PVTreeOptions <Button-5> {
        %W yview scroll 4 unit
        break
    }
    bindtags $T [list $T PVTreeOptions TreeCtrl [winfo toplevel $T] all]

    set includefilter "*"
    set excludefilter ""
    ttk::frame $frame.filter
    ttk::button $frame.filter.unselect -text "Unselect All" -command UnselectPVs
    ttk::button $frame.filter.select -text "Select All" -command SelectPVs
    ttk::label $frame.filter.label1 -text " Include:"
    ttk::entry $frame.filter.include -textvariable includefilter
    ttk::label $frame.filter.label2 -text " Exclude:"
    ttk::entry $frame.filter.exclude -textvariable excludefilter
    grid configure $frame.filter -row 2 -column 0 -columnspan 2 -sticky ew

    pack $frame.filter.unselect -side left
    pack $frame.filter.select -side left
    pack $frame.filter.label1 -side left
    pack $frame.filter.include -side left -expand true -fill x
    pack $frame.filter.label2 -side left
    pack $frame.filter.exclude -side left -expand true -fill x
    bind $frame.filter.include <Return> "FilterPVs"
    bind $frame.filter.exclude <Return> "FilterPVs"

    return $T

}

set yselect all

proc UnselectPVs {args} {
    global PVtreectrl PlotOptions
    set T $PVtreectrl
    
    if {[catch {$T item count} count]} {
        set count [$T numitems]
    }
    for {set i 1} {$i < $count} {incr i} {
        $T item element configure $i 0 elemImg -image check-off
        $T item element configure $i 1 elemImg -image check-off
    }
    set PlotOptions(timeXaxis) 1
}

proc SelectPVs {args} {
    global PVtreectrl PlotOptions
    set T $PVtreectrl
    
    if {[catch {$T item count} count]} {
        set count [$T numitems]
    }
    for {set i 1} {$i < $count} {incr i} {
        if {[$T item cget $i -visible]} {
            $T item element configure $i 1 elemImg -image check-on
        }
    }
}

proc PVTreeClicked {T x y mode id} {
    global PVtreectrl PVtreesort status

    focus $T
    if {$id == ""} {
        set id [$T identify $x $y]
    }
    #Click outside of any item
    if {$id eq ""} {

    #Click in header
    } elseif {[lindex $id 0] eq "header"} {
        if {$mode == "motion"} {return}
        if {[llength $id] == 3} {return}
        set column [lindex $id 1]
        if {$column == "tail"} {return}
        if {$column == 0} {
            if {[catch {$T item count} count]} {
                set count [$T numitems]
            }
            for {set i 1} {$i < $count} {incr i} {
                $T item element configure $i 0 elemImg -image check-off
            }
            global PlotOptions
            set PlotOptions(timeXaxis) 1
        } elseif {$column == 1} {
            global yselect
            if {$yselect == "all"} {
                if {[catch {$T item count} count]} {
                    set count [$T numitems]
                }
                for {set i 1} {$i < $count} {incr i} {
                    if {[$T item cget $i -visible]} {
                        $T item element configure $i 1 elemImg -image check-on
                    }
                }
                set yselect none
            } else {
                if {[catch {$T item count} count]} {
                    set count [$T numitems]
                }
                for {set i 1} {$i < $count} {incr i} {
                    if {[$T item cget $i -visible]} {
                        $T item element configure $i 1 elemImg -image check-off
                    }
                }
                set yselect all
            }
        } elseif {$column >= 2} {
            if {[catch {$T item count} count]} {
                set count [$T numitems]
            }
            if {$count > 10000} {
                APSSetVarAndUpdate status "Sorting is disabled when there are over 10000 PVs displayed"
                return
            }
            if {[lindex $PVtreesort 0] == $column} {
                if {[lindex $PVtreesort 1] == "increasing"} {
                    set PVtreesort "$column decreasing"
                } else {
                    set PVtreesort "$column increasing"
                }
            } else {
                set PVtreesort "$column increasing"
            }
            $T item sort root -dictionary -column $column -[lindex $PVtreesort 1]
            if {$column == 2} {
                if {[lindex $PVtreesort 1] == "increasing"} {
                    $T column configure 2 -arrow down
                } else {
                    $T column configure 2 -arrow up
                }
                APSSetVarAndUpdate status "Sorted PVs by ReadBack Names"
                $T column configure 3 -arrow none
            } else {
                if {[lindex $PVtreesort 1] == "increasing"} {
                    $T column configure 3 -arrow down
                } else {
                    $T column configure 3 -arrow up
                }
                APSSetVarAndUpdate status "Sorted PVs by Control Names"
                $T column configure 2 -arrow none
            }
        }

    #Click in item
    } else {
        set item [lindex $id 1]
        set column [lindex $id 3]
        if {$column == 0} {
            if {$mode == "motion"} {return}
            global PlotOptions
            if {[$T item element cget $item 0 elemImg -image] == "check-on"} {
                set setting off
                set PlotOptions(timeXaxis) 1
            } else {
                set setting on
                if {[catch {$T item count} count]} {
                    set count [$T numitems]
                }
                for {set i 1} {$i < $count} {incr i} {
                    if {[$T item element cget $i 0 elemImg -image] == "check-on"} {
                        $T item element configure $i 0 elemImg -image check-off
                        break
                    }
                }
                set PlotOptions(timeXaxis) 0
            }
            $T item element configure $item 0 elemImg -image check-$setting
        } else {
            global pvtreeYsetting
            if {$mode != "motion"} {
                if {[$T item element cget $item 1 elemImg -image] == "check-on"} {
                    set pvtreeYsetting off
                } else {
                    set pvtreeYsetting on
                }
            }
            $T item element configure $item 1 elemImg -image check-$pvtreeYsetting
        }
    }
    return
}

proc CreatePresetPlotTree {frame} {
    set T $frame.t

    grid columnconfigure $frame 0 -weight 1
    grid rowconfigure $frame 0 -weight 1

    global screenheight
    if {$screenheight < 960} {
        treectrl $T \
          -background white \
          -selectmode extended \
          -showroot no \
          -showbuttons no \
          -showlines 0 \
          -width 620 \
          -height 150 \
          -font TkDefaultFont \
          -xscrollincrement 1
    } else {
        treectrl $T \
          -background white \
          -selectmode extended \
          -showroot no \
          -showbuttons no \
          -showlines 0 \
          -width 620 \
          -height 300 \
          -font TkDefaultFont \
          -xscrollincrement 1
    }
    ttk::scrollbar $frame.sh -orient horizontal -command "$T xview"
    $T notify bind $frame.sh <Scroll-x> { %W set %l %u }
    bind $frame.sh <ButtonPress-1> "focus $T"

    ttk::scrollbar $frame.sv -orient vertical -command "$T yview"
    $T notify bind $frame.sv <Scroll-y> { %W set %l %u }
    bind $frame.sv <ButtonPress-1> "focus $T"

    grid configure $T -row 0 -column 0 -sticky news
    grid configure $frame.sh -row 1 -column 0 -sticky we
    grid configure $frame.sv -row 0 -column 1 -sticky ns

    $T column create -text "Selected" -tag X -itembackground "white \#ddddcc"
    $T column create -text "Preset Plots" -tag Preset -itembackground "white \#ddddcc"
    $T column create -text "Data Logger" -tag Logger -itembackground "white \#ddddcc"
    $T column create -text "Command" -tag Command -visible false

    $T state define check

    InitPics check-on check-off
    $T element create elemImg image -image {
        check-on {check}
        check-off {}
    }
    $T element create elemTxt text

    set S [$T style create CHECKSTYLE]
    $T style elements $S {elemImg}
    $T style layout $S elemImg -padx {4 4} -expand nsew

    set S [$T style create TEXTSTYLE]
    $T style elements $S {elemTxt}
    $T style layout $S elemTxt -padx {6 0} -expand ns

    bind PresetTreeOptions <ButtonPress-1> {
        ::TreeCtrl::ButtonPress1 %W %x %y
        PresetTreeClicked %W %x %y press
        break
    }
    bind PresetTreeOptions <Button1-Motion> {
        TreeCtrl::Motion1 %W %x %y
        PresetTreeClicked %W %x %y motion
        break
    }
    bind PresetTreeOptions <Button-4> {
        %W yview scroll -4 unit
        break
    }
    bind PresetTreeOptions <Button-5> {
        %W yview scroll 4 unit
        break
    }
    bindtags $T [list $T PresetTreeOptions TreeCtrl [winfo toplevel $T] all]
    return $T

}

proc PresetTreeClicked {T x y mode} {
    global PresetTreectrl status

    focus $T
    set id [$T identify $x $y]
    #Click outside of any item
    if {$id eq ""} {

    #Click in header
    } elseif {[lindex $id 0] eq "header"} {

    #Click in item
    } else {
        set item [lindex $id 1]
        set column [lindex $id 3]
        global presettreeselectionsetting
        if {$mode != "motion"} {
            if {[$T item element cget $item 0 elemImg -image] == "check-on"} {
                set presettreeselectionsetting off
            } else {
                set presettreeselectionsetting on
            }
        }
        $T item element configure $item 0 elemImg -image check-$presettreeselectionsetting
    }
    return
}

proc CreateCustomPlotTree {frame} {
    set T $frame.t

    grid columnconfigure $frame 1 -weight 1
    grid rowconfigure $frame 0 -weight 1

    global screenheight
    if {$screenheight < 960} {
        treectrl $T \
          -background white \
          -selectmode extended \
          -showroot no \
          -showbuttons no \
          -showlines 0 \
          -width 620 \
          -height 150 \
          -font TkDefaultFont \
          -xscrollincrement 1
    } else {
        treectrl $T \
          -background white \
          -selectmode extended \
          -showroot no \
          -showbuttons no \
          -showlines 0 \
          -width 620 \
          -height 300 \
          -font TkDefaultFont \
          -xscrollincrement 1
    }
    ttk::scrollbar $frame.sh -orient horizontal -command "$T xview"
    $T notify bind $frame.sh <Scroll-x> { %W set %l %u }
    bind $frame.sh <ButtonPress-1> "focus $T"

    ttk::scrollbar $frame.sv -orient vertical -command "$T yview"
    $T notify bind $frame.sv <Scroll-y> { %W set %l %u }
    bind $frame.sv <ButtonPress-1> "focus $T"

    grid configure $T -row 0 -column 0 -columnspan 2 -sticky news
    grid configure $frame.sh -row 1 -column 0 -columnspan 2 -sticky we
    grid configure $frame.sv -row 0 -column 2 -sticky ns

    $T column create -text "Selected" -tag X -itembackground "white \#ddddcc"
    $T column create -text "Custom Plots" -tag Custom -itembackground "white \#ddddcc"
    $T column create -text "Script" -tag Script -visible false
#    $T column create -text "Data Logger" -tag Logger -itembackground "white \#ddddcc"
#    $T column create -text "Command" -tag Command -visible false

    $T state define check

    InitPics check-on check-off
    $T element create elemImg image -image {
        check-on {check}
        check-off {}
    }
    $T element create elemTxt text

    set S [$T style create CHECKSTYLE]
    $T style elements $S {elemImg}
    $T style layout $S elemImg -padx {4 4} -expand nsew

    set S [$T style create TEXTSTYLE]
    $T style elements $S {elemTxt}
    $T style layout $S elemTxt -padx {6 0} -expand ns

    bind CustomTreeOptions <ButtonPress-1> {
        ::TreeCtrl::ButtonPress1 %W %x %y
        CustomTreeClicked %W %x %y press
        break
    }
    bind CustomTreeOptions <Button1-Motion> {
        TreeCtrl::Motion1 %W %x %y
        CustomTreeClicked %W %x %y motion
        break
    }
    bind CustomTreeOptions <Button-4> {
        %W yview scroll -4 unit
        break
    }
    bind CustomTreeOptions <Button-5> {
        %W yview scroll 4 unit
        break
    }
    bindtags $T [list $T CustomTreeOptions TreeCtrl [winfo toplevel $T] all]

    global env
    if {[file exists $env(HOME)/.dataLoggerViewer/customPlotNames.sdds]} {
        sdds load $env(HOME)/.dataLoggerViewer/customPlotNames.sdds data
        set names [lindex $data(Column.PlotName) 0]
        set files [lindex $data(Column.File) 0]
        foreach n $names f $files {
            set item [$T item create]
            $T item style set $item X CHECKSTYLE 
            $T item style set $item Custom TEXTSTYLE Script TEXTSTYLE
            $T item element configure $item X elemImg -image check-off
            $T item element configure $item Custom elemTxt -text "$n"
            $T item element configure $item Script elemTxt -text "$f"
            $T item lastchild root $item
        }


    }

    ttk::button $frame.button1 -text "Apply Selected" -command "ApplyCustomPlot"
    grid $frame.button1 -row 2 -column 0 -sticky nw
    ttk::button $frame.button2 -text "Delete Selected" -command "DeleteCustomPlot"
    grid $frame.button2 -row 2 -column 1 -sticky nw
    return $T
}

proc CustomTreeClicked {T x y mode} {
    global CustomTreectrl

    if {$mode != "press"} {return}
    focus $T
    set id [$T identify $x $y]
    #Click outside of any item
    if {$id eq ""} {

    #Click in header
    } elseif {[lindex $id 0] eq "header"} {

    #Click in item
    } else {
        set item [lindex $id 1]
        for {set i 1} {$i < [$T item count]} {incr i} {
            if {$i == $item} {continue}
            $T item element configure $i 0 elemImg -image check-off
        }
        $T selection clear
        set column [lindex $id 3]
        global customtreeselectionsetting
        if {$mode != "motion"} {
            if {[$T item element cget $item 0 elemImg -image] == "check-on"} {
                set customtreeselectionsetting off
            } else {
                set customtreeselectionsetting on
                $T selection add $item
            }
        }
        $T item element configure $item 0 elemImg -image check-$customtreeselectionsetting
    }
    return
}

proc DeleteCustomPlot {args} {
    global CustomTreectrl env
    set item [$CustomTreectrl selection get]
    if {[llength $item] == 1} {
        set filename [$CustomTreectrl item element cget $item Script elemTxt -text]
        file delete $filename
        catch {exec sddsprocess $env(HOME)/.dataLoggerViewer/customPlotNames.sdds -match=column,File=${filename},!}
    }
    sdds load $env(HOME)/.dataLoggerViewer/customPlotNames.sdds data
    set names [lindex $data(Column.PlotName) 0]
    set files [lindex $data(Column.File) 0]
    $CustomTreectrl item delete all
    foreach n $names f $files {
        set item [$CustomTreectrl item create]
        $CustomTreectrl item style set $item X CHECKSTYLE 
        $CustomTreectrl item style set $item Custom TEXTSTYLE Script TEXTSTYLE
        $CustomTreectrl item element configure $item X elemImg -image check-off
        $CustomTreectrl item element configure $item Custom elemTxt -text "$n"
        $CustomTreectrl item element configure $item Script elemTxt -text "$f"
        $CustomTreectrl item lastchild root $item
    }

}

proc ApplyCustomPlot {args} {
    global CustomTreectrl PlotOptions DataLoggerTreectrl PVtreectrl
    set item [$CustomTreectrl selection get]
    if {[llength $item] == 1} {
        source [$CustomTreectrl item element cget $item Script elemTxt -text]
        for {set i 1} {$i < [$DataLoggerTreectrl item count]} {incr i} {
            if {[$DataLoggerTreectrl item element cget $i 0 elemImg -image] == "check-on"} {
                DataLoggerClicked $DataLoggerTreectrl 0 0 "item $i column 0"
                $DataLoggerTreectrl selection clear $i
            }
        }
        for {set i 1} {$i < [$DataLoggerTreectrl item count]} {incr i} {
            if {[lsearch -exact $dataLoggers [$DataLoggerTreectrl item element cget $i 0 elemTxt -text]] != -1} {
                if {[$DataLoggerTreectrl depth $i] != 1} {
                    DataLoggerClicked $DataLoggerTreectrl 0 0 "item $i column 0"
                }
            }
        }
        for {set i 1} {$i < [$PVtreectrl item count]} {incr i} {
            if {[lsearch -exact $xReadbackName [$PVtreectrl item element cget $i 2 elemTxt -text]] != -1} {
                PVTreeClicked $PVtreectrl 0 0 press "item $i column 0"
            }
            if {[lsearch -exact $yReadbackNames [$PVtreectrl item element cget $i 2 elemTxt -text]] != -1} {
                PVTreeClicked $PVtreectrl 0 0 press "item $i column 1"
            }
        }
    }
}

proc MakeDateTimeFrame {frame} {
    global StartTextDay StartDay StartTextMonth StartYear 
    global StartHour StartMinute StartSecond StartTime
    global EndTextDay EndDay EndTextMonth EndYear 
    global EndHour EndMinute EndSecond EndTime

    set s [clock seconds]

    ttk::frame $frame -padding 2
    pack $frame

    ttk::frame $frame.from
    pack $frame.from 
    set f $frame.from

    ttk::label $f.label -text "From:"
    ttk::spinbox $f.textday -values "Mon Tue Wed Thu Fri Sat Sun" \
      -width 3 -wrap true -textvariable StartTextDay \
      -style Tall.TSpinbox
    bindtags $f.textday "TSpinbox . all .userFrame.date.from.textday "
    bind $f.textday <<Increment>> "TimeAdjusted Start %W up"
    bind $f.textday <<Decrement>> "TimeAdjusted Start %W down"
    ttk::spinbox $f.day -from 1 -to 31 -width 2 -wrap true \
      -textvariable StartDay \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.day "TSpinbox . all .userFrame.date.from.day "
    bind $f.day <<Increment>> "TimeAdjusted Start %W up"
    bind $f.day <<Decrement>> "TimeAdjusted Start %W down"
    ttk::spinbox $f.month \
      -values "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" \
      -width 3 -wrap true -textvariable StartTextMonth \
      -style Tall.TSpinbox
    bindtags $f.month "TSpinbox . all .userFrame.date.from.month "
    bind $f.month <<Increment>> "TimeAdjusted Start %W up"
    bind $f.month <<Decrement>> "TimeAdjusted Start %W down"
    ttk::spinbox $f.year -from 1900 -to 2100 -width 4 -wrap true \
      -textvariable StartYear \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.year "TSpinbox . all .userFrame.date.from.year "
    bind $f.year <<Increment>> "TimeAdjusted Start %W up"
    bind $f.year <<Decrement>> "TimeAdjusted Start %W down"
    ttk::label $f.space -text " "
    ttk::spinbox $f.hour -from 0 -to 23 -width 2 -wrap true \
      -format %02.0f -textvariable StartHour \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.hour "TSpinbox . all .userFrame.date.from.hour "
    bind $f.hour <<Increment>> "TimeAdjusted Start %W up"
    bind $f.hour <<Decrement>> "TimeAdjusted Start %W down"
    ttk::label $f.colon1 -text ":"
    ttk::spinbox $f.minute -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable StartMinute \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.minute "TSpinbox . all .userFrame.date.from.minute "
    bind $f.minute <<Increment>> "TimeAdjusted Start %W up"
    bind $f.minute <<Decrement>> "TimeAdjusted Start %W down"
    ttk::label $f.colon2 -text ":"
    ttk::spinbox $f.second -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable StartSecond \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.second "TSpinbox . all .userFrame.date.from.second "
    bind $f.second <<Increment>> "TimeAdjusted Start %W up"
    bind $f.second <<Decrement>> "TimeAdjusted Start %W down"

    bind $f.textday <Return> "TimeAdjustedManually"
    bind $f.day <Return> "TimeAdjustedManually"
    bind $f.month <Return> "TimeAdjustedManually"
    bind $f.year <Return> "TimeAdjustedManually"
    bind $f.hour <Return> "TimeAdjustedManually"
    bind $f.minute <Return> "TimeAdjustedManually"
    bind $f.second <Return> "TimeAdjustedManually"

    set StartTextDay [clock format $s -format %a]
    set StartDay [clock format $s -format %d]
    set StartTextMonth [clock format $s -format %b]
    set StartYear [clock format $s -format %Y]
    set StartHour 00
    set StartMinute 00
    set StartSecond 00

    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]

   ttk::button $f.reset -text "Reset" -command "set StartTextDay $StartTextDay ; set StartDay $StartDay ; set StartTextMonth $StartTextMonth ; set StartYear $StartYear ; set StartHour $StartHour ; set StartMinute $StartMinute ; set StartSecond $StartSecond ; set StartTime $StartTime" -style Tight.TButton

    pack $f.label $f.textday $f.day $f.month \
      $f.year $f.space $f.hour $f.colon1 \
      $f.minute $f.colon2 $f.second $f.reset -side left

    ttk::button $f.15min -text "last 15min" -command "TimePreset -minutes 15" -style Tight.TButton
    pack $f.15min -side left
    ttk::button $f.30min -text "last 30min" -command "TimePreset -minutes 30" -style Tight.TButton
    pack $f.30min -side left


    ttk::frame $frame.to
    pack $frame.to -anchor e
    set f $frame.to

    ttk::label $f.label -text "To:"
    ttk::spinbox $f.textday -values "Mon Tue Wed Thu Fri Sat Sun" \
      -width 3 -wrap true -textvariable EndTextDay \
      -style Tall.TSpinbox
    bindtags $f.textday "TSpinbox . all .userFrame.date.to.textday "
    bind $f.textday <<Increment>> "TimeAdjusted End %W up"
    bind $f.textday <<Decrement>> "TimeAdjusted End %W down"
    ttk::spinbox $f.day -from 1 -to 31 -width 2 -wrap true \
      -textvariable EndDay \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.day "TSpinbox . all .userFrame.date.to.day "
    bind $f.day <<Increment>> "TimeAdjusted End %W up"
    bind $f.day <<Decrement>> "TimeAdjusted End %W down"
    ttk::spinbox $f.month \
      -values "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" \
      -width 3 -wrap true -textvariable EndTextMonth \
      -style Tall.TSpinbox
    bindtags $f.month "TSpinbox . all .userFrame.date.to.month "
    bind $f.month <<Increment>> "TimeAdjusted End %W up"
    bind $f.month <<Decrement>> "TimeAdjusted End %W down"
    ttk::spinbox $f.year -from 1900 -to 2100 -width 4 -wrap true \
      -textvariable EndYear \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.year "TSpinbox . all .userFrame.date.to.year "
    bind $f.year <<Increment>> "TimeAdjusted End %W up"
    bind $f.year <<Decrement>> "TimeAdjusted End %W down"
    ttk::label $f.space -text " "
    ttk::spinbox $f.hour -from 0 -to 23 -width 2 -wrap true \
      -format %02.0f -textvariable EndHour \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.hour "TSpinbox . all .userFrame.date.to.hour "
    bind $f.hour <<Increment>> "TimeAdjusted End %W up"
    bind $f.hour <<Decrement>> "TimeAdjusted End %W down"
    ttk::label $f.colon1 -text ":"
    ttk::spinbox $f.minute -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable EndMinute \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.minute "TSpinbox . all .userFrame.date.to.minute "
    bind $f.minute <<Increment>> "TimeAdjusted End %W up"
    bind $f.minute <<Decrement>> "TimeAdjusted End %W down"
    ttk::label $f.colon2 -text ":"
    ttk::spinbox $f.second -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable EndSecond \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.second "TSpinbox . all .userFrame.date.to.second "
    bind $f.second <<Increment>> "TimeAdjusted End %W up"
    bind $f.second <<Decrement>> "TimeAdjusted End %W down"

    bind $f.textday <Return> "TimeAdjustedManually"
    bind $f.day <Return> "TimeAdjustedManually"
    bind $f.month <Return> "TimeAdjustedManually"
    bind $f.year <Return> "TimeAdjustedManually"
    bind $f.hour <Return> "TimeAdjustedManually"
    bind $f.minute <Return> "TimeAdjustedManually"
    bind $f.second <Return> "TimeAdjustedManually"

    set EndTextDay [clock format $s -format %a]
    set EndDay [clock format $s -format %d]
    set EndTextMonth [clock format $s -format %b]
    set EndYear [clock format $s -format %Y]
    set EndHour 23
    set EndMinute 59
    set EndSecond 59

    set EndTime [clock scan "$EndTextDay $EndTextMonth $EndDay ${EndHour}:${EndMinute}:${EndSecond} $EndYear"]

    ttk::button $f.reset -text "Reset" -command "set EndTextDay $EndTextDay ; set EndDay $EndDay ; set EndTextMonth $EndTextMonth ; set EndYear $EndYear ; set EndHour $EndHour ; set EndMinute $EndMinute ; set EndSecond $EndSecond ; set EndTime $EndTime" -style Tight.TButton

    pack $f.label $f.textday $f.day $f.month \
      $f.year $f.space $f.hour $f.colon1 \
      $f.minute $f.colon2 $f.second $f.reset -side left

    ttk::button $f.45min -text "last 45min" -command "TimePreset -minutes 45" -style Tight.TButton
    pack $f.45min -side left
    ttk::button $f.60min -text "last 60min" -command "TimePreset -minutes 60" -style Tight.TButton
    pack $f.60min -side left

}

proc TimePreset {args} {
    APSStrictParseArguments {minutes}
    foreach var "Start End" {
        global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
        global ${var}Hour ${var}Minute ${var}Second ${var}Time
    }
    set s [clock seconds]
    
    set EndTextDay [clock format $s -format %a]
    set EndDay [clock format $s -format %d]
    set EndTextMonth [clock format $s -format %b]
    set EndYear [clock format $s -format %Y]
    set EndHour 23
    set EndMinute 59
    set EndSecond 59
    set EndTime [clock scan "$EndTextDay $EndTextMonth $EndDay ${EndHour}:${EndMinute}:${EndSecond} $EndYear"]

    set s [expr $s - ($minutes * 60)]
    set StartTextDay [clock format $s -format %a]
    set StartDay [clock format $s -format %d]
    set StartTextMonth [clock format $s -format %b]
    set StartYear [clock format $s -format %Y]
    set StartHour [clock format $s -format %H]
    set StartMinute [clock format $s -format %M]
    set StartSecond [clock format $s -format %S]
    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]


}

proc TimeAdjustedManually {args} {
    foreach var "Start End" {
        global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
        global ${var}Hour ${var}Minute ${var}Second ${var}Time
        
        set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]
        set ${var}Minute [clock format [set ${var}Time] -format %M]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    }
}

proc TimeAdjusted {var widget direction} {
    global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
    global ${var}Hour ${var}Minute ${var}Second ${var}Time

    if {[lindex [split $widget .] end] == "second"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (1)"]
        set ${var}Second [clock format [set ${var}Time] -format %S]
        set ${var}Minute [clock format [set ${var}Time] -format %M]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "minute"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (60)"]
        set ${var}Minute [clock format [set ${var}Time] -format %M]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "hour"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (60 * 60)"]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "textday"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (24 * 60 * 60)"]
        set initTextDay [set ${var}TextDay]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        if {$initTextDay != [set ${var}TextDay]} {
            #This is needed for the transition to daylight savings time.
            set ${var}Time [expr "[set ${var}Time] $direction (1 * 60 * 60)"]
            set ${var}TextDay [clock format [set ${var}Time] -format %a]
        }
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "day"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (24 * 60 * 60)"]
        set initTextDay [set ${var}TextDay]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        if {$initTextDay == [set ${var}TextDay]} {
            #This is needed for the transition to daylight savings time.
            set ${var}Time [expr "[set ${var}Time] $direction (1 * 60 * 60)"]
            set ${var}TextDay [clock format [set ${var}Time] -format %a]
        }
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "month"} {
        set month [clock format [set ${var}Time] -format %b]
        set year [clock format [set ${var}Time] -format %Y]
        set s1 [clock scan "$month 01 00:00:00 $year"]
        if {$direction == "up"} {
            if {$month == "Dec"} {
                incr year
            }
        } else {
            if {$month == "Jan"} {
                incr year -1
            }
        }
        set s2 [clock scan "[set ${var}TextMonth] 01 00:00:00 $year"]
        set s [expr {$s2 - $s1 + (60 * 60)}]
        set ${var}Time [expr "[set ${var}Time] + $s"]
        while {[set ${var}TextMonth] != [clock format [set ${var}Time] -format %b]} {
            if {$month == [clock format [set ${var}Time] -format %b]} {
                if {$direction == "up"} {
                    set ${var}Time [expr "[set ${var}Time] + (12 * 60 * 60)"]
                } else {
                    set ${var}Time [expr "[set ${var}Time] - (12 * 60 * 60)"]
                }
            } else {
                if {$direction == "up"} {
                    set ${var}Time [expr "[set ${var}Time] - (12 * 60 * 60)"]
                } else {
                    set ${var}Time [expr "[set ${var}Time] + (12 * 60 * 60)"]
                }
            }
        }
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "year"} {
        if {([set ${var}Day] == "29") && ([set ${var}TextMonth] == "Feb")} {
            set ${var}Day 28
        }
        set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
    }
    set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]

}

proc CalcTime {} {
    foreach var "Start End" {
        global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
        global ${var}Hour ${var}Minute ${var}Second ${var}Time
        global dateEntryStyle ${var}Month
        if {$dateEntryStyle == "old"} {
            if [catch {APSConvertTimeToHours [set ${var}Hour]} hour] {
                APSSetVarAndUpdate status "Invalid ${var}ing hour: [set ${var}Hour]"
                return
            }
            set ${var}Time \
              [expr int([exec timeconvert \
                           -breakDown=year=[set ${var}Year],day=[set ${var}Day],month=[set ${var}Month],hour=$hour])]
        } else {
            set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]
        }
    }
}

proc MakeDateTimeFrameOldStyle {widget args} {
    set parent .
    set rootname ""
    APSStrictParseArguments {parent rootname}
    set label "Date/Time Range of Interest"
    APSFrame $widget -parent $parent -label $label
    set w $parent$widget.frame

    APSDateTimeAdjEntry .startDate -parent $w \
        -yearVariable ${rootname}StartYear \
        -monthVariable ${rootname}StartMonth \
        -dayVariable ${rootname}StartDay \
        -hourVariable ${rootname}StartHour \
        -label "Starting date/time (year, month, day, hour): " -defaultHour 0 \
        -command ResetMonDataFileList
    APSDateTimeAdjEntry .endDate -parent $w \
        -yearVariable ${rootname}EndYear \
        -monthVariable ${rootname}EndMonth \
        -dayVariable ${rootname}EndDay \
        -hourVariable ${rootname}EndHour \
        -label "Ending date/time (year, month, day, hour):   " -defaultHour 24 \
        -command ResetMonDataFileList

    SetDateTimeToToday -rootname ${rootname}Start -hour 0
    SetDateTimeToToday -rootname ${rootname}End  -hour 24
}

proc SetDateTimeToToday {args} {
    set rootname ""
    set hour 0
    ResetMonDataFileList
    APSStrictParseArguments {rootname hour}
    global todayMonth todayYear todayDay 
    global ${rootname}Month ${rootname}Year ${rootname}Day ${rootname}Hour
    
    APSDateBreakDown -dayVariable todayDay -yearVariable todayYear \
      -monthVariable todayMonth -twoDigitYear 0 -leadingZeros 0
    set ${rootname}Hour $hour
    set ${rootname}Month $todayMonth
    set ${rootname}Day $todayDay
    set ${rootname}Year $todayYear
}

proc ResetMonDataFileList {} {
    global MonDataFileList MonDataFileListIsOld
    global MonDataGroupIndex

    set MonDataFileListIsOld 1
}

proc CreatePlotOptionsPane {canvas} {
    global PlotOptions

    set frame $canvas.frame
    ttk::frame $frame
    $canvas create window 0 0 -anchor nw -window $frame

    bindtags $canvas.frame ".userFrame.pane.pane.plotoptions.canvas [bindtags $canvas.frame]"
    
    #grid columnconfigure $frame 2 -weight 1
    #grid rowconfigure $frame 20 -weight 1

    set row 0

    ttk::label $frame.label1 -text "Layout:"
    tk_optionMenu $frame.options1 PlotOptions(layout) 1x1 1x2 1x3 1x4 1x5 2x1 2x2 2x3 2x4 2x5 3x1 3x2 3x3 3x4 3x5 4x1 4x2 4x3 4x4 4x5 5x1 5x2 5x3 5x4 5x5
    grid configure $frame.label1 -row $row -column 0 -sticky e
    grid configure $frame.options1 -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.label1 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label1]"
    bindtags $frame.options1 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.options1]"
    incr row
    
    ttk::label $frame.label2 -text "Label Size:"
    tk_optionMenu $frame.options2 PlotOptions(labelsize) normal +15% +30% +45% +60%
    grid configure $frame.label2 -row $row -column 0 -sticky e
    grid configure $frame.options2 -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.label2 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label2]"
    bindtags $frame.options2 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.options2]"
    incr row
    
    ttk::label $frame.label3 -text "Graphic:"
    tk_optionMenu $frame.options3 PlotOptions(graphic) "multicolor line" "line" "multicolor symbol" "symbol" "multicolor symbol w/line" "symbol w/line" "multicolor dot" "dot" "multicolor bar" "bar"
    grid configure $frame.label3 -row $row -column 0 -sticky e
    grid configure $frame.options3 -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.label3 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label3]"
    bindtags $frame.options3 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.options3]"
    incr row

    ttk::label $frame.label4 -text " Device:"
    tk_optionMenu $frame.options4 PlotOptions(device) "X-windows" "B&W Postscript" "Color Postscript" "PNG file (white)" "PNG file (black)"
    grid configure $frame.label4 -row $row -column 0 -sticky e
    grid configure $frame.options4 -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.label4 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label4]"
    bindtags $frame.options4 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.options4]"
    incr row

    set PlotOptions(outputfile) ""
    ttk::label $frame.label5 -text "Output File:"
    ttk::entry $frame.entry5 -textvariable PlotOptions(outputfile)
    ttk::button $frame.button5 -style Toolbutton -text "F" -command {
        if {($PlotOptions(device) == "PNG file (white)") || ($PlotOptions(device) == "PNG file (black)")} {
            set PlotOptions(outputfile) [tk_getSaveFile -confirmoverwrite 0 -parent . -filetypes {{{PNG Files} {.png}} {{All Files} *}}]
        } elseif {($PlotOptions(device) == "B&W Postscript") || ($PlotOptions(device) == "Color Postscript")} {
            set PlotOptions(outputfile) [tk_getSaveFile -confirmoverwrite 0 -parent . -filetypes {{{PS Files} {.ps}} {{All Files} *}}]
        } else {
            set PlotOptions(outputfile) [tk_getSaveFile -confirmoverwrite 0 -parent . -filetypes {{{All Files} *}}]
        }
    }
    grid configure $frame.label5 -row $row -column 0 -sticky e
    grid configure $frame.entry5 -row $row -column 1 -sticky ew -columnspan 2
    grid configure $frame.button5 -row $row -column 3 -sticky w
    bindtags $frame.label5 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label5]"
    bindtags $frame.entry5 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry5]"
    bindtags $frame.button5 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.button5]"
    incr row

    set PlotOptions(xlabel) ""
    ttk::label $frame.label6 -text "X Label:"
    ttk::entry $frame.entry6 -textvariable PlotOptions(xlabel)
    grid configure $frame.label6 -row $row -column 0 -sticky e
    grid configure $frame.entry6 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label6 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label6]"
    bindtags $frame.entry6 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry6]"
    incr row

    set PlotOptions(ylabel) ""
    ttk::label $frame.label7 -text "Y Label:"
    ttk::entry $frame.entry7 -textvariable PlotOptions(ylabel)
    grid configure $frame.label7 -row $row -column 0 -sticky e
    grid configure $frame.entry7 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label7 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label7]"
    bindtags $frame.entry7 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry7]"
    incr row

    set PlotOptions(title) ""
    ttk::label $frame.label8 -text "Title:"
    ttk::entry $frame.entry8 -textvariable PlotOptions(title)
    grid configure $frame.label8 -row $row -column 0 -sticky e
    grid configure $frame.entry8 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label8 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label8]"
    bindtags $frame.entry8 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry8]"
    incr row

    set PlotOptions(topline) ""
    ttk::label $frame.label9 -text "Topline:"
    ttk::entry $frame.entry9 -textvariable PlotOptions(topline)
    grid configure $frame.label9 -row $row -column 0 -sticky e
    grid configure $frame.entry9 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label9 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label9]"
    bindtags $frame.entry9 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry9]"
    incr row

    set PlotOptions(extra) ""
    ttk::label $frame.label10 -text "Extra Options:"
    ttk::entry $frame.entry10 -textvariable PlotOptions(extra)
    grid configure $frame.label10 -row $row -column 0 -sticky e
    grid configure $frame.entry10 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label10 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label10]"
    bindtags $frame.entry10 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry10]"
    incr row

    set PlotOptions(logx) 0
    set PlotOptions(logy) 0
    ttk::label $frame.label11 -text "Logarithmic:"
    ttk::checkbutton $frame.logx -text "X-axis" -variable PlotOptions(logx)
    ttk::checkbutton $frame.logy -text "Y-axis" -variable PlotOptions(logy)
    grid configure $frame.label11 -row $row -column 0 -sticky e
    grid configure $frame.logx -row $row -column 1 -sticky w
    grid configure $frame.logy -row $row -column 2 -sticky w
    bindtags $frame.label11 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label11]"
    bindtags $frame.logx ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.logx]"
    bindtags $frame.logy ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.logy]"
    incr row

    set PlotOptions(timeXaxis) 1
    ttk::checkbutton $frame.timeXaxis -text "Time on X-axis" -variable PlotOptions(timeXaxis)
    grid configure $frame.timeXaxis -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.timeXaxis ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.timeXaxis]"
    incr row

    set PlotOptions(legends) 1
    ttk::checkbutton $frame.legends -text "Legends" -variable PlotOptions(legends)
    grid configure $frame.legends -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.legends ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.legends]"
    incr row

    set PlotOptions(separate) 0
    ttk::checkbutton $frame.separate -text "Separate" -variable PlotOptions(separate)
    grid configure $frame.separate -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.separate ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.separate]"
    incr row

    set PlotOptions(samescale) 0
    ttk::checkbutton $frame.samescale -text "Same Scale" -variable PlotOptions(samescale)
    grid configure $frame.samescale -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.samescale ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.samescale]"
    incr row

    set PlotOptions(commonoffset) 0
    ttk::checkbutton $frame.commonoffset -text "Common Offset" -variable PlotOptions(commonoffset)
    grid configure $frame.commonoffset -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.commonoffset ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.commonoffset]"
    incr row

    set PlotOptions(repeat) 0
    ttk::checkbutton $frame.repeat -text "Repeat" -variable PlotOptions(repeat)
    grid configure $frame.repeat -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.repeat ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(xmin) 0
    set PlotOptions(xmax) 0
    ttk::label $frame.label12 -text "X min, max:"
    ttk::entry $frame.entry12a -textvariable PlotOptions(xmin) -width 8
    ttk::entry $frame.entry12b -textvariable PlotOptions(xmax) -width 8
    grid configure $frame.label12 -row $row -column 0 -sticky e
    grid configure $frame.entry12a -row $row -column 1 -sticky w
    grid configure $frame.entry12b -row $row -column 2 -sticky w
    bindtags $frame.label12 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label12]"
    bindtags $frame.entry12a ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry12a]"
    bindtags $frame.entry12b ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry12b]"
    incr row

    set PlotOptions(ymin) 0
    set PlotOptions(ymax) 0
    ttk::label $frame.label13 -text "Y min, max:"
    ttk::entry $frame.entry13a -textvariable PlotOptions(ymin) -width 8
    ttk::entry $frame.entry13b -textvariable PlotOptions(ymax) -width 8
    grid configure $frame.label13 -row $row -column 0 -sticky e
    grid configure $frame.entry13a -row $row -column 1 -sticky w
    grid configure $frame.entry13b -row $row -column 2 -sticky w
    bindtags $frame.label13 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label13]"
    bindtags $frame.entry13a ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry13a]"
    bindtags $frame.entry13b ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry13b]"
    incr row

    set PlotOptions(xLogBase) 1e-14
    set PlotOptions(yLogBase) 1e-14
    ttk::label $frame.label12x -text "X, Y log base:"
    ttk::entry $frame.entry12xa -textvariable PlotOptions(xLogBase) -width 8
    ttk::entry $frame.entry12xb -textvariable PlotOptions(yLogBase) -width 8
    grid configure $frame.label12x -row $row -column 0 -sticky e
    grid configure $frame.entry12xa -row $row -column 1 -sticky w
    grid configure $frame.entry12xb -row $row -column 2 -sticky w
    bindtags $frame.label12x ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label12x]"
    bindtags $frame.entry12xa ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry12xa]"
    bindtags $frame.entry12xb ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry12xb]"
    incr row

    set PlotOptions(histogram) 0
    ttk::checkbutton $frame.histogram -text "Histogram" -variable PlotOptions(histogram) \
      -command "ToggleHistogramMode $frame"
    grid configure $frame.histogram -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.histogram ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.histogram]"
    incr row

    set PlotOptions(histogramstats) 0
    ttk::checkbutton $frame.histogramstats -text "Histogram Stats" -variable PlotOptions(histogramstats) -state disabled
    grid configure $frame.histogramstats -row $row -column 1 -sticky w -columnspan 2
    bindtags $frame.histogramstats ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.histogramstats]"
    incr row

    set PlotOptions(bins) 20
    ttk::label $frame.label14 -text "Bins:"
    ttk::entry $frame.entry14 -textvariable PlotOptions(bins) -state disabled
    grid configure $frame.label14 -row $row -column 0 -sticky e
    grid configure $frame.entry14 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label14 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label14]"
    bindtags $frame.entry14 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry14]"
    incr row

    set PlotOptions(sizeofbins) ""
    ttk::label $frame.label15 -text "Size Of Bins:"
    ttk::entry $frame.entry15 -textvariable PlotOptions(sizeofbins) -state disabled
    grid configure $frame.label15 -row $row -column 0 -sticky e
    grid configure $frame.entry15 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label15 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label15]"
    bindtags $frame.entry15 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry15]"
    incr row

    set PlotOptions(lowerlimit) ""
    ttk::label $frame.label16 -text "Lower Limit:"
    ttk::entry $frame.entry16 -textvariable PlotOptions(lowerlimit) -state disabled
    grid configure $frame.label16 -row $row -column 0 -sticky e
    grid configure $frame.entry16 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label16 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label16]"
    bindtags $frame.entry16 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry16]"
    incr row

    set PlotOptions(upperlimit) ""
    ttk::label $frame.label17 -text "Upper Limit:"
    ttk::entry $frame.entry17 -textvariable PlotOptions(upperlimit) -state disabled
    grid configure $frame.label17 -row $row -column 0 -sticky e
    grid configure $frame.entry17 -row $row -column 1 -sticky ew -columnspan 2
    bindtags $frame.label17 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.label17]"
    bindtags $frame.entry17 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.entry17]"
    incr row

    set PlotOptions(useroperations) 0
    ttk::checkbutton $frame.useroperations -text "Filter by User Operations Mode" -variable PlotOptions(useroperations)
    grid configure $frame.useroperations -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.useroperations ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(asdstudies) 0
    ttk::checkbutton $frame.asdstudies -text "Filter by ASD Studies Mode" -variable PlotOptions(asdstudies)
    grid configure $frame.asdstudies -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.asdstudies ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(storedbeam) 0
    ttk::checkbutton $frame.storedbeam -text "Filter by Stored Beam (.1 - 300mA)" -variable PlotOptions(storedbeam)
    grid configure $frame.storedbeam -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.storedbeam ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(storedbeam2) 0
    ttk::checkbutton $frame.storedbeam2 -text "Filter by Stored Beam (40 - 300mA) or\nASD Studies Mode                     " -variable PlotOptions(storedbeam2)
    grid configure $frame.storedbeam2 -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.storedbeam2 ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(topup) 0
    ttk::checkbutton $frame.topup -text "Filter by Top Up" -variable PlotOptions(topup)
    grid configure $frame.topup -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.topup ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(srinjection) 0
    ttk::checkbutton $frame.srinjection -text "Filter by SR Injection" -variable PlotOptions(srinjection)
    grid configure $frame.srinjection -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.srinjection ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(binjection) 0
    ttk::checkbutton $frame.binjection -text "Filter by Booster Injection" -variable PlotOptions(binjection)
    grid configure $frame.binjection -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.binjection ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(boosterbeampermit) 0
    ttk::checkbutton $frame.boosterbeampermit -text "Filter by Booster Beam Permit" -variable PlotOptions(boosterbeampermit)
    grid configure $frame.boosterbeampermit -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.boosterbeampermit ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

    set PlotOptions(srbunchpurity) 0
    ttk::checkbutton $frame.srbunchpurity -text "Filter by SR Bunch Purity" -variable PlotOptions(srbunchpurity)
    grid configure $frame.srbunchpurity -row $row -column 0 -sticky w -columnspan 3
    bindtags $frame.srbunchpurity ".userFrame.pane.pane.plotoptions.canvas [bindtags $frame.repeat]"
    incr row

}

proc ToggleHistogramMode {frame} {
    global PlotOptions PVtreectrl
    if {$PlotOptions(histogram)} {
        $frame.histogramstats configure -state normal
        $frame.entry14 configure -state normal
        $frame.entry15 configure -state normal
        $frame.entry16 configure -state normal
        $frame.entry17 configure -state normal
        $PVtreectrl column configure 0 -visible false
        $PVtreectrl column configure 1 -text " "
        set PlotOptions(graphic) "bar"
    } else {
        $frame.histogramstats configure -state disabled
        $frame.entry14 configure -state disabled
        $frame.entry15 configure -state disabled
        $frame.entry16 configure -state disabled
        $frame.entry17 configure -state disabled
        $PVtreectrl column configure 0 -visible true
        $PVtreectrl column configure 1 -text "Y"
        set PlotOptions(graphic) "multicolor line"
    }
}

proc DoExport {args} {
    set type sdds
    APSStrictParseArguments {type}
    global StartTime EndTime PVtreectrl status PlotOptions
    global SampleInterval SelectedDataLoggers PresetTreectrl

    APSSetVarAndUpdate status "Exporting PVs..."
    CalcTime
    if {$StartTime >= $EndTime} {
        bell
        APSSetVarAndUpdate status "The date/time range is invalid"
        return
    }
    set preset 0
    if {[.userFrame.pane.tnb.frame.tn index [.userFrame.pane.tnb.frame.tn select]] == 1} {
        set preset 1
    }

    set xVar ""
    set yVars ""

    global tmpPrefix
    set tmpFile $tmpPrefix/[APSTmpString]
    set index 1

    if {$preset} {
        APSSetVarAndUpdate status "Cannot yet export preset plots."
        return
    }
    set T $PVtreectrl        
    if {[catch {$T item count} count]} {
        set count [$T numitems]
    }
    for {set i 1} {$i < $count} {incr i} {
        if {[$T item cget $i -visible]} {
            if {(!$PlotOptions(timeXaxis)) && ([$T item element cget $i 0 elemImg -image] == "check-on")} {
                set xVar [$T item element cget $i 2 elemTxt -text]
            }
            if {[$T item element cget $i 1 elemImg -image] == "check-on"} {
                lappend yVars [$T item element cget $i 2 elemTxt -text]
            }
        }
    }
    if {[llength $xVar]} {
        lappend yVars $xVar
    }
    if {![llength $yVars]} {
        bell
        APSSetVarAndUpdate status "No PVs selected"
        return
    }

    set sampleIntervals ""
    foreach sdl $SelectedDataLoggers {
        lappend sampleIntervals $SampleInterval($sdl)
    }
    set sampleIntervals [lsort -unique -integer $sampleIntervals]
    #This will only come into play if the Old PVs are selected.
    #In that case we will look in all the sample interval directories for them.
    if {[lindex $sampleIntervals 0] == 0} {
        set sampleIntervals "1 2 4 8 16 32 64 128 256"
    }
    #I need to force it to check all the directories because some PV change sampling rates over time.
    set sampleIntervals "1 2 4 8 16 32 64 128 256"
    set DataFileList ""
    set i 0
    set nextUpdate [expr [clock seconds]+2]
    foreach yVar $yVars {
        if [clock seconds]>$nextUpdate {
            set nextUpdate [expr [clock seconds]+2]
            APSSetVarAndUpdate status "Working on $i of [llength $yVars]"
        }
        set yDataFileList ""
        set year [clock format $StartTime -format %Y]
        set month [clock format $StartTime -format %m]
        set endyear [clock format $EndTime -format %Y]
        set endmonth [clock format $EndTime -format %m]
        set yVarModified [join [split $yVar / ] + ]
        set fileList ""
        while {($year < $endyear) || (($year == $endyear) && ($month <= $endmonth))} {
            append fileList "[lsort [glob -nocomplain /home/helios/oagData/logging/\{[join $sampleIntervals ,]\}/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
            append fileList "[lsort [glob -nocomplain /home/helios/oagData/logging/Variable/[string toupper [string index ${yVarModified} 0]]/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
            if {$month == 12} {
                set month 01
                incr year
            } else {
                scan $month %d month
                incr month
                set month [format %02d $month]
            }
        }
        if {[llength $fileList] > 1} {
            APSAddToTempFileList ${tmpFile}$index
            if {[catch {eval exec sddscombine $fileList -pipe=out -merge | sddsprocess -pipe -filter=column,Time,$StartTime,$EndTime | sddssort -pipe=in ${tmpFile}$index -col=Time -unique} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            lappend DataFileList ${tmpFile}$index
            incr index
        } elseif {[llength $fileList] == 1} {
            APSAddToTempFileList ${tmpFile}$index
            if {[catch {eval exec sddsprocess $fileList ${tmpFile}$index -filter=column,Time,$StartTime,$EndTime } results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            lappend DataFileList ${tmpFile}$index
            incr index  
        } else {
            bell
            APSSetVarAndUpdate status "No data for $yVar in given time frame"
            return
        }
        incr i
    }
    if {$type == "csv"} {
        set types {
            {{CSV Files}        {.csv}        }
            {{All Files}        *             }
        }
    } else {
        set types {
            {{SDDS Files}       {.sdds}       }
            {{All Files}        *             }
        }
    }
    set exportFile [tk_getSaveFile -confirmoverwrite 0 -parent . -filetypes $types]
   # set exportFile [APSFileSelectDialog .fileselect -checkValidity 0]
    if {[llength $exportFile]} {
        if {[llength $DataFileList] > 1} {
            if {$type == "sdds2"} {
                set fillin -fillin
            } else {
                set fillin ""
            }
            set first 1
            while {[llength $DataFileList] >= 1} {
                set dfl [lrange $DataFileList 0 1000]
                set DataFileList [lrange $DataFileList 1001 end]
                if {$first} {
                    set lastFile ""
                    set first 0
                } else {
                    set lastFile ${tmpFile}$index
                }
                incr index
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddsxref $lastFile $dfl ${tmpFile}$index -equate=Time "-take=*" -nowarn $fillin} results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
            }
            if {[catch {exec sddssort ${tmpFile}$index $exportFile -col=Time -unique} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
        } else {
            file copy -force $DataFileList $exportFile
        }
        ApplyFilter -file $exportFile
        if {$type == "csv"} {
            if {[catch {exec sdds2csv -input $exportFile -output $exportFile} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
        }
    }
    APSSetVarAndUpdate status "Done"
}

proc ApplyFilter {args} {
    set file ""
    APSStrictParseArguments {file}
    global PlotOptions
    global StartTime EndTime

    global tmpPrefix
    set tmpFile $tmpPrefix/[APSTmpString]
    set index 1

    set yVars ""
    set lowerLimits ""
    set upperLimits ""
    
    if {$PlotOptions(useroperations) && $PlotOptions(asdstudies)} {
        lappend yVars SRDesiredMode
        lappend lowerLimits 0.5
        lappend upperLimits 4.5
        set mode all
    } elseif {$PlotOptions(useroperations)} {
        lappend yVars SRDesiredMode
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        set mode all
    } elseif {$PlotOptions(asdstudies)} {
        lappend yVars SRDesiredMode
        lappend lowerLimits 1.5
        lappend upperLimits 4.5
        set mode all
    } elseif {$PlotOptions(storedbeam)} {
        lappend yVars S-DCCT:CurrentM
        lappend lowerLimits 0.1
        lappend upperLimits 300.0
        set mode all
    } elseif {$PlotOptions(storedbeam2)} {
        lappend yVars S-DCCT:CurrentM
        lappend lowerLimits 40.0
        lappend upperLimits 300.0
        lappend yVars SRDesiredMode
        lappend lowerLimits 1.5
        lappend upperLimits 4.5
        set mode one
    } elseif {$PlotOptions(topup)} {
        lappend yVars TopUpEnabled 
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars TopUpTime2Warn
        lappend lowerLimits -0.5
        lappend upperLimits 0.5
        set mode all
    } elseif {$PlotOptions(srinjection)} {
        lappend yVars SRInjectOn
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars SRInjecting
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        set mode one
    } elseif {$PlotOptions(binjection)} {
        lappend yVars P:IK:Charge
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars P:EK:Charge
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars P:ESP:Discharge
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars P:ESP:Charge
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars PTB:qTotal
        lappend lowerLimits 0.1
        lappend upperLimits 5.5
        set mode all
    } elseif {$PlotOptions(boosterbeampermit)} {
        lappend yVars ACIS:SA_BP_Mode
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        lappend yVars ACIS:SB_BP_Mode
        lappend lowerLimits 0.5
        lappend upperLimits 1.5
        set mode all
    } elseif {$PlotOptions(srbunchpurity)} {
        lappend yVars SR:bpure2:Counts
        lappend lowerLimits 1000000.0
        lappend upperLimits 9e+99
        lappend yVars SR:bpure2:InvalidCountsAve
        lappend lowerLimits -1.0
        lappend upperLimits 1000.0
        set mode all
    } else {
        return
    }

    set sampleIntervals "1 2 4 8 16 32 64 128 256"
    if {$mode == "all"} {
        foreach yVar $yVars lowerLimit $lowerLimits upperLimit $upperLimits {
            set DataFileList ""
            set year [clock format $StartTime -format %Y]
            set month [clock format $StartTime -format %m]
            set endyear [clock format $EndTime -format %Y]
            set endmonth [clock format $EndTime -format %m]
            set yVarModified [join [split $yVar / ] + ]
            set fileList ""
            while {($year < $endyear) || (($year == $endyear) && ($month <= $endmonth))} {
                append fileList "[lsort [glob -nocomplain /home/helios/oagData/logging/\{[join $sampleIntervals ,]\}/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append fileList "[lsort [glob -nocomplain /home/helios/oagData/logging/Variable/[string toupper [string index ${yVarModified} 0]]/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                if {$month == 12} {
                    set month 01
                    incr year
                } else {
                    scan $month %d month
                    incr month
                    set month [format %02d $month]
                }
            }
            if {[llength $fileList] > 1} {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddscombine $fileList -pipe=out -merge | sddsprocess -pipe=in ${tmpFile}$index -filter=column,Time,$StartTime,$EndTime -filter=column,${yVar},${lowerLimit},${upperLimit} } results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
                lappend DataFileList ${tmpFile}$index
                incr index
            } elseif {[llength $fileList] == 1} {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddsprocess $fileList ${tmpFile}$index -filter=column,Time,$StartTime,$EndTime -filter=column,${yVar},${lowerLimit},${upperLimit} } results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
                lappend DataFileList ${tmpFile}$index
                incr index  
            } else {
                bell
                APSSetVarAndUpdate status "No data for $yVar in given time frame"
                continue
            }
            if {[catch {exec sddsxref $file $DataFileList -equate=Time "-leave=*" -nowarn} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            catch {file delete ${file}~}
        }
    } else {
        set DataFileList ""
        foreach yVar $yVars lowerLimit $lowerLimits upperLimit $upperLimits {
            set year [clock format $StartTime -format %Y]
            set month [clock format $StartTime -format %m]
            set endyear [clock format $EndTime -format %Y]
            set endmonth [clock format $EndTime -format %m]
            set yVarModified [join [split $yVar / ] + ]
            set fileList ""
            while {($year < $endyear) || (($year == $endyear) && ($month <= $endmonth))} {
                append fileList "[lsort [glob -nocomplain /home/helios/oagData/logging/\{[join $sampleIntervals ,]\}/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append fileList "[lsort [glob -nocomplain /home/helios/oagData/logging/Variable/[string toupper [string index ${yVarModified} 0]]/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                if {$month == 12} {
                    set month 01
                    incr year
                } else {
                    scan $month %d month
                    incr month
                    set month [format %02d $month]
                }
            }
            if {[llength $fileList] > 1} {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddscombine $fileList -pipe=out -merge | sddsprocess -pipe -filter=column,Time,$StartTime,$EndTime -filter=column,${yVar},${lowerLimit},${upperLimit} -nowarn | sddsprocess -pipe=in ${tmpFile}$index -retain=column,Time -nowarn} results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
                lappend DataFileList ${tmpFile}$index
                incr index
            } elseif {[llength $fileList] == 1} {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddsprocess $fileList -pipe=out -filter=column,Time,$StartTime,$EndTime -filter=column,${yVar},${lowerLimit},${upperLimit} -nowarn | sddsprocess -pipe=in ${tmpFile}$index  -retain=column,Time -nowarn} results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
                lappend DataFileList ${tmpFile}$index
                incr index  
            } else {
                bell
                APSSetVarAndUpdate status "No data for $yVar in given time frame"
                continue
            }
        }
        APSAddToTempFileList ${tmpFile}$index
        if {[llength $DataFileList]} {
            if {[catch {eval exec sddscombine $DataFileList -pipe=out -retain=column,Time -merge | sddssort -pipe=in ${tmpFile}$index -unique -col=Time } results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            if {[catch {exec sddsxref $file ${tmpFile}$index -equate=Time "-leave=*" -nowarn} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            catch {file delete ${file}~}
        }
    }
}

proc DoPlot {args} {
    global StartTime EndTime PVtreectrl status PlotOptions apsScrolledStatusVar
    global SampleInterval SelectedDataLoggers PresetTreectrl lastPlotCommand extraLoggers timeSeriesConfig
    global env
    if {[info exists env(SDDS_LOGGER_CONFIG)]} {
        set loggingDir [file dirname $env(SDDS_LOGGER_CONFIG)]
    } else {
        set loggingDir /home/helios/oagData/logging
    }

    set i1 [lsearch -exact $SelectedDataLoggers "Booster Injection Waveforms"]
    set i2 [lsearch -exact $SelectedDataLoggers "SR Injection Waveforms"]
    if {$i1 != -1} {
        if {[llength $SelectedDataLoggers] > 1} {
            bell
            APSSetVarAndUpdate status "Booster Injection Waveform can't be selected with other loggers."
            return
        }
        set arrayData 1
    } elseif {$i2 != -1} {
        if {[llength $SelectedDataLoggers] > 1} {
            bell
            APSSetVarAndUpdate status "SR Injection Waveform can't be selected with other loggers."
            return
        }
        set arrayData 1
    } else {
        set arrayData 0
    }


   
    CalcTime
    if {$StartTime >= $EndTime} {
        bell
        APSSetVarAndUpdate status "The date/time range is invalid"
        return
    }
    set preset 0
    if {[.userFrame.pane.tnb.frame.tn index [.userFrame.pane.tnb.frame.tn select]] == 1} {
        set preset 1
    }

    set xVar ""
    set yVars ""
    set filterVars ""

    if {$preset} {
        APSSetVarAndUpdate status "Preset plotting... ([clock format [clock seconds] -format %T])"
        if {$PlotOptions(histogram)} {
            bell
            APSSetVarAndUpdate status "Histogram plotting and preset plots cannot be used together"
            return
        }
        set T $PresetTreectrl

        set IsTimePlot 1
        set FixedTimeScale 0

        if {[catch {$T item count} count]} {
            set count [$T numitems]
        }
        set sddsplotOptions ""
        for {set i 1} {$i < $count} {incr i} {
            if {[$T item element cget $i 0 elemImg -image] == "check-on"} {
                set presetOptions "[$T item element cget $i 3 elemTxt -text]"
                append sddsplotOptions "$presetOptions -end "
                set groupname "[$T item element cget $i 2 elemTxt -text]"
                set index [string first -co $presetOptions 0]
                while {$index != -1} {
                    set i2 [string first " " $presetOptions $index]
                    if {$i2 == -1} {
                        set i2 end
                    }
                    set request [string range $presetOptions $index $i2]
                    set request [join [split [join [split [join [split [join [split [join [split [join [split [join [split $request =]] ,]] \"]] \(]] \)]] \{]] \}]]
                    append xVar "[lindex $request 1] "
                    append yVars "[lrange $request 2 end] "
                    for {set j 0} {$j < [llength [lrange $request 2 end]]} {incr j} {
                        lappend sampleIntervals $SampleInterval($groupname)
                    }
                    set index [string first -co $presetOptions $i2]
                }
                set index [string first -filter $presetOptions 0]
                while {$index != -1} {
                    set i2 [string first " " $presetOptions $index]
                    if {$i2 == -1} {
                        set i2 end
                    }
                    set request [string range $presetOptions $index $i2]
                    set request [join [split [join [split [join [split [join [split [join [split [join [split [join [split $request =]] ,]] \"]] \(]] \)]] \{]] \}]]
                    append filterVars "[lindex $request 2] "
                    lappend sampleFilterIntervals $SampleInterval($groupname)
                    if {[llength $request] >= 5} {
                        append filterVars "[lindex $request 5] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    if {[llength $request] >= 9} {
                        append filterVars "[lindex $request 9] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    if {[llength $request] >= 13} {
                        append filterVars "[lindex $request 13] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    if {[llength $request] >= 17} {
                        append filterVars "[lindex $request 17] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    if {[llength $request] >= 21} {
                        append filterVars "[lindex $request 21] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    if {[llength $request] >= 25} {
                        append filterVars "[lindex $request 25] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    if {[llength $request] >= 29} {
                        append filterVars "[lindex $request 29] "
                        lappend sampleFilterIntervals $SampleInterval($groupname)
                    }
                    set index [string first -filter $presetOptions $i2]
                }
            }
        }
        foreach x $xVar {
            if {$x != "Time"} {
                bell
                APSSetVarAndUpdate status "This preset plot not supported yet."
                return
            }
        }
    }

    global tmpPrefix
    set tmpFile $tmpPrefix/[APSTmpString]
    set index 1

    if {!$preset} {

        APSSetVarAndUpdate status "Plotting... ([clock format [clock seconds] -format %T])"
        
        set T $PVtreectrl
        
        if {[catch {$T item count} count]} {
            set count [$T numitems]
        }
        set yVarsTime ""
        set yVarsEndTime ""
        for {set i 1} {$i < $count} {incr i} {
            if {[$T item cget $i -visible]} {
                if {(!$PlotOptions(timeXaxis)) && ([$T item element cget $i 0 elemImg -image] == "check-on")} {
                    set xVar [$T item element cget $i 2 elemTxt -text]
                }
                if {[string range [$T item element cget $i 2 elemTxt -text] end-7 end] == ".endTime"} {
                    lappend yVarsEndTime [string range [$T item element cget $i 2 elemTxt -text] 0 end-7]
                }
                if {[string range [$T item element cget $i 2 elemTxt -text] end-4 end] == ".time"} {
                    lappend yVarsTime [string range [$T item element cget $i 2 elemTxt -text] 0 end-4]
                }
                if {[$T item element cget $i 1 elemImg -image] == "check-on"} {
                    lappend yVars [$T item element cget $i 2 elemTxt -text]
                }
            }
        }
        if {$PlotOptions(histogram)} {
            if {![llength $yVars]} {
                bell
                APSSetVarAndUpdate status "No PV selected"
                return
            }
        } else {
            if {![llength $yVars]} {
                bell
                APSSetVarAndUpdate status "No Y-axis PVs selected"
                return
            }
            if {![llength $xVar]} {
                if {[llength $yVarsEndTime]} {
                    foreach v $yVars {
                        set i [string first . $v]
                        if {$i > 0} {
                            set i [lsearch -exact $yVarsEndTime [string range $v 0 $i]]
                            if {$i >= 0} {
                                lappend pvaStructureVars([lindex $yVarsEndTime $i]endTime) $v
                            }
                        }
                    }
                    set xVar "pvaStructureTime"
                } elseif {[llength $yVarsTime]} {
                    foreach v $yVars {
                        set i [string first . $v]
                        if {$i > 0} {
                            set i [lsearch -exact $yVarsTime [string range $v 0 $i]]
                            if {$i >= 0} {
                                lappend pvaStructureVars([lindex $yVarsTime $i]time) $v
                            }
                        }
                    }
                    set xVar "pvaStructureTime"
                } else {
                    set xVar "Time"
                }
            }
        }
        if {$PlotOptions(device) != "X-windows"} {
            if {![llength $PlotOptions(outputfile)]} {
                bell
                APSSetVarAndUpdate status "No output filename given"
                return
            }
        }
        
        set sampleIntervals ""
        foreach sdl $SelectedDataLoggers {
            lappend sampleIntervals $SampleInterval($sdl)
        }
        set sampleIntervals [lsort -unique -integer $sampleIntervals]
        #This will only come into play if the Old PVs are selected.
        #In that case we will look in all the sample interval directories for them.
        if {[lindex $sampleIntervals 0] == 0} {
            set sampleIntervals "1 2 4 8 16 32 64 128 256"
        }
#Overriding the sample interval to force a check of every interval.
#The script that creates the input files forces some PVs to log at faster rates because
#the data logging system currently does not have a better way of controlling the log
#rate on a pv by pv level. This really should be added.
        set sampleIntervals "1 2 4 8 16 32 64 128 256"

        if {0} {
            #modified to be able to plot historgram, shang 10/21/2015
        if {$PlotOptions(histogram)} {
            if {[llength $sampleIntervals] != 1} {
                bell
                APSSetVarAndUpdate status "Please select only one data logger category to ensure a single sample interval that is needed to plot histograms."
                return
            }
        }
        }
        set xDataFileListCombined ""
        if {$xVar != "Time"} {
            set xDataFileList ""
            set year [clock format $StartTime -format %Y]
            set month [clock format $StartTime -format %m]
            set endyear [clock format $EndTime -format %Y]
            set endmonth [clock format $EndTime -format %m]
            set xVarModified [join [split $xVar / ] + ]
            while {($year < $endyear) || (($year == $endyear) && ($month <= $endmonth))} {
                append xDataFileList "[lsort [glob -nocomplain ${loggingDir}/\{[join $sampleIntervals ,]\}/${xVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append xDataFileList "[lsort [glob -nocomplain ${loggingDir}/Variable/[string toupper [string index ${xVarModified} 0]]/${xVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                if {$month == 12} {
                    set month 01
                    incr year
                } else {
                    scan $month %d month
                    incr month
                    set month [format %02d $month]
                }
            }
            if {[llength $xDataFileList] > 1} {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddscombine $xDataFileList -pipe=out -merge | sddssort -pipe=in ${tmpFile}$index -col=Time -unique} results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
                lappend xDataFileListCombined ${tmpFile}$index
                incr index
            } else {
                append xDataFileListCombined "$xDataFileList "
            }
        }
        if {[string length $PlotOptions(extra)]} {
            set index2 [string first -filter $PlotOptions(extra) 0]
            while {$index2 != -1} {
                set i2 [string first " " $PlotOptions(extra) $index2]
                if {$i2 == -1} {
                    set i2 end
                }
                set request [string range $PlotOptions(extra) $index2 $i2]
                set request [join [split [join [split [join [split [join [split [join [split [join [split [join [split $request =]] ,]] \"]] \(]] \)]] \{]] \}]]
                append filterVars "[lindex $request 2] "
                set index2 [string first -filter $PlotOptions(extra) $i2]
            }
        }
    }
    
    set yDataFileListCombined ""
    foreach eL $extraLoggers {
        set i [lsearch -exact [lindex $timeSeriesConfig(Column.GroupName) 0] $eL]
        if {$i == -1} {
            continue
        }
        set rootname "[file dirname $loggingDir]/[lindex [lindex $timeSeriesConfig(Column.subDirectory) 0] $i]/[lindex [lindex $timeSeriesConfig(Column.rootname) 0] $i]"
        set year [clock format $StartTime -format %Y]
        set jday [string trimleft [clock format $StartTime -format %j] 0]
        set month [string trimleft [clock format $StartTime -format %m] 0]
        set endyear [clock format $EndTime -format %Y]
        set endjday [string trimleft [clock format $EndTime -format %j] 0]
        while {($year < $endyear) || (($year == $endyear) && ($jday <= $endjday))} {
            append yDataFileList "[lsort [glob -nocomplain ${rootname}-${year}-[format %03d ${jday}]-???? ${rootname}-${year}-[format %03d ${jday}]-????.???? ${rootname}-${year}-${month}.???? ${rootname}-${year}-[format %03d ${jday}]-????.gz  ${rootname}-${year}-[format %03d ${jday}]-????.??:??:??]] "
            incr jday
            if {$jday == 367} {
                incr year
                set jday 1
            }
        }
        append yDataFileListCombined "$yDataFileList "
    }

    set i 0
    foreach yVar $yVars {
        set yDataFileList ""
        set year [clock format $StartTime -format %Y]
        set month [clock format $StartTime -format %m]
        set endyear [clock format $EndTime -format %Y]
        set endmonth [clock format $EndTime -format %m]
        set yVarModified [join [split $yVar / ] + ]
        while {($year < $endyear) || (($year == $endyear) && ($month <= $endmonth))} {
            if {$preset} {
                append yDataFileList "[lsort [glob -nocomplain ${loggingDir}/[lindex $sampleIntervals $i]/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append yDataFileList "[lsort [glob -nocomplain ${loggingDir}/Variable/[string toupper [string index ${yVarModified} 0]]/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
            } else {
                append yDataFileList "[lsort [glob -nocomplain ${loggingDir}/\{[join $sampleIntervals ,]\}/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append yDataFileList "[lsort [glob -nocomplain ${loggingDir}/Variable/[string toupper [string index ${yVarModified} 0]]/${yVarModified}/log-${year}-${month}.{gz,xz,????}]] "
            }
            if {$month == 12} {
                set month 01
                incr year
            } else {
                scan $month %d month
                incr month
                set month [format %02d $month]
            }
        }
        incr i
        if {$preset} {
            append yDataFileListCombined "$yDataFileList "
        } else {
            set combine 0
            set unique ""
            if {$xVar != "Time"} {
                if {[llength $yDataFileList] > 1} {
                    set combine 1
                    set unique -unique
                }
            } else {
                set interval [lindex [split [lindex $yDataFileList 0] /] 5]
                foreach yDataFile $yDataFileList {
                    if {$interval != [lindex [split $yDataFile /] 5]} {
                        #This is needed, just try to plot S35DCCT from loggers at different intervals and you will see
                        set combine 1
                        break
                    }
                }
            }
            if {$combine} {
                if {$PlotOptions(repeat)} {
                    APSSetVarAndUpdate status "Repeat option disabled for this plot"
                }
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddscombine $yDataFileList -pipe=out -merge | sddssort -pipe=in ${tmpFile}$index -col=Time $unique} results]} {
                    bell
                    APSSetVarAndUpdate status "$results"
                    return
                }
                append yDataFileListCombined "${tmpFile}$index "
                incr index
            } else {
                append yDataFileListCombined "$yDataFileList "
            }
        }
    }
    set filterDataFileListCombined ""
    set i 0
    foreach filterVar $filterVars {
        set filterDataFileList ""
        set year [clock format $StartTime -format %Y]
        set month [clock format $StartTime -format %m]
        set endyear [clock format $EndTime -format %Y]
        set endmonth [clock format $EndTime -format %m]
        set filterVarModified [join [split $filterVar / ] + ]
        while {($year < $endyear) || (($year == $endyear) && ($month <= $endmonth))} {
            if {$preset} {
                append filterDataFileList "[lsort [glob -nocomplain ${loggingDir}/[lindex $sampleFilterIntervals $i]/${filterVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append filterDataFileList "[lsort [glob -nocomplain ${loggingDir}/Variable/[string toupper [string index ${filterVarModified} 0]]/${filterVarModified}/log-${year}-${month}.{gz,xz,????}]] "
            } else {
                append filterDataFileList "[lsort [glob -nocomplain ${loggingDir}/\{[join $sampleIntervals ,]\}/${filterVarModified}/log-${year}-${month}.{gz,xz,????}]] "
                append filterDataFileList "[lsort [glob -nocomplain ${loggingDir}/Variable/[string toupper [string index ${filterVarModified} 0]]/${filterVarModified}/log-${year}-${month}.{gz,xz,????}]] "
            }
            if {$month == 12} {
                set month 01
                incr year
            } else {
                scan $month %d month
                incr month
                set month [format %02d $month]
            }
        }
        incr i
        append filterDataFileListCombined "$filterDataFileList "
    }
    if {$preset} {
        if {([llength $filterVars]) || ($PlotOptions(useroperations)) || ($PlotOptions(asdstudies)) || ($PlotOptions(storedbeam)) || ($PlotOptions(storedbeam2)) || ($PlotOptions(topup))  || ($PlotOptions(srinjection))  || ($PlotOptions(binjection))  || ($PlotOptions(boosterbeampermit))  || ($PlotOptions(srbunchpurity))} {
            APSSetVarAndUpdate status "Combining PVs for -filter option"
            APSAddToTempFileList ${tmpFile}$index
            set tmpList ""
            foreach f $filterDataFileListCombined {
                if {[lsearch -exact $yDataFileListCombined $f] == -1} {
                    lappend tmpList $f
                }
            }
            if {[catch {eval exec sddscombinelogfiles $yDataFileListCombined $tmpList ${tmpFile}$index} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            set DataFileList ${tmpFile}$index
            ApplyFilter -file $DataFileList
            incr index
        } else {
            set DataFileList $yDataFileListCombined
        }
    } else {
        if {(([llength $filterVars]) || ($PlotOptions(useroperations)) || ($PlotOptions(asdstudies)) || ($PlotOptions(storedbeam)) || ($PlotOptions(storedbeam2)) || ($PlotOptions(topup))  || ($PlotOptions(srinjection))  || ($PlotOptions(binjection))  || ($PlotOptions(boosterbeampermit))  || ($PlotOptions(srbunchpurity))) && ($xVar != "Time") && (!$PlotOptions(histogram))} {
            APSSetVarAndUpdate status "Combining PVs for -filter option"
            APSAddToTempFileList ${tmpFile}$index
            set tmpList ""
            foreach f $filterDataFileListCombined {
                if {([lsearch -exact $yDataFileListCombined $f] == -1) && ([lsearch -exact $xDataFileListCombined $f] == -1)} {
                    lappend tmpList $f
                }
            }
            if {[catch {eval exec sddscombinelogfiles $xDataFileListCombined $yDataFileListCombined $tmpList ${tmpFile}$index} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            set DataFileList ${tmpFile}$index
            ApplyFilter -file $DataFileList
            incr index
	} elseif {($xVar != "Time") && ($xVar != "pvaStructureTime") && (!$PlotOptions(histogram))} {
            APSAddToTempFileList ${tmpFile}$index
            if {[catch {eval exec sddsxref $xDataFileListCombined $yDataFileListCombined ${tmpFile}$index -equate=Time=Time -nowarn} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            set DataFileList ${tmpFile}$index
            incr index
        } elseif {([llength $filterVars]) || ($PlotOptions(useroperations)) || ($PlotOptions(asdstudies)) || ($PlotOptions(storedbeam)) || ($PlotOptions(storedbeam2)) || ($PlotOptions(topup))  || ($PlotOptions(srinjection))  || ($PlotOptions(binjection))  || ($PlotOptions(boosterbeampermit))  || ($PlotOptions(srbunchpurity))} {
            APSSetVarAndUpdate status "Combining PVs for -filter option"
            APSAddToTempFileList ${tmpFile}$index
            set tmpList ""
            foreach f $filterDataFileListCombined {
                if {[lsearch -exact $yDataFileListCombined $f] == -1} {
                    lappend tmpList $f
                }
            }
            if {[catch {eval exec sddscombinelogfiles $yDataFileListCombined $tmpList ${tmpFile}$index} results]} {
                bell
                APSSetVarAndUpdate status "$results"
                return
            }
            set DataFileList ${tmpFile}$index
            ApplyFilter -file $DataFileList
            incr index
        } else {
            set DataFileList $yDataFileListCombined
        }
    }
    set DataFileList [lsort -unique $DataFileList]
    if {[llength $DataFileList] == 0} {
        APSSetVarAndUpdate status "No data found in given time frame"
    }

    switch -exact $PlotOptions(labelsize) {
        "+15%" {set labelsizeOption -labelSize=.0345}
        "+30%" {set labelsizeOption -labelSize=.039}
        "+45%" {set labelsizeOption -labelSize=.0435}
        "+60%" {set labelsizeOption -labelSize=.048}
        default {set labelsizeOption ""}
    }

    switch -exact $PlotOptions(graphic) {
        "multicolor line" {set graphicOption -graph=line,vary}
        "line" {set graphicOption -graph=line}
        "multicolor symbol" {set graphicOption -graph=symbol,vary=subtype}
        "symbol" {set graphicOption -graph=symbol,vary}
        "multicolor symbol w/line" {set graphicOption -graph=symbol,vary=subtype,connect=subtype}
        "symbol w/line" {set graphicOption -graph=symbol,vary,connect}
        "multicolor dot" {set graphicOption -graph=dot,vary}
        "dot" {set graphicOption -graph=dot}
        "multicolor bar" {set graphicOption -graph=bar,vary,thickness=2}
        "bar" {set graphicOption -graph=bar,thickness=2}
    }
    set graphicTypeModifier ",fixForName"
    if {$preset} {
        #append graphicTypeModifier ",eachRequest"
    }
    set extraOptions ""
    set splitOption ""
    set separateOption ""
    set groupbyOption ""
    if {$PlotOptions(separate)} {
        #each plot panel will have one PV and
        #it will be plotted in white.
        set separateOption -separate=namestring
        set groupbyOption -groupby=namestring
        append graphicTypeModifier ",eachPage"
    }

    if {$PlotOptions(samescale)} {
        set samescaleOption -samescale=y
    } else {
        set samescaleOption ""
    }

    if {$PlotOptions(legends)} {
        set legendOption -legend
        if {$preset} {
            set index [string first -legend $sddsplotOptions 0]
            if {$index != -1} {
                set legendOption ""
            }
        }
    } else {
        set legendOption ""
    }

    if {$PlotOptions(commonoffset)} {
        set commonoffsetOption -mode=y=coffset
    } else {
        set commonoffsetOption ""
    }

    if {[string length $PlotOptions(xlabel)]} {
        set xlabelOption "\"-xlabel=[APSMakeSafeQualifierString $PlotOptions(xlabel)]\""
    } else {
        set xlabelOption ""
    }
    if {[string length $PlotOptions(ylabel)]} {
        set ylabelOption "\"-ylabel=[APSMakeSafeQualifierString $PlotOptions(ylabel)]\""
    } else {
        set ylabelOption ""
    }
    if {[string length $PlotOptions(title)]} {
        set titleOption "\"-title=[APSMakeSafeQualifierString $PlotOptions(title)]\""
    } else {
        set titleOption ""
    }
    if {[string length $PlotOptions(topline)]} {
        set toplineOption "\"-topline=[APSMakeSafeQualifierString $PlotOptions(topline)]\""
    } else {
        set toplineOption ""
    }

    if {[string length $PlotOptions(extra)]} {
        append extraOptions " $PlotOptions(extra) "
    }

    if {$PlotOptions(timeXaxis)} {
        if {$PlotOptions(histogram) || $arrayData} {
            set modeOption ""
        } elseif {$PlotOptions(logy)} {
            set modeOption "-mode=y=log,y=special,x=linear -offset=ychange=$PlotOptions(yLogBase),ybeforelog -ticks=xtime"
        } else {
            set modeOption -ticks=xtime
        }
    } else {
        if {$PlotOptions(logy) && $PlotOptions(logx)} {
            set modeOption -mode=y=log,y=special,x=log,x=special -offset=xchange=$PlotOptions(xLogBase),ychange=$PlotOptions(yLogBase),xbeforelog,ybeforelog
        } elseif {$PlotOptions(logy)} {
            set modeOption -mode=y=log,y=special,x=linear -offset=ychange=$PlotOptions(yLogBase),ybeforelog
        } elseif {$PlotOptions(logx)} {
            set modeOption -mode=y=linear,x=log,x=special -offset=xchange=$PlotOptions(xLogBase),xbeforelog
        } else {
            set modeOption ""
        }
    }
    
    if {$PlotOptions(xmin) || $PlotOptions(xmax) || $PlotOptions(ymin) || $PlotOptions(ymax)} {
        set scaleOption -scale=$PlotOptions(xmin),$PlotOptions(xmax),$PlotOptions(ymin),$PlotOptions(ymax)
    } else {
        set scaleOption ""
    }

    if {$PlotOptions(histogram)} {
        set filterOption ""
        set repeatOption ""
    } else {
        if {$xVar == "pvaStructureTime"} {
            set filterType column
            if {$PlotOptions(repeat)} {
                
                set filterOption -filter=${filterType},[lindex [lsort [array names pvaStructureVars]] 0],$StartTime,1e300
                set repeatOption -repeat
            } else {
                set filterOption -filter=${filterType},[lindex [lsort [array names pvaStructureVars]] 0],$StartTime,$EndTime
                set repeatOption ""
            }
        } else {
            set filterType column
            if {$PlotOptions(repeat)} {
                set filterOption -filter=${filterType},Time,$StartTime,1e300
                set repeatOption -repeat
            } else {
                set filterOption -filter=${filterType},Time,$StartTime,$EndTime
                set repeatOption ""
            }
        }
    }
    switch -exact $PlotOptions(device) {
        "X-windows" {
            if {$PlotOptions(repeat)} {
                set deviceOption {"-device=motif,(-movie true -keep 1)"}
            } else {
                set deviceOption {"-device=motif,(-newzoom true)"}
            }
            set outputfileOption ""
        }
        "B&W Postscript" {
            set deviceOption -device=post
            set outputfileOption -output=$PlotOptions(outputfile)
        }
        "Color Postscript" {
            set deviceOption -device=cpost
            set outputfileOption -output=$PlotOptions(outputfile)
        }
        "PNG file (white)" {
            set deviceOption -device=png,onwhite
            set outputfileOption -output=$PlotOptions(outputfile)
        }
        "PNG file (black)" {
            set deviceOption -device=png,onblack
            set outputfileOption -output=$PlotOptions(outputfile)
        }
    }

    if {$arrayData} {
        foreach f $DataFileList {
            if {[catch {exec sddsprocess $f -pipe=out \
                          -filter=parameter,Time,$StartTime,$EndTime \
                          -retain=array,[join $yVars ,] -nowarn | \
                          sddstimeconvert -pipe=in ${tmpFile}$index \
                          -breakdown=parameter,Time,text=TimeString} result]} {
                bell
                APSSetVarAndUpdate status "$result"
                return
            }
            lappend DataFileListNew ${tmpFile}$index
            incr index
        }
        set DataFileList $DataFileListNew
    }

    if {$PlotOptions(histogram)} {
        set histogramOptions ""
        if {[llength $PlotOptions(sizeofbins)]} {
            append histogramOptions "-sizeOfBins=$PlotOptions(sizeOfBins) "
        } else {
            append histogramOptions "-bins=$PlotOptions(bins) "
        }
        if {[llength $PlotOptions(lowerlimit)]} {
            append histogramOptions "-lowerLimit=$PlotOptions(lowerlimit) "
        }
        if {[llength $PlotOptions(upperlimit)]} {
            append histogramOptions "-upperLimit=$PlotOptions(upperlimit) "
        }
        if {$PlotOptions(histogramstats)} {
            foreach f $DataFileList yVar $yVars {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddsprocess $f -pipe=out -filter=column,Time,$StartTime,$EndTime -process=${yVar},standarddeviation,${yVar}Sigma -process=${yVar},mad,${yVar}Mad -process=${yVar},spread,${yVar}Spread -process=${yVar},average,${yVar}Average | sddsmultihist -pipe=in ${tmpFile}$index -column=[join $yVars ,] -separate $histogramOptions} result]} {
                    bell
                    APSSetVarAndUpdate status "$result"
                    return
                }
                lappend DataFileListNew ${tmpFile}$index
                incr index
            }
        } else {
            foreach f $DataFileList {
                APSAddToTempFileList ${tmpFile}$index
                if {[catch {eval exec sddsprocess $f -pipe=out -filter=column,Time,$StartTime,$EndTime | sddsmultihist -pipe=in ${tmpFile}$index -column=[join $yVars ,] -separate $histogramOptions} result]} {
                    bell
                    APSSetVarAndUpdate status "$result"
                    return
                }
                lappend DataFileListNew ${tmpFile}$index
                incr index
            }
        }
        set DataFileList $DataFileListNew
    }
    set layoutOption -layout=[join [split $PlotOptions(layout) x ] , ]

    global stderrFile
    if {[file exists $stderrFile]} {
        file delete $stderrFile
    }

    set options "$graphicOption$graphicTypeModifier $layoutOption $modeOption $labelsizeOption $samescaleOption $legendOption $commonoffsetOption $xlabelOption $ylabelOption $titleOption $toplineOption $scaleOption $filterOption $repeatOption $separateOption $groupbyOption $extraOptions"
    if {$preset} {
        if {![llength $filterVars]} {
            #Don't trust the -graphic option in the preset plots. Too many of them don't have fixforname defined.
            #Plus this gives the user a little control of the preset plot.
            
            set index [string first -graph $sddsplotOptions 0]
            while {$index != -1} {
                set i2 [string first " " $sddsplotOptions $index]
                if {$i2 == -1} {
                    set i2 end
                }
                set sddsplotOptions [string range $sddsplotOptions 0 [expr {$index - 1}]][string range $sddsplotOptions $i2 end]
                set index [string first -graph $sddsplotOptions 0]
            }
        }
        
        #Remove the -namescan option because this probably should never be used for the one-PV-per-file data files.
        set index [string first -name $sddsplotOptions 0]
        while {$index != -1} {
            set i2 [string first " " $sddsplotOptions $index]
            if {$i2 == -1} {
                set i2 end
            }
            set sddsplotOptions [string range $sddsplotOptions 0 [expr {$index - 1}]][string range $sddsplotOptions $i2 end]
            set index [string first -name $sddsplotOptions 0]
        }

        set sddsplotOptions [join [split $sddsplotOptions \$] \\\$]
        
        eval exec sddsplot $deviceOption $outputfileOption $options $DataFileList $sddsplotOptions 2> $stderrFile &
        set lastPlotCommand "sddsplot $deviceOption $outputfileOption $options $DataFileList $sddsplotOptions\n"
    } else {
        if {$arrayData} {
            set requestOption ""
            foreach elem $yVars {
                append requestOption "-array=$elem "
            }
            eval exec            sddsplot -sep=page -split=pages -groupby=page -topline=@TimeString $options $deviceOption $outputfileOption $DataFileList $requestOption 2> $stderrFile &
            set lastPlotCommand "sddsplot -sep=page -split=pages -groupby=page -topline=@TimeString $options $deviceOption $outputfileOption $DataFileList $requestOption\n"
        } elseif {$PlotOptions(commonoffset) && $PlotOptions(separate)} {
            set requestOption ""
            foreach elem $yVars {
                append requestOption "-column=${xVar},($elem) "
            }
            eval exec sddsplot $DataFileList $options $requestOption $deviceOption $outputfileOption 2> $stderrFile &
            set lastPlotCommand "sddsplot $DataFileList $options $requestOption $deviceOption $outputfileOption\n"
        } elseif {$PlotOptions(histogram)} {
            set requestOption ""
            foreach elem $yVars f $DataFileList {
                if {$PlotOptions(histogramstats)} {
                    append requestOption "-column=${elem},(${elem}Frequency) $f \"-string=@${elem}Sigma,pCoord=.0,qCoord=1.01,editstring=i/  SIGMA =/\" \"-string=@${elem}Mad,pCoord=.5,qCoord=1.01,editstring=i/   MAD =/\" \"-string=@${elem}Average,pCoord=.0,qCoord=1.05,editstring=i/AVERAGE =/\" \"-string=@${elem}Spread,pCoord=.5,qCoord=1.05,editstring=i/SPREAD =/\" -end "
                } else {
                    append requestOption "-column=${elem},(${elem}Frequency) $f -end "
                }
            }
            eval exec sddsplot $options $deviceOption $outputfileOption $requestOption 2> $stderrFile &
            set lastPlotCommand "sddsplot $options $deviceOption $outputfileOption $requestOption\n"
            #set apsScrolledStatusVar(lastPlotCommand) $lastPlotCommand
        } else {
            if {$xVar == "pvaStructureTime"} {
                foreach a [lsort [array names pvaStructureVars]] {
                    append requestOptions "-column=${a},([join $pvaStructureVars($a) ,]) $DataFileList "
                }
                eval exec sddsplot $options $deviceOption $outputfileOption $requestOptions 2> $stderrFile &
                set lastPlotCommand "sddsplot $options $deviceOption $outputfileOption $requestOptions\n"
            } else {
                set requestOption "-column=${xVar},([join $yVars ,])"
                eval exec sddsplot $requestOption $DataFileList $options $deviceOption $outputfileOption 2> $stderrFile &
                set lastPlotCommand "sddsplot $requestOption $DataFileList $options $deviceOption $outputfileOption\n"
            }
        }
    }
    #set apsScrolledStatusVar(lastPlotCommand) $lastPlotCommand
    APSEnableButton .userFrame.bottomButtons.showCommand
    APSEnableButton .userFrame.bottomButtons.savemovie
    APSSetVarAndUpdate status "Done ([clock format [clock seconds] -format %T])"
    after 1000
    global lastPlotCommandOnly
    set lastPlotCommandOnly $lastPlotCommand
    if {[file exists $stderrFile]} {
        set fid [open $stderrFile r]
        set errorOutput [read $fid]
        close $fid
        append lastPlotCommand "\n$errorOutput"
    }
}

proc ShowCommand {args} {
    global lastPlotCommand
    if {![winfo exists .lastPlotCommand]} {
        APSScrolledStatus .lastPlotCommand \
          -name "Plot Command History" \
          -textVariable lastPlotCommand \
          -height 20 \
          -width 100
    }
}

proc SaveLayout {args} {
    global DataLoggerTreectrl PVtreectrl PlotOptions plotName env CustomTreectrl
        
    set T $DataLoggerTreectrl
    set dataLoggers ""
    for {set i 1} {$i < [$T item count]} {incr i} {
        if {[$T item element cget $i 0 elemImg -image] == "check-on"} {
            append dataLoggers "[$T item text $i] "
        }
    }
    if {[file exists $env(HOME)/.dataLoggerViewer] == 0} {
        file mkdir $env(HOME)/.dataLoggerViewer
    }
    set i 0
    while {[file exists $env(HOME)/.dataLoggerViewer/customPlot.[format %05d $i]]} {
        incr i
    }
    set customPlotFile $env(HOME)/.dataLoggerViewer/customPlot.[format %05d $i]
    set fid [open $customPlotFile w]
    puts $fid "set dataLoggers \"$dataLoggers\""

    set T $PVtreectrl
    set xReadbackName ""
    set yReadbackNames ""
    if {[catch {$T item count} count]} {
        set count [$T numitems]
    }
    for {set i 1} {$i < $count} {incr i} {
        if {[$T item cget $i -visible]} {
            if {(!$PlotOptions(timeXaxis)) && ([$T item element cget $i 0 elemImg -image] == "check-on")} {
                set xReadbackName [$T item element cget $i 2 elemTxt -text]
            }
            if {[$T item element cget $i 1 elemImg -image] == "check-on"} {
                lappend yReadbackNames [$T item element cget $i 2 elemTxt -text]
            }
        }
    }
    puts $fid "set xReadbackName \"$xReadbackName\""
    puts $fid "set yReadbackNames \"$yReadbackNames\""

    foreach n [lsort [array names PlotOptions]] {
        puts $fid "set PlotOptions($n) \"$PlotOptions($n)\""
    }
    close $fid
    if {[file exists $env(HOME)/.dataLoggerViewer/customPlotNames.sdds] == 0} {
        set data(ColumnNames) "PlotName File"
        set data(Column.PlotName) [list \"$plotName\"]
        set data(Column.File) [list [file normalize $customPlotFile]]
        sdds save $env(HOME)/.dataLoggerViewer/customPlotNames.sdds data
    } else {
        sdds load $env(HOME)/.dataLoggerViewer/customPlotNames.sdds data
        set var [lindex $data(Column.PlotName) 0]
        lappend var $plotName
        set data(Column.PlotName) [list $var]
        set var [lindex $data(Column.File) 0]
        lappend var [file normalize $customPlotFile]
        set data(Column.File) [list $var]
        sdds save $env(HOME)/.dataLoggerViewer/customPlotNames.sdds data
    }
    set item [$CustomTreectrl item create]
    $CustomTreectrl item style set $item X CHECKSTYLE 
    $CustomTreectrl item style set $item Custom TEXTSTYLE Script TEXTSTYLE
    $CustomTreectrl item element configure $item X elemImg -image check-off
    $CustomTreectrl item element configure $item Custom elemTxt -text "$plotName"
    $CustomTreectrl item element configure $item Script elemTxt -text "[file normalize $customPlotFile]"
    $CustomTreectrl item lastchild root $item
  
}

proc SaveLayoutDialog {args} {
    global PVtreectrl plotName PlotOptions
    set T $PVtreectrl
    set xReadbackName ""
    set yReadbackNames ""
    if {[catch {$T item count} count]} {
        set count [$T numitems]
    }
    for {set i 1} {$i < $count} {incr i} {
        if {[$T item cget $i -visible]} {
            if {(!$PlotOptions(timeXaxis)) && ([$T item element cget $i 0 elemImg -image] == "check-on")} {
                set xReadbackName [$T item element cget $i 2 elemTxt -text]
            }
            if {[$T item element cget $i 1 elemImg -image] == "check-on"} {
                lappend yReadbackNames [$T item element cget $i 2 elemTxt -text]
            }
        }
    }
    if {$xReadbackName == ""} {
        set xReadbackName time
    }
    if {$yReadbackNames == ""} return
    set plotName "$xReadbackName,([join $yReadbackNames ,])"
    if {$PlotOptions(topline) != ""} {
        set plotName $PlotOptions(topline)
    } elseif {$PlotOptions(title) != ""} {
        set plotName $PlotOptions(title)
    }
    APSDialogBox .saveLayout -name "Save Custom Plot" -okCommand SaveLayout
    APSLabeledEntry .label -parent .saveLayout.userFrame -label "Custom Plot Name:" -textVariable plotName -width 50 -packOption "-fill x -expand true"
    
}

proc SavePlotMovie {args} {
    global lastPlotCommand status
    if {![info exist lastPlotCommand] || ![string length $lastPlotCommand]} {
	return -code error "No plot is created yet, please click 'Plot' button first!"
    }
    global movieRoot
    set movieRoot movie
    APSDialogBox .movieroot -name "MovieRootName"  -okCommand "PlotMovie"
    APSLabeledEntry .label -parent .movieroot.userFrame -label "Rootname for movie plot:" -textVariable movieRoot -width 50 -packOption "-fill x -expand true"
}
proc PlotMovie {args} {
    global lastPlotCommandOnly status movieRoot
    set index [lsearch -regexp $lastPlotCommandOnly "-device"]
    set plotcomm [lreplace $lastPlotCommandOnly $index $index "-device=png,template=$movieRoot.%03d.png"]
    set plotcomm1 [lreplace $lastPlotCommandOnly $index $index "-device=png,movie,rootname=$movieRoot"]
    set dir [pwd]
    
    #ffmpeg can not run in background
    catch {eval exec $plotcomm }
    set files [glob -nocomplain ${movieRoot}*.png]
    if ![llength $files] {
	return -code error "Error no png files created, can not generate movie!"
    }
    #puts "ffmpeg -y -framerate 1 -i [join $files] -c:v libx264 -pix_fmt yuv420p $movieRoot.mp4 -nostdin -v 0 "
    eval exec ffmpeg  -y -framerate 1 -i [join $files] -c:v libx264 -pix_fmt yuv420p $movieRoot.mp4 -nostdin -v 0
    set status "Movie plot $dir/$movieRoot.mp4 created"					 
    eval file delete -force $files
    set plotcomm1 [regsub {\(} $plotcomm1 "'("]
    set plotcomm1 [regsub {\)} $plotcomm1 ")'"]
    global MoviePlotCommand
    set MoviePlotCommand $plotcomm1
    catch {destroy .movieCommand}
    APSScrolledStatus .movieCommand \
          -name "Plot Movie Command" \
          -textVariable MoviePlotCommand \
          -height 20 \
          -width 100
}    

if {[file exists /home/helios/oagData/dataLoggerConfig/timeSeries.config]} {
    set tsFile $tmpPrefix/[APSTmpString]
    APSAddToTempFileList $tsFile
    if {[catch {exec sddscombine /home/helios/oagData/dataLoggerConfig/timeSeries.config /home/helios/oagData/dataLoggerConfig/ExtraLogger.config -pipe=out -merge | \
                  sddsprocess -pipe=in $tsFile "-match=column,GroupName=SR Fast Logger,!"} result]} {
        puts stderr $result
        exit
    }

    sdds load $tsFile timeSeriesConfig
}
if {[file exists /home/helios/oagData/dataLoggerConfig/timeSeries.sdds]} {
    sdds load /home/helios/oagData/dataLoggerConfig/timeSeries.sdds timeSeriesSDDS
    sdds load /home/helios/oagData/dataLoggerConfig/timeSeriesOldPVs.sdds timeSeriesOldPVsSDDS
}
if {[file exists /home/helios/oagData/monitoring/SRFastLog1]} {
    set timeSeriesConfig(Column.TabName) [list "[lindex $timeSeriesConfig(Column.TabName) 0] SR"]
    set timeSeriesConfig(Column.monitorProgram) [list "[lindex $timeSeriesConfig(Column.monitorProgram) 0] sddslogger"]
    set timeSeriesConfig(Column.GroupName) [list "[lindex $timeSeriesConfig(Column.GroupName) 0] \"SR Fast Logger\""]
    set timeSeriesConfig(Column.sampleInterval) [list "[lindex $timeSeriesConfig(Column.sampleInterval) 0] 2"]
    set timeSeriesConfig(Column.subDirectory) [list "[lindex $timeSeriesConfig(Column.subDirectory) 0] monitoring/SRFastLog1"]
    set timeSeriesConfig(Column.rootname) [list "[lindex $timeSeriesConfig(Column.rootname) 0] SRFastLog1"]
}
if {[info exists env(SDDS_LOGGER_CONFIG)]} {
    sdds load $env(SDDS_LOGGER_CONFIG) timeSeriesConfig
    set timeSeriesConfig(Column.TabName) $timeSeriesConfig(Column.GroupLabel)
    set timeSeriesConfig(Column.monitorProgram) $timeSeriesConfig(Column.LoggerProgram) 
    set timeSeriesConfig(Column.GroupName) $timeSeriesConfig(Column.LoggerLabel)
    set timeSeriesConfig(Column.sampleInterval) $timeSeriesConfig(Column.SampleInterval)
    set timeSeriesConfig(Column.subDirectory) $timeSeriesConfig(Column.SubDirectory)
    set timeSeriesConfig(Column.rootname) $timeSeriesConfig(Column.Rootname) 
    set timeSeriesConfig(Column.doRun) $timeSeriesConfig(Column.Active)
    set valList ""
    foreach val [lindex $timeSeriesConfig(Column.Active) 0] {
        lappend valList 0
    }
    set timeSeriesConfig(Column.doOnePvPerFileRun) [list $valList]
    sdds load [file dirname $env(SDDS_LOGGER_CONFIG)]/timeSeries.sdds timeSeriesSDDS
}
set status Ready

ttk::panedwindow .userFrame.pane -orient vertical
pack .userFrame.pane -expand yes -fill both

ttk::panedwindow .userFrame.pane.pane -orient horizontal
pack .userFrame.pane.pane -expand yes -fill both

ttk::frame .userFrame.pane.pane.dataLoggers
pack .userFrame.pane.pane.dataLoggers -anchor nw

ttk::frame .userFrame.pane.pane.plotoptions -borderwidth 2 -relief ridge -height 100
pack .userFrame.pane.pane.plotoptions -anchor nw

canvas .userFrame.pane.pane.plotoptions.canvas -width 280 -height 350 \
  -scrollregion "0 0 280 750" \
  -yscrollcommand ".userFrame.pane.pane.plotoptions.scrollbar set"
pack .userFrame.pane.pane.plotoptions.canvas -side left -anchor nw -fill y
ttk::scrollbar .userFrame.pane.pane.plotoptions.scrollbar \
  -orient vertical \
  -command ".userFrame.pane.pane.plotoptions.canvas yview"
pack .userFrame.pane.pane.plotoptions.scrollbar -side right -fill y

bind .userFrame.pane.pane.plotoptions.canvas <Button-4> \
    ".userFrame.pane.pane.plotoptions.canvas yview scroll -1 unit"
bind .userFrame.pane.pane.plotoptions.canvas <Button-5> \
    ".userFrame.pane.pane.plotoptions.canvas yview scroll 1 unit"

if {$screenheight < 960} {
    set height 220
} else {
    set height 370
}
set widgetList [APSTabFrame .tnb -parent .userFrame.pane -width 650 -height $height -labelList {"PVs" "Preset Plots" "Custom Plots"}]
pack .userFrame.pane.tnb -expand true -fill both

set pvTab [lindex $widgetList 0]
set presetTab [lindex $widgetList 1]
set customTab [lindex $widgetList 2]

ttk::frame $pvTab.pvs
pack $pvTab.pvs -expand true -fill both

ttk::frame $presetTab.preset
pack $presetTab.preset -expand true -fill both

ttk::frame $customTab.custom
pack $customTab.custom -expand true -fill both

set DataLoggerTreectrl [CreateDataLoggerTree .userFrame.pane.pane.dataLoggers]
CreatePlotOptionsPane .userFrame.pane.pane.plotoptions.canvas

set PVtreectrl [CreatePVTree $pvTab.pvs]
set PresetTreectrl [CreatePresetPlotTree $presetTab.preset]
set CustomTreectrl [CreateCustomPlotTree $customTab.custom]

.userFrame.pane add .userFrame.pane.pane
.userFrame.pane add .userFrame.pane.tnb
.userFrame.pane.pane add .userFrame.pane.pane.dataLoggers
.userFrame.pane.pane add .userFrame.pane.pane.plotoptions
#.userFrame.pane paneconfigure .userFrame.pane.pane -height 300

if {($apsScriptUser == "decker") || ($apsScriptUser == "sr")} {
    if {[winfo screenheight .] < 1200} {
        set dateEntryStyle new
    } else {
        set dateEntryStyle old
    }
} else {
    set dateEntryStyle new
}

if {$dateEntryStyle == "old"} {
    MakeDateTimeFrameOldStyle .date -parent .userFrame
} else {
    MakeDateTimeFrame .userFrame.date
}

ttk::frame .userFrame.bottomButtons
pack .userFrame.bottomButtons -side top -anchor w -padx 2
ttk::frame .userFrame.bottomButtons2
pack .userFrame.bottomButtons2 -side top -anchor w -padx 2
ttk::button .userFrame.bottomButtons.plot -text Plot -command DoPlot
ttk::button .userFrame.bottomButtons.savemovie -text "Show Movie Plot..." -command SavePlotMovie
ttk::button .userFrame.bottomButtons.search -text "Search for PVs..." -command "exec SearchDataLoggers &"
ttk::button .userFrame.bottomButtons.showCommand -text "Show Command and Errors..." -command ShowCommand
ttk::button .userFrame.bottomButtons.saveLayout -text "Save Custom Plot..." -command SaveLayoutDialog
ttk::button .userFrame.bottomButtons2.exportSDDS -text "Export as SDDS..." -command "DoExport -type sdds"
ttk::button .userFrame.bottomButtons2.exportSDDS2 -text "Export as SDDS (fill in zeros)..." -command "DoExport -type sdds2"
ttk::button .userFrame.bottomButtons2.exportCSV -text "Export as CSV..." -command "DoExport -type csv"
pack .userFrame.bottomButtons.plot  .userFrame.bottomButtons.savemovie .userFrame.bottomButtons.search .userFrame.bottomButtons.showCommand .userFrame.bottomButtons.saveLayout -side left
pack .userFrame.bottomButtons2.exportSDDS .userFrame.bottomButtons2.exportSDDS2 .userFrame.bottomButtons2.exportCSV -side left
#APSDisableButton .userFrame.showCommand.button
APSDisableButton .userFrame.bottomButtons.showCommand
APSDisableButton .userFrame.bottomButtons.savemovie


#Still need to fix preset plots with the -filter option.

