;+
;
; @file_comments
; Enhanced version of TVSCL
;
; @categories
; quick exploration of 2D arrays
;
; @param Z2D {in}{required}
; 2D array to visualize
;
; @param CELLSIZE {in}{optional}
; This is the size (in pixel) of the square
; representing 1 array element. By default, this size is computed
; automatically in order that the size of the plotting window do
; not exceed the screen size. If the user specify a large value
; of cellsize that forces tvplus to create a window larger than
; the screen, a "scrolling window" will be displayed instead of a
; regular window. Unfortunately the nice functionalities of tvplus
; are not coded for "scrolling window" case...
;
; @keyword BOTTOM {default=1}
; The lowest color index of the colors to be used
;
; @keyword C_NAN {default=!d.n_colors < 255}
; The color number that should be used for the NaN values.
;
; @keyword C_MASK {default=0}
; The color number that should be used for the mask values.
;
; @keyword OFFSET
; 2 elements vector used by tvplus itself when showing zoom.
; It is used to shift the ranges of xaxis and yaxis.
; For example: tvplus,sst[x1:x2,y1:y2],offset=[x1,y1]
;
; @keyword MASK
; The mask value. Note that if abs(mask) < 1.e6, then the
; exact value of the mask is used to find the maskwd point.
; if abs(mask) > 1.e6, the test to find the masked value is ge
; abs(mask)/10. This is necessary to avoid the rounding errors
;
; @keyword MIN
; Scalar used to specify the min value to be drawn.
;
; @keyword MAX
; Scalar used to specify the max value to be drawn.
;
; @keyword NCOLORS {default=(d.n_colors < 256) - 1 - bottom}
; number of colors to be used.
;
; @keyword NOINTERP
; Used this keyword if you don't want that the values
; are interpolated from BOTTOM using NCOLORS colors.
; This can be for example useful when working on byte type arrays.
;
; @keyword NOUSEINFOS
; Activate to suppress the printed message explaining how to use tvplus
;
; @keyword WINDOW
; Number of the window used to display the array values.
; default is window number 0.
;
; @keyword _EXTRA
; Used to pass keywords to TV,
; PLOT,
; colorbar
;
; @restrictions
; use your mouse to scan the array values...
; left button : mouse position and associated array value
; middle button: use it twice to define a zoom box
; right button : quit
;
; the nice functionalities of tvplus are not coded
; for "scrolling window" case...
;
; @examples
; IDL> tvplus, dist(100)
;
; @history
; Sebastien Masson (smasson\@lodyc.jussieu.fr)
; 18/12/98
; Aug 2005: quick cleaning + english
;
; @version
; $Id$
;
;-
PRO tvplus, z2d, cellsize $
, BOTTOM=bottom, C_MASK=c_mask, C_NAN=c_nan, WINDOW=window $
, MIN=min, MAX=max, MASK=mask, OFFSET=offset $
, NOUSEINFOS=NOUSEINFOS $
, NCOLORS=ncolors, NOINTERP=nointerp, _EXTRA=ex
;
compile_opt idl2, strictarrsubs
;
IF n_elements(z2d) EQ 0 THEN return
arr = reform(float(z2d))
;------------------------------------------------------------
; check the size of the input array
;------------------------------------------------------------
if (size(arr))[0] NE 2 then begin
ras = report('Input array must have only 2 dimensions and not '+ strtrim(size(arr, /n_dimensions), 1))
return
endif
;------------------------------------------------------------
; def of ncolmax, bottom, topcol and ncolors
;------------------------------------------------------------
ncolmax = !d.n_colors < 256
IF N_ELEMENTS(bottom) EQ 0 THEN bottom = 1
if NOT keyword_set(ncolors) then ncolors = ncolmax - 1 - bottom
topcol = (bottom+ncolors-1) < (ncolmax-1)
;------------------------------------------------------------
; get default values of !x, !y, !z
;------------------------------------------------------------
; xenvsauve = !x & yenvsauve = !y & penvsauve = !p
reinitplt, /z, /invert
;------------------------------------------------------------
; Do we have NaN values in arr???
;------------------------------------------------------------
nan = total(finite(z2d, /nan)) < 1
if keyword_set(nan) then begin
nanindex = where(finite(z2d, /nan) EQ 1)
arr[nanindex] = min(arr, /nan)
endif
;------------------------------------------------------------
; Compute the size (in pixel) of the square representing 1
; point of the input array
;------------------------------------------------------------
dimensions = GET_SCREEN_SIZE()
if n_elements(cellsize) EQ 0 then BEGIN
cellsize = min(floor(dimensions/(size(z2d))[1: 2]*.75))
ENDIF ELSE $
; we need to use a scrolling bar window
if cellsize GE min(floor(dimensions/(size(z2d))[1: 2]*.75)) then scrolling = 1
if cellsize LT 1 then begin
cellsize = 1
scrolling = 1
endif
;------------------------------------------------------------
; Change the value of the masked value for the min of the non-masked values
;------------------------------------------------------------
if n_elements(mask) then BEGIN
if abs(mask) LT 1e6 then BEGIN
masked = where(arr EQ mask)
if masked[0] NE -1 then arr[masked] = min(arr[where(arr NE mask)])
ENDIF ELSE BEGIN
masked = where(abs(arr) GE abs(mask)/10.)
if masked[0] NE -1 then arr[masked] = min(arr[where(abs(arr) LT abs(mask)/10.)])
ENDELSE
ENDIF ELSE masked = -1
;------------------------------------------------------------
; apply min/max keywords
;------------------------------------------------------------
if n_elements(min) NE 0 then BEGIN
arr = min > arr
truemin = min
ENDIF ELSE truemin = min(arr)
if n_elements(max) NE 0 then BEGIN
arr = arr < max
truemax = max
ENDIF ELSE truemax = max(arr)
;
IF truemin EQ truemax THEN BEGIN
dummy = report('constant value everywhere: '+ strtrim(truemin, 1))
return
ENDIF
;------------------------------------------------------------
; apply other keywords (nointerp, c_nan, c_mask)
;------------------------------------------------------------
if NOT keyword_set(nointerp) then BEGIN
; interpolation between bottom and bottom+ncolors-1
m = 1.*(ncolors-1)/(truemax-truemin)
p = bottom-1.*truemin*m
arr = round(m*temporary(arr)+p)
endif
; set c_nan for NaN values
if keyword_set(nan) then begin
if n_elements(c_nan) NE 0 THEN arr[nanindex] = c_nan < (ncolmax -1) $
ELSE arr[nanindex] = topcol
endif
; c_mask for masked values
if n_elements(c_mask) NE 0 AND masked[0] NE -1 THEN $
arr[masked] = c_mask < (ncolmax -1)
; use byte type to save memory
arr = byte(temporary(arr))
; increase the size of the array in order to be displayed
; with the suitable size
szarr = size(arr, /dimensions)
arr = congrid(temporary(arr), szarr[0]*cellsize, szarr[1]*cellsize)
;------------------------------------------------------------
; open a window with the correct size
;------------------------------------------------------------
nx = (size(arr))[1]
ny = (size(arr))[2]
; margin size (in pixel)
xyaspect = 1.*nx/ny
if xyaspect GE 1 THEN marginpix = 1.*[25, 25, 75, 25] ELSE marginpix = 1.*[25, 100, 25, 25]
;
if n_elements(scrolling) EQ 0 then BEGIN ; open the regular window
if NOT keyword_set(window) then window = 0
window, window, xsize = nx+marginpix[0]+marginpix[1] $
, ysize = ny+marginpix[2]+marginpix[3]
; for 24 bits colors, make sure that the background color is the good one...
if !d.n_colors gt 256 then BEGIN
device, decomposed = 1
!p.background = 'ffffff'x
plot, [0], [0], xstyle = 5, ystyle = 5
device, decomposed = 0
endif
tv, arr, marginpix[0], marginpix[2], _EXTRA = ex
;
; axis and plot frame
;
; get the normalized position of the tv (we just done above)
; to know where the frame should be drawn
poscadre = fltarr(4)
poscadre[0] = marginpix[0]/!d.x_size
poscadre[2] = 1.-marginpix[1]/!d.x_size
poscadre[1] = marginpix[2]/!d.y_size
poscadre[3] = 1-marginpix[3]/!d.y_size
; Use plot to draw the frame
if NOT keyword_set(offset) then offset = [0, 0]
!p.position = poscadre
plot, [0], [0], /nodata, /noerase, position = poscadre, color = 0 $
, xstyle = 1, ystyle = 1, xticklen = 1, yticklen = 1 $
, xrange = 1.*[0, nx]/cellsize-.5+offset[0] $
, yrange = 1.*[0, ny]/cellsize-.5+offset[1], _extra = ex
xenvsauve = !x & yenvsauve = !y & penvsauve = !p
;
; draw the colorbar
;
IF truemin ne truemax THEN BEGIN
if xyaspect ge 1 then $
posbar = [25./!d.x_size, 25./!d.y_size, 1-25./!d.x_size, 50./!d.y_size] $
ELSE posbar = [1-75./!d.x_size, 25./!d.y_size, 1-50./!d.x_size, 1-25./!d.y_size]
if keyword_set(nointerp) then BEGIN & truemin = 0 & truemax = ncolmax & endif
colorbar, min = truemin, max = truemax, division = 10, cb_color = 0, position = posbar $
, vertical = xyaspect lt 1, /right, BOTTOM = bottom, NCOLORS = ncolors, _EXTRA = ex
ENDIF
; !p.position = poscadre
ENDIF ELSE BEGIN
;------------------------------------------------------------
; scrolling bar window case...
;------------------------------------------------------------
; for 24 bits colors, make sure that the background color is the good one...
if !d.n_colors gt 256 then begin
window, /pixmap
device, decomposed = 1
!p.background = 'ffffff'x
plot, [0], [0]
device, decomposed = 0
endif
slide_image, arr $ ; We draw it in a window with a scrolling bar
, xsize = nx, ysize = ny $
, xvisible = round(.7*dimensions[0]) < (size(arr))[1] $
, yvisible = round(.7*dimensions[1]) < (size(arr))[2], /register, congrid = 0, show_full = 0
return
ENDELSE
;------------------------------------------------------------
; Use the mouse to get nice functionalities
;------------------------------------------------------------
; format to print the mouse position
CASE 1 OF
nx LT 10:fmt1 = '(i1)'
nx LT 100:fmt1 = '(i2)'
nx LT 1000:fmt1 = '(i3)'
nx LT 10000:fmt1 = '(i4)'
ELSE:fmt1 = ''
ENDCASE
CASE 1 OF
ny LT 10:fmt2 = '(i1)'
ny LT 100:fmt2 = '(i2)'
ny LT 1000:fmt2 = '(i3)'
ny LT 10000:fmt2 = '(i4)'
ELSE:fmt2 = ''
ENDCASE
;
if NOT keyword_set(nouseinfos) then begin
print, 'left button : mouse position and associated array value'
print, 'middle button: use it twice to define a zoom box'
print, 'right button : quit'
endif
cursor, x, y, /device, /down
x = x-marginpix[0] & x = 0 > floor(x/cellsize) < ((size(arr))[1]/cellsize-1)
y = y-marginpix[2] & y = 0 > floor(y/cellsize) < ((size(arr))[2]/cellsize-1)
while (!mouse.button ne 4) do BEGIN
case !mouse.button of
0:return
1:BEGIN ; get value
if x LE nx/cellsize AND y LE ny/cellsize then begin
print, '(x, y) = (' + string(x+offset[0], format = fmt1) $
+ ', ' + string(y+offset[1], format = fmt2) $
+ '), value = '+strtrim(float((reform(z2d))[x, y]), 1)
ENDIF
cursor, x, y, /device, /down
x = x-marginpix[0] & x = 0 > floor(x/cellsize) < ((size(arr))[1]/cellsize-1)
y = y-marginpix[2] & y = 0 > floor(y/cellsize) < ((size(arr))[2]/cellsize-1)
END
2:BEGIN ; zoom
cursor, x2, y2, /device, /down
x2 = x2-marginpix[0] & x2 = 0 > floor(x2/cellsize) < ((size(arr))[1]/cellsize-1)
y2 = y2-marginpix[2] & y2 = 0 > floor(y2/cellsize) < ((size(arr))[2]/cellsize-1)
x = [x, x2] & x = x[sort(x)]
y = [y, y2] & y = y[sort(y)]
IF keyword_set(OFFSET) THEN offset = [x[0], y[0]]+offset ELSE offset = [x[0], y[0]]
tvplus, z2d[x[0]:x[1], y[0]:y[1] ], WINDOW = window, MIN = min, MAX = max $
, MASK = mask, C_MASK = c_mask, C_NAN = c_nan, /NOUSEINFOS, OFFSET = OFFSET $
, NCOLORS = ncolors, NOINTERP = nointerp, BOTTOM = bottom, _EXTRA = ex
return
END
ELSE:
endcase
ENDWHILE
;------------------------------------------------------------
!x = xenvsauve & !y = yenvsauve & !p = penvsauve
!x.range = 1.*[0, nx]/cellsize-.5+offset[0]
!y.range = 1.*[0, ny]/cellsize-.5+offset[1]
;------------------------------------------------------------
return
end