- The SAOTk extension was originally intended for astronomical applications, but can be used for other purposes. It can cope with very large files (see ds9).
- The new canvas item types are the Frame, Panner, Magnifier, and Colorbar. These support the display of images in FITS format, manipulating colormaps, region marking, coordinate readout (including WCS), arbitrary image scaling and rotation, advanced postscript printing, Truecolor graphic support, and image mosaics.
- The documentation lags behind the code
- Papers on SAOTk by its authors William Joye and Eric Mandel: [1] (1999, refers to an older version), [2] (1998, refers to an even older version)
- Binaries and Source for SAOTk are available as part of the ds9 application - download links can be found at [3]
- License: GPL v2
- framepseudocolor8
- frametruecolor8
- frametruecolor16
- frametruecolor24
- framergbtruecolor8 - no docs - check ds9 source
- framergbtruecolor16 - no docs - check ds9 source
- framergbtruecolor24 - no docs - check ds9 source
- colorbarpseudocolor8
- colorbartruecolor8
- colorbartruecolor16
- colorbartruecolor24
- pannerpseudocolor
- pannertruecolor
- magnifierpseudocolor
- magnifiertruecolor
- The screenshot (below) of ds9 shows the SAOTk widgets in action.
- The main graphical display is a canvas widget with a "Frame" item.
- The two smaller graphics at the top are canvas widgets with "Panner" (left) and "Magnifier" (right) items.
- The bar at the bottom is a canvas with a "Colorbar" item.
- When the mouse pointer is in the "Frame", the "Magnifier" gives an enlarged view in real time of the region around the pointer.
- The "Panner" is most useful when the image has been zoomed and only a part is shown in the "Frame". The "Panner" shows the full image, with the cyan rectangle showing the area displayed in the "Frame". Mouse drag operations in the "Panner" control the cyan rectangle and therefore the area displayed in the "Frame".
Does SAOTk require a custom version of Tcl/Tk?- In principle, yes: the README states "DS9 comes with Tcl/Tk8.4.12 [and BLT 2.4z]. There are several modifications to the Tcl/Tk source code to provide support for certain features within DS9. Please use this version when building DS9."
- In practice, the changes appear to be minor on X11 systems. KJN has built SAOTk using the recommended procedure, and found that the library libsaotk.so has no unexpected dependencies and works perfectly well with ActiveTcl 8.4.14 and stock BLT 2.4z. The patches to Tcl/Tk and BLT are greater on Windows and Mac OS X, which I have not tested.
- In astronomy beyond the visible spectrum, the most common form of image is monochrome, displayed with false colour. However, other forms are possible and are supported by FITS, including use of a third array dimension to represent spectral information.
- There are tools for FITS file conversion, and some of these have a Tcl interface. See FITS.
- SAOTk documentation is brief and lags behind the software (e.g. the framergb* item types are undocumented).
- The framergb* item types are capable of loading a conventional RGB image. For example, in DS9, select "New Frame RGB" from the "Frame" menu, and then load colour-separated FITS images into each of the R, G, B channels, which may be selected in turn with the "Current" radiobutton in the RGB popup window. Simplifying this procedure is left as an exercise for the programmer ;-)
- You will need a *.fits file to use the demo. See ds9 for instructions on where to find one.
# Copyright (C) 1999-2005
# Smithsonian Astrophysical Observatory, Cambridge, MA, USA
# For conditions of distribution and use, see copyright notice in "copyright"
# Obtained from the SAOTk docs and patched by KJN in 2007.
# The conditions referred to above are the GPL v2.
lappend auto_path .
package require BLT
load libsaotk.so
package require saotk
# Variables
set simple(visual) [winfo visual .]
set simple(depth) [winfo depth .]
set current(zoom) 1
set current(orient) none
set current(rotate) 0
set canvas(width) 518
set canvas(height) 518
set colorbar(width) 512
set colorbar(height) 15
set colorbar(map) Grey
set colorbar(invert) 0
set scale(mode) minmax
# Procedures
proc OpenFile {} {
set fileName [tk_getOpenFile -parent . -filetypes {{{FITS Files} {.fits} }}]
if {$fileName != ""} {
if [catch {frame1 load fits \"$fileName\" mmapincr}] {
tk_messageBox -message "Unable to load Fits Image $fileName." \
-type ok -icon error
}
}
}
proc AdjustColormap {x y} {
global canvas
set cursorX [expr double($x-$canvas(width)/2+512/2) / 512
set cursorY [expr double($y)/512 * 10]
colorbar adjust $cursorX $cursorY
frame1 colormap [colorbar get colormap]
}
proc UpdateColorbarGeometry {} {
global colorbar
set colorbar(width) [expr [winfo width .simple.colorbar]-2]
set colorbar(height) [expr [winfo height .simple.colorbar]-2]
colorbar configure -width $colorbar(width) -height $colorbar(height)
}
proc UpdateCanvasGeometry {} {
global canvas
set canvas(width) [expr [winfo width .simple.image] - 4]
set canvas(height) [expr [winfo height .simple.image] - 4]
set w $canvas(width)
set h $canvas(height)
set x [expr int($canvas(width)/2.) + 2]
set y [expr int($canvas(height)/2.) + 2]
frame1 configure -x $x -y $y -width $w -height $h -anchor center
}
proc CreateColorMenu {} {
global colorbar
set id [colorbar list id]
set count 0
foreach i $id {
set name [colorbar get name $i]
.menuBar.color insert $count radiobutton -label "$name" \
-command "ChangeColormap $i" -variable colorbar(map)
incr count
}
}
proc ChangeColormap {id} {
global colorbar
colorbar map $id
frame1 colormap [colorbar get colormap]
set colorbar(map) [colorbar get name]
set colorbar(invert) [colorbar get invert]
}
proc ScaleMode {} {
global scale
frame1 clip mode $scale(mode)
}
# Set Application Behavior
set tk_strictMotif 1
wm title . "Simple Image Display"
. configure -menu .menuBar
# Base Frame
frame .simple
# Create Colorbar
canvas .simple.colorbar -width $colorbar(width) \
-height $colorbar(height) \
-bd 2 -relief groove -insertofftime 0
.simple.colorbar create colorbar$simple(visual)$simple(depth) \
-width $colorbar(width) -height $colorbar(height) -anchor nw
colorbar set colormap window .simple
# Create Image
canvas .simple.image -width $canvas(width) -height $canvas(height) \
-bd 2 -relief groove -highlightthickness 0 -insertofftime 0
# Display the Widgets
pack .simple.image -side top -expand true -fill both
pack .simple.colorbar -side bottom -fill x
pack .simple -expand true -fill both
# Menu Bar
menu .menuBar -tearoff 0 -selectcolor red
.menuBar add cascade -label "File" -menu .menuBar.file
.menuBar add cascade -label "Color" -menu .menuBar.color
.menuBar add cascade -label "Zoom" -menu .menuBar.zoom
.menuBar add cascade -label "Orient" -menu .menuBar.orient
.menuBar add cascade -label "Scale" -menu .menuBar.scale
menu .menuBar.file -tearoff 0 -selectcolor red
.menuBar.file add command -label "Open..." -command OpenFile
.menuBar.file add separator
.menuBar.file add command -label "Exit" -command exit
menu .menuBar.color -tearoff 0 -selectcolor red
.menuBar.color add separator
.menuBar.color add checkbutton -label "Invert Colormap" \
-variable colorbar(invert) -command {colorbar invert $colorbar(invert)}
CreateColorMenu
menu .menuBar.zoom -tearoff 0 -selectcolor red
.menuBar.zoom add command -label "Zoom In" \
-command {frame1 zoom 2 2; set current(zoom) [frame1 get zoom]}
.menuBar.zoom add command -label "Zoom Out" \
-command {frame1 zoom .5 .5; set current(zoom) [frame1 get zoom]}
.menuBar.zoom add separator
.menuBar.zoom add radiobutton -label "1/16" \
-variable current(zoom) -value {0.0625 0.0625} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "1/8" \
-variable current(zoom) -value {0.125 0.125} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "1/4" \
-variable current(zoom) -value {0.25 0.25} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "1/2" \
-variable current(zoom) -value {0.5 0.5} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "1" \
-variable current(zoom) -value {1 1} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "2" \
-variable current(zoom) -value {2 2} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "4" \
-variable current(zoom) -value {4 4} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "8" \
-variable current(zoom) -value {8 8} -command {frame1 zoom to $current(zoom)}
.menuBar.zoom add radiobutton -label "16" \
-variable current(zoom) -value {16 16} -command {frame1 zoom to $current(zoom)}
menu .menuBar.orient -tearoff 0 -selectcolor red
.menuBar.orient add radiobutton -label "None" \
-variable current(orient) -value none -command {frame1 orient $current(orient)}
.menuBar.orient add radiobutton -label "Invert X" \
-variable current(orient) -value x -command {frame1 orient $current(orient)}
.menuBar.orient add radiobutton -label "Invert Y" \
-variable current(orient) -value y -command {frame1 orient $current(orient)}
.menuBar.orient add radiobutton -label "Invert X&Y" \
-variable current(orient) -value xy -command {frame1 orient $current(orient)}
.menuBar.orient add separator
.menuBar.orient add radiobutton -label "0 deg" \
-variable current(rotate) -value 0 -command {frame1 rotate to $current(rotate)}
.menuBar.orient add radiobutton -label "90 deg" \
-variable current(rotate) -value 90 -command {frame1 rotate to $current(rotate)}
.menuBar.orient add radiobutton -label "180 deg" \
-variable current(rotate) -value 180 -command {frame1 rotate to $current(rotate)}
.menuBar.orient add radiobutton -label "270 deg" \
-variable current(rotate) -value 270 -command {frame1 rotate to $current(rotate)}
# Scale Menu
menu .menuBar.scale -tearoff 0 -selectcolor red
.menuBar.scale add radiobutton -label "Min Max" \
-variable scale(mode) -command ScaleMode -value minmax
.menuBar.scale add radiobutton -label "IRAF ZScale" \
-variable scale(mode) -command ScaleMode -value zscale
# Make sure that the wm knows when to swap in the colormap (if needed)
wm colormapwindows . ".simple .simple.image"
# Init Colorbar
bind .simple.colorbar <Configure> [list UpdateColorbarGeometry]
colorbar map $colorbar(map)
colorbar invert $colorbar(invert)
# Init Frame
bind .simple.image <Configure> [list UpdateCanvasGeometry]
bind .simple.image <Button-3> {AdjustColormap %x %y}
bind .simple.image <B3-Motion> {AdjustColormap %x %y}
.simple.image create frame$simple(visual)$simple(depth) \
-x 0 -y 0 -anchor nw -command frame1
frame1 colormap [colorbar get colormap]I'm confused by this code:
package require saotk
pack [frame .pippo]
canvas .pippo.ima -width 516 -height 516 -bd 1 -relief solid -insertofftime 0
pack .pippo.ima -side top -expand true -fill both
.pippo.ima create frametruecolor24 -width 512 -height 512 \
-x 4 -y 4 -anchor nw -command frame1
#
set magni [canvas .pippo.magni -width 200 -height 200 -bd 2 -relief groove \
-highlightthickness 0 -insertofftime 0 -takefocus 0]
pack .pippo.magni -expand true -fill both
$magni create magnifiertruecolor -width 204 -height 204 \
-x 2 -y 2 -anchor nw -command magnifier -tag magnifier
#
magnifier clear
magnifier reset
frame1 magnifier on
frame1 magnifier zoom 4
frame1 magnifier graphics 1
frame1 magnifier cursor yes
#
bind .pippo.ima <Motion> {
set id [.pippo.ima find closest \
[.pippo.ima canvasx %x] [.pippo.ima canvasy %y]]
set x [expr {int([.pippo.ima canvasx %x])}]
set y [expr {int([.pippo.ima canvasy %y])}]
frame1 magnifier update $x $y
update
}
#
frame1 load fits HHPZ0094.fits mmapincr
frame1 zoom to fit
frame1 clip mode zscale... the fits file is displayed but the Magnifier doesn't work! (it's still white) Any ideas?
