Viewing contents of file '../idllib/contrib/markwardt/plotimage.pro'
;+
; NAME:
; PLOTIMAGE
;
; AUTHOR:
; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
; craigm@lheamail.gsfc.nasa.gov
;
; PURPOSE:
; Displays an image via a "PLOT"-like interface.
;
; CALLING SEQUENCE:
; PLOTIMAGE, img, [xrange=xrange,] [yrange=yrange,] ...
;
; DESCRIPTION:
;
; PLOTIMAGE displays an image (or slice of an image) on the current
; graphics device. The syntax is very similar to the PLOT command,
; in the sense that an XRANGE and YRANGE for the plot can be
; specified.
;
; More importantly, coordinate ranges can be specified for the
; *image* itself, and then PLOTIMAGE will intelligently crop the
; image so that only the part that falls within the XRANGE and
; YRANGE is displayed. Images often have physical units (other than
; pixels) assigned to their X and Y dimensions. PLOTIMAGE allows
; you to slice the image appropriately and display appropriate
; coordinate axes.
;
; Image coordinates are specified via the IMGXRANGE and IMGYRANGE
; keywords. IMGXRANGE specifies the x-values for the first and last
; pixels in each row. IMGYRANGE gives the y-values for the first
; and last pixels in each column. Default image coordinates are in
; units of pixels.
;
; Plot coordinates are specified in the usual XRANGE and YRANGE
; keywords. The [XY]RANGE may specify a range smaller than the
; image size, so that the image is cropped; or a range larger than
; the image size, in which case the appropriate portion of the image
; is displayed.
;
; INPUTS:
;
; IMG - A byte array to be displayed. An image declared as
; ARRAY(M,N) will be M pixels in the x-direction and N pixels
; in the y-direction. The image is resampled via
; interpolation to fill the desired display region.
;
; OPTIONAL INPUTS:
; NONE
;
; INPUT KEYWORD PARAMETERS:
;
; XRANGE, YRANGE - Each is a two component vector that specifies the
; X and Y plot ranges, respectively. These values
; are not required to coincide with IMG[XY]RANGE.
; Default: the image ranges
;
; IMGXRANGE, IMGYRANGE - Each is a two component vector that
; describes the X and Y position of the first
; and last pixels.
; Default: the size of the image in pixels
;
; POSITION - Position of the inner plot window in the standard
; graphics keyword format. Overrides PANEL and SUBPANEL.
;
; PANEL, SUBPANEL - An alternate way to more precisely specify the
; plot and annotation positions. See SUBCELL.
;
; NOERASE - If set, the display is not erased before graphics
; operations.
;
; NODATA - If set, the image is not actually displayed, but
; coordinate axes may be drawn.
;
; NOAXES - An attempt is made to render the image without coordinate
; axes. This is possible if POSITION, PANEL, or SUBPANEL
; are given.
;
; PLOTIMAGE will pass other keywords directly to the PLOT command
; used for generating the plot axes. XSTYLE=1 and YSTYLE=1 are
; enforced.
;
; OUTPUTS:
; NONE
;
; PROCEDURE:
;
; EXAMPLE:
;
; This example constructs an image whose values are found by
; z(x,y) = cos(x) * sin(y)
; and x and y are in the range [-2,2] and [4,8], respectively.
; The image is then plotted, with appropriate axes.
;
; x = findgen(20)/5. - 2.
; y = findgen(20)/5. + 4.
; zz = cos(x) # sin(y)
; imgxrange = [min(x), max(x)]
; imgyrange = [min(y), max(y)]
; plotimage, bytscl(zz), imgxrange=imgxrange, imgyrange=imgyrange
;
; This second example plots the same image, but with a plot range
; much larger than the image's.
;
; xr=[-10.,10]
; yr=[-10.,10]
; plotimage, bytscl(zz), imgxrange=imgxrange, imgyrange=imgyrange, $
; xrange=xr, yrange=yr
;
; SEE ALSO:
;
; OPLOTIMAGE, BYTSCL
;
; EXTERNAL SUBROUTINES:
;
; SUBCELL, DEFSUBCELL, TVIMAGE
;
; MODIFICATION HISTORY:
; Written, CM, 1997
;
;-
forward_function defsubcell, subcell
function defsubcell, default
if n_elements(default) EQ 0 then default = [-1.,-1,-1,-1]
mysubcell = default
defaultsubpos = [ 0.08, 0.08, 0.95, 0.95 ]
iwh = where(mysubcell LT 0, ict)
if ict GT 0 then $
mysubcell(iwh) = defaultsubpos(iwh)
return, mysubcell
end
function subcell, subpos, position, margin=margin
;; Default value for subposition
if n_elements(subpos) EQ 0 then mysubpos = [-1.,-1,-1,-1] $
else mysubpos = subpos
;; Default value for position - full screen
if n_elements(position) EQ 0 then position = [0.,0.,1.,1.]
;; Get margins if necessary
if keyword_set(margin) EQ 1 OR n_elements(subpos) EQ 0 then $
mysubpos = defsubcell(mysubpos)
;; Compute new window position
x0 = position(0)
y0 = position(1)
dx = position(2)-position(0)
dy = position(3)-position(1)
newsubpos = reform(mysubpos * 0, 4)
newsubpos([0,2]) = x0 + dx * mysubpos([0,2])
newsubpos([1,3]) = y0 + dy * mysubpos([1,3])
return, newsubpos
end
pro plotimage, img, xrange=xrange, yrange=yrange, $
imgxrange=imgxrange, imgyrange=imgyrange, $
position=position, panel=panel, subpanel=subpanel, $
noerase=noerase, nodata=nodata, noaxes=noaxes, $
pixtolerance=pixtolerance, $
_EXTRA=extra
;; Usage message
if n_params() EQ 0 then begin
message, 'PLOTIMAGE, image, xrange=, yrange=, imgxrange=, imgyrange=,..'$
, /info
return
endif
;; Must have a byte-scaled image already
imgsize = size(img)
if imgsize(imgsize(0)+1) NE 1 then begin
message, 'ERROR: image must be of type BYTE', /cont
return
endif
;; Parameter checking
if keyword_set(nodata) then mynodata = 1 else mynodata = 0
if n_elements(pixtolerance) EQ 0 then pixtolerance = 1.e-2
imgpanel = [0., 0., 1., 1.]
;; Image size
imgdim = imgsize(0)
imgxsize = imgsize(1)
if imgdim NE 2 then $
message, 'ERROR: image must have 2 dimensions'
imgysize = imgsize(2)
;; By default, we have no info about the image, and display the
;; whole thing
if n_elements(imgxrange) EQ 0 then $
imgxrange = [ 0L, imgxsize ]
if n_elements(xrange) EQ 0 then $
xrange = imgxrange
if xrange(1) LT xrange(0) then $
message, 'ERROR: Do not reverse XRANGE in PLOTIMAGE'
srcxpix = [ 0L, imgxsize-1 ]
;; Size of one x pix
dx = (imgxrange(1) - imgxrange(0)) / imgxsize
if xrange(0) GE imgxrange(1) OR xrange(1) LE imgxrange(0) then begin
message, 'WARNING: No image data in specified XRANGE.', /info
mynodata = 1
goto, PLOTDATA
endif
;; Case where xrange cuts off image at left
if xrange(0) GT imgxrange(0) then begin
offset = double(xrange(0)-imgxrange(0))/dx
srcxpix(0) = long( offset )
froffset = offset - long(offset)
if abs(froffset) GT pixtolerance then $
xrange(0) = xrange(0) - froffset * dx
endif
;; Case where xrange cuts off image at right
if xrange(1) LT imgxrange(1) then begin
offset = double(imgxrange(1)-xrange(1))/dx
srcxpix(1) = imgxsize - long(offset) - 1
froffset = offset - long(offset)
if abs(froffset) GT pixtolerance then begin
xrange(1) = xrange(1) + froffset * dx
srcxpix(1) = srcxpix(1) + 1
endif
endif
if xrange(0) LT imgxrange(0) then $
imgpanel(0) = (imgxrange(0) - xrange(0))/(xrange(1)-xrange(0))
if xrange(1) GT imgxrange(1) then $
imgpanel(2) = (imgxrange(1) - xrange(0))/(xrange(1)-xrange(0))
;; By default, we have no info about the image, and display the
;; whole thing
if n_elements(imgyrange) EQ 0 then $
imgyrange = [ 0L, imgysize ]
if n_elements(yrange) EQ 0 then $
yrange = imgyrange
if yrange(1) LT yrange(0) then $
message, 'ERROR: Do not reverse YRANGE in PLOTIMAGE'
srcypix = [ 0L, imgysize-1 ]
;; Size of one y pix
dy = (imgyrange(1) - imgyrange(0)) / imgysize
if yrange(0) GE imgyrange(1) OR yrange(1) LE imgyrange(0) then begin
message, 'WARNING: No image data in specified YRANGE.', /info
mynodata = 1
goto, PLOTDATA
endif
;; Case where yrange cuts off image at bottom
if yrange(0) GT imgyrange(0) then begin
offset = double(yrange(0)-imgyrange(0))/dy
srcypix(0) = long( offset )
froffset = offset - long(offset)
if abs(froffset) GT pixtolerance then $
yrange(0) = yrange(0) - froffset * dy
endif
;; Case where yrange cuts off image at top
if yrange(1) LT imgyrange(1) then begin
offset = double(imgyrange(1)-yrange(1))/dy
srcypix(1) = imgysize - long(offset) - 1
froffset = offset - long(offset)
if abs(froffset) GT pixtolerance then begin
yrange(1) = yrange(1) + froffset * dy
srcypix(1) = srcypix(1) + 1
endif
endif
if yrange(0) LT imgyrange(0) then $
imgpanel(1) = (imgyrange(0) - yrange(0))/(yrange(1)-yrange(0))
if yrange(1) GT imgyrange(1) then $
imgpanel(3) = (imgyrange(1) - yrange(0))/(yrange(1)-yrange(0))
PLOTDATA:
if n_elements(position) EQ 0 AND n_elements(panel) EQ 0 $
AND n_elements(subpanel) EQ 0 then begin
;; If neither POSITION nor PANEL/SUBPANEL are given, then plot
;; once to set up axes, despite NOAXES
plot, xrange, yrange, noerase=noerase, /nodata, xstyle=1, ystyle=1, $
_EXTRA=extra
mypanel = fltarr(4)
mypanel([0,2]) = !x.window
mypanel([1,3]) = !y.window
imgposition = subcell(imgpanel, mypanel)
endif else begin
;; Construct the plot size from panel info. Default is full-screen
if NOT keyword_set(noerase) then erase
if n_elements(position) GT 0 then begin
imgposition = subcell(imgpanel, position)
endif else begin
if n_elements(panel) EQ 0 then panel=[0.0,0.0,1.0,1.0]
if n_elements(subpanel) EQ 0 then subpanel = [-1., -1, -1, -1]
subpanel = defsubcell(subpanel)
imgpanel = [0., 0., 1, 1]
imgposition = subcell(subcell(imgpanel, subpanel), panel)
position = subcell(subpanel, panel)
endelse
endelse
if NOT keyword_set(mynodata) then begin
myimg = img(srcxpix(0):srcxpix(1), srcypix(0):srcypix(1))
myimg = reform(myimg, srcxpix(1)-srcxpix(0)+1, srcypix(1)-srcypix(0)+1, $
/overwrite)
tvimage, myimg, position=imgposition, /half_half
endif
if NOT keyword_set(noaxes) then begin
if n_elements(mypanel) GT 0 then begin
axis, xaxis=0, xtickformat='(A1)', xstyle=1
axis, xaxis=1, xtickformat='(A1)', xstyle=1
axis, yaxis=0, ytickformat='(A1)', ystyle=1
axis, yaxis=1, ytickformat='(A1)', ystyle=1
endif else begin
plot, xrange, yrange, /noerase, /nodata, /normal, xstyle=1, $
ystyle=1, position=position, _EXTRA=extra
endelse
endif
return
end