pro spectrogram, Z0, X0, Y0, X1, Y1, X2, Y2, $ colorbar=colorbar, ctitle=ctitle, cscale=cscale, cCharSize=cCharSize, $ logZ=logZ, logX=logX, logY=logY, $ center=center, centerX=centerX, centerY=centerY, $ fillValue=fillValue, Xfillval=Xfillval, Yfillval=Yfillval, $ maxValue=maxValue, minValue=minValue, nResCol=nResCol, $ noSkipGaps=noSkipGaps, noYSkipGaps=noYSkipGaps, $ quick=quick, reduce=reduce, noclip=noclip, status=status, $ firstplot=firstplot, $ _Extra=extra ;+ ; NAME: ; Spectrogram ; ; PURPOSE: ; This function plots a color spectrogram of Z in contiguous or ; non-contiguous blocks with color Z(i,j) (data Z(i,j) is shown as a box ; of size Xmin(i):Xmax(i) and Ymin(j):Ymax(j) with color Z(i,j)) ; ; CATEGORY: ; Graphics ; ; CALLING SEQUENCE: ; SPECTROGRAM, Z, [X, Y] ; SPECTROGRAM, Z, Xmin, Ymin, Xmax, Ymax ; SPECTROGRAM, Z, Xcenter, Ycenter, Xminus, Yminus, Xplus, Yplus ; ; INPUTS: ; Z: 2-dimensional data array; converted to float or double for NAN use ; ; OPTIONAL INPUTS: ; X: 1-dimensional data array of size Z[*,0] or 2-dim of size Z[*,*] ; Y: 1-dimensional data array of size Z[0,*] or 2-dim of size Z[*,*] ; ; Xmin: 1- or 2- dim array of X values for left side of each data box ; Ymin: 1- or 2- dim array of Y values for bottom side of each data box ; Xmax: 1- or 2- dim array of X values for right side of each data box ; Ymax: 1- or 2- dim array of Y values for top side of each data box ; ; Xcenter:1- or 2- dim array of X values for center side of each data box ; Ycenter:1- or 2- dim array of Y values for center side of each data box ; Xminus: Xcenter-Xminus defines left side of each data box ; Yminus: Ycenter-Yminus defines bottom side of each data box ; Xplus: Xcenter+Xplus defines right side of each data box ; Yplus: Ycenter+Yplus defines top side of each data box ; (this allows gaps or overlaps in boxes; if not desired, use Z,X,Y case) ; ; KEYWORD PARAMETERS: ; COLORBAR=colorbar: Switch to create color bar on right ; CSCALE=cScale: scale for colorbar range [min, max]; sets /colorbar ; CTITLE=cTitle: String title for colorbar ; CCHARSIZE=cCharSize: Character size for axis on color bar ; LOGZ=logZ: Scale Z data and color scale logarithmically ; LOGX=logX: Scale Y axis logarithmically ; LOGY=logY: Scale Y axis logarithmically ; CENTER=center: Center boxes on (X,Y) location (only for 3 parameter ; case: spectrogram, Z, X, Y, /center) ; CENTERX=centerX: Center boxes in X direction (only for 3 parameter ; case: spectrogram, Z, X, Y, /centerX) ; CENTERY=centerY: Center boxes in Y direction (only for 3 parameter ; case: spectrogram, Z, X, Y, /centerY) ; FILLVALUE=fillValue: Z data with this value are ignored ; YFILLVALUE=YfillValue: Y data with this value are ignored ; XFILLVALUE=XfillValue: X data with this value are ignored ; MAXVALUE=maxValue: Max value of data to plot; values above are ignored ; MINVALUE=minValue: Min value of data to plot; values below are ignored ; [probably better to use cScale so extremas are colored not ignored] ; NRESCOL=nResCol: number of colors to reserve outside color table, def=2 ; NOSKIPGAPS=noSkipGaps: Turns off treating large delta X as missing data ; and skip; not done anyway if Center option selected ; #### Also assumes 1-dim X array ; NOYSKIPGAPS=noYSkipGaps: Turns off treating large delta Y as missing data ; QUICK=quick: Allow quick and dirty plotting ignoring X and Y sizes ; (for X and Z plot devices only) ; REDUCE=reduce: Reduce the number of X values to polyfill to not more ; than twice the number of pixels across the plot, by ; sampling every so many values; for non-Postscript ; devices only; done for speed, alternative to /quick ; NOCLIP=noclip: Polyfill bug in Z device; defaults to noclip=0 ; STATUS=status: Return 0 if plot okay, else -1 for an error, ; status variable must be predefined before call ; _EXTRA=extra: Any extra parameters to pass on to plot outline ; Add your own title, xtitle, ytitle ; May be able to over-ride plot location/size with position ; ; OUTPUTS: ; No outputs. ; ; COMMON BLOCKS: ; DEVICETYPEC: deviceType ; Shared with DeviceOpen.pro to allow inverting grayscale Postscript ; ; SIDE EFFECTS: ; Creates plot to screen or file. ; ; RESTRICTIONS: ; Sets a specific X margin to allow for the colorbar. ; Forces input arrays to float or double ; ; SUBROUTINES: ; Calls colorbar.pro, findgaps.pro, align_center.pro ; ; PROCEDURE: ; Uses plot,/nodata to setup the plot area and then uses polyfill to ; on each data value to color each small square of the spectrogram ; A colorbar is plotted on the right if cscale is set. ; ; EXAMPLE: ; Create a spectrogram plot of 2 dimensional data Z = dist(50) ; spectrogram, dist(50), /colorbar ; spectrogram,dist(50),findgen(50),findgen(50)+1,findgen(50),findgen(50)+1 ; ; MODIFICATION HISTORY: ; Written by: Bobby Candey, NASA GSFC Code 632, 1993 August 27 ; Robert.M.Candey.1@gsfc.nasa.gov ; 1993 Nov 9 BC, removed timeaxis call and made more generic ; 1994 Sept 19 BC, update with documentation and higher level routine ; 1994 Nov 28 BC, added handling of 2-dim X and Y ; 1994 Dec 6 BC, merged routines and added center-minus-plus option ; 1995 April 10 BC, completed initial coding of version 5 ; 1995 Jun 22 BC, added smaller font size for color bar axis ; 1995 July 26 BC, added cCharSize and reforming ; 1995 Oct 11 BC, added min/maxValue scaling to bytscl ; 1996 March 17 BC, added skip over time gaps and added fillValue ; 1996 March 18 BC, added /reduce for speed plotting ; 1996 March 25 BC, added noclip keyword for Z device bug with polyfill ; 1996 April 8 BC, added status keyword and plot a blank on all fill ; 1996 April 16 BC, moved Cscale to override min/maxValue ; 1996 April 17 BC, added colorBar switch to allow autoscale ; 1996 August 28 BC, added save for !p.multi so overplot works ; 2001 March 7 BC, added centerX/Y, XfillVal, and repaired Yfillval, etc. ; 2001 March 16 BC, repaired Yfillval, force all to float/double, added checks for NAN ; 2001 March 20 BC, added noYskipGaps, logX, and rearranged calling sequence for clarity ; 2001 March 30 BC, added nResCol in place of fixed 2 colors ; 2001 April 27 BC, added additional fillValue checks and updated alog10(Z) section ; 2001 August 9 BC, added logY tick sections ; ;Copyright 1996-2013 United States Government as represented by the ;Administrator of the National Aeronautics and Space Administration. ;All Rights Reserved. ; ;- common deviceTypeC, deviceType, file;required for inverting grayscale Postscript forward_function loglevels if (n_params(0) lt 1) then $ message, 'spectrogram, Z, [X, Y] or [Xmin, Ymin, Xmax, Ymax]' if (n_elements(nResCol) le 0) then nResCol = 2 if (n_elements(status) gt 0) then doStatus = 1 else doStatus = 0 ;if (n_elements(extra) le 0) then extra = {} status = 0L ;if doStatus then begin ; catch, error_status ; if (error_status ne 0) then begin ; message, 'General error: '+string(error_status)+': '+!err_string, /info ; status = -1L & return ; endif ; else return ;endif if not keyword_set(logX) then logX = 0 if not keyword_set(logY) then logY = 0 if not keyword_set(logZ) then logZ = 0 Z = 1.*reform(Z0) ; remove extraneous dimensions Zsize = size(Z) if (Zsize[0] ne 2) then begin msgText = 'Requires 2-dimensional Z array' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif case n_params(0) of 1: begin ; Z only Xmin = rebin(dindgen(Zsize[1]),Zsize[1],Zsize[2],/sample) & Xmax = Xmin + 1 Ymin = rebin(dindgen(1,Zsize[2]),Zsize[1],Zsize[2],/sample) & Ymax = Ymin + 1 end ; Z only 3: begin ; Z, X, Y X0 = 1.*reform(X0) & Y0 = 1.*reform(Y0) ; remove extraneous dimensions Vsize = size(X0) if not ((Vsize[Vsize[0]+2] eq Zsize[1]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'X must be of same size as Z[*,0] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[1]) then Xmin = X0 else $ Xmin = rebin(X0,Zsize[1],Zsize[2],/sample) Vsize = size(Y0) if not ((Vsize[Vsize[0]+2] eq Zsize[2]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Y must be of same size as Z[0,*] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[2]) then Ymin = Y0 else $ Ymin = rebin(reform(Y0,1,Zsize[2],/overwrite),Zsize[1],Zsize[2],/sample) ; added checks for fillVal, BC 2001Mar7 if n_elements(Xfillval) gt 0 then begin wn = where(Xmin eq Xfillval[0], wnc) if wnc gt 0 then Xmin[wn] = !values.d_nan ; set to NAN ; wn = where(Xmin ne Xmin, wnc) ; find NANs including XfillVal's wn = where(finite(Xmin), wnc) ; find non-NANs including XfillVal's if wnc le 0 then begin ; no valid Xmin data msgText = 'No valid Xmin data' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif ; wnc le 0 endif ; Xfillval if n_elements(Yfillval) gt 0 then begin wn = where(Ymin eq Yfillval[0], wnc) if wnc gt 0 then Ymin[wn] = !values.d_nan ; set to NAN ; wn = where(Ymin ne Ymin, wnc) ; find NANs including XfillVal's wn = where(finite(Ymin), wnc) ; find non-NANs including XfillVal's if wnc le 0 then begin ; no valid Ymin data msgText = 'No valid Ymin data' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif ; wnc le 0 endif ; Yfillval ; create Xmax and Ymax from Xmin and Ymin if keyword_set(center) then begin centerX = 1 & centerY = 1 endif if keyword_set(centerX) then begin ;align_center, X, Xmin, Xmax ; 1 dim case Xmax = Xmin for i = 0L, Zsize[2]-1 do begin align_center, Xmin[*,i], Xmint, Xmaxt Xmin[*,i] = Xmint & Xmax[*,i] = Xmaxt endfor ; i endif else begin ; shift min up to max array and add top value ; Scheme for aligning lower left corner of box on (X, Y) position ;Xmax = [X[1:*], X[nX-1]*2 - X[nX-2]] ; add deltaX to last item; 1 dim case Xmax = shift(Xmin,-1,0) ; shift all elements in 1st dim to the left ; ####following assumes last 2 values in each row are real if logX then begin ;### Xmax[Zsize[1]-1,*]=alog10(10^(Xmin[Zsize[1]-1,*])*2 - 10^(Xmin[Zsize[1]-2,*])) Xmax[Zsize[1]-1,*]=10^(alog10(Xmin[Zsize[1]-1,*])*2 - alog10(Xmin[Zsize[1]-2,*])) endif else begin Xmax[Zsize[1]-1,*] = Xmin[Zsize[1]-1,*]*2 - Xmin[Zsize[1]-2,*] endelse ; 2001 Mar 20 BC, new code for skipping NANs ; where Xmin has a real value and Xmax is NAN then set Xmax to next real Xmax up ; next real value may be much further up; ####do skipGaps to handle ; also does not have a value when NANs in last two positions? ; w = where((Xmax ne Xmax) and (Xmin eq Xmin), wc) w = where((finite(Xmax) ne 1) and finite(Xmin), wc) if (wc gt 0) then $ for i=0L,wc-1 do begin j = w[i] mod Zsize[1] k = long(w[i]/Zsize[1]) ; while (j lt (Zsize[1]-1)) and (Xmax[j,k] ne Xmax[j,k]) do j=j+1; skip to next while (j lt (Zsize[1]-1)) and (finite(Xmax[j,k]) ne 1) do j=j+1; skip to next Xmax[w[i]] = Xmax[j,k] endfor ; i if not keyword_set(noSkipGaps) then begin ;#### only uses first row of Xmin; assumes no fill data, no log spacing ;### really have to do this for every column for i = 0L, Zsize[2]-1 do begin gaps = findGaps(Xmin[*,i], 1.5, avg=avgDeltaX) if (gaps[0] lt 0) then nGaps = 0 else nGaps = n_elements(gaps) if (nGaps gt 0) then for k = 0L, nGaps-1 do $ Xmax[gaps[k],i] = Xmin[gaps[k],i] + avgDeltaX endfor ; i endif ; noSkipGaps endelse if keyword_set(centerY) then begin Ymax = Ymin for i = 0L, Zsize[1]-1 do begin align_center, Ymin[i,*], Ymint, Ymaxt Ymin[i,*] = Ymint & Ymax[i,*] = Ymaxt endfor ; i endif else begin ; shift min up to max array and add top value ; Scheme for aligning lower left corner of box on (X, Y) position Ymax = shift(Ymin,0,-1) ; shift all elements in 2nd dim to the bottom ;print,transpose(ymax[1,*]),' ***' ;RCJ ; ####following assumes last 2 values in each row are real if logY then begin ;### Ymax[*,Zsize[2]-1]=alog10(10^(Ymin[*,Zsize[2]-1])*2 - 10^(Ymin[*,Zsize[2]-2])) Ymax[*,Zsize[2]-1]=10^(alog10(Ymin[*,Zsize[2]-1])*2 - alog10(Ymin[*,Zsize[2]-2])) ;print,transpose(ymax[1,*]) ;RCJ endif else begin Ymax[*,Zsize[2]-1] = Ymin[*,Zsize[2]-1]*2 - Ymin[*,Zsize[2]-2] endelse ; 2001 Mar 20 BC, new code for skipping NANs ; where Xmin has a real value and Xmax is NAN then set Xmax to next real Xmax up ; next real value may be much further up; ####do skipGaps to handle ; also does not have a value when NANs in last two positions? ; w = where((Ymax ne Ymax) and (Ymin eq Ymin), wc) w = where((finite(Ymax) ne 1) and finite(Ymin), wc) if (wc gt 0) then $ for i=0L,wc-1 do begin j = w[i] mod Zsize[1] k = long(w[i]/Zsize[1]) ; while (k lt (Zsize[2]-1)) and (Ymax[j,k] ne Ymax[j,k]) do k=k+1; skip to next while (k lt (Zsize[2]-1)) and (finite(Ymax[j,k]) ne 1) do k=k+1; skip to next Ymax[w[i]] = Ymax[j,k] endfor ; i if not keyword_set(noYSkipGaps) then begin ;#### only uses first col of Ymin; assumes no fill data, no log spacing ;### really have to do this for every column for i = 0L, Zsize[1]-1 do begin gaps = findGaps(Ymin[i,0], 1.5, avg=avgDeltaY) if (gaps[0] lt 0) then nGaps = 0 else nGaps = n_elements(gaps) if (nGaps gt 0) then for k = 0L, nGaps-1 do $ Ymax[i,gaps[k]] = Ymin[i,gaps[k]] + avgDeltaY endfor ; i endif ; noSkipGaps endelse ; if not keyword_set(center) then begin ; ; Scheme for aligning lower left corner of box on (X, Y) position ; ;Xmax = [X(1:*), X(nX-1)*2 - X(nX-2)] ; add deltaX to last item; 1 dim case ; Xmax = shift(Xmin,-1,0) ; shift all elements in 1st dim to the left ; Xmax(Zsize[1]-1,*) = Xmin(Zsize[1]-1,*)*2 - Xmin(Zsize[1]-2,*) ; Ymax = shift(Ymin,0,-1) ; shift all elements in 2nd dim to the bottom ; Ymax(*,Zsize[2]-1) = Ymin(*,Zsize[2]-1)*2 - Ymin(*,Zsize[2]-2) ; if not keyword_set(noSkipGaps) then begin ; ;#### only uses first row of Xmin; assumes no fill data ; gaps = findGaps(Xmin(*,0), 1.5, avg=avgDeltaX) ; if (gaps[0] lt 0) then nGaps = 0 else nGaps = n_elements(gaps) ; if (nGaps gt 0) then for k = 0L, nGaps-1 do $ ; Xmax(gaps(k),*) = Xmin(gaps(k),*) + avgDeltaX ; endif ; noSkipGaps ; endif else begin ; center box ; ;align_center, X, Xmin, Xmax ; 1 dim case ; Xmax = Xmin ; for i = 0L, Zsize[2]-1 do begin ; align_center, Xmin(*,i), Xmint, Xmaxt ; Xmin(*,i) = Xmint & Xmax(*,i) = Xmaxt ; endfor ; i ; Ymax = Ymin ; for i = 0L, Zsize[1]-1 do begin ; align_center, Ymin[i,*], Ymint, Ymaxt ; Ymin[i,*] = Ymint & Ymax[i,*] = Ymaxt ; endfor ; i ; endelse ; centering end ; Z, X, Y 5: begin ; Z, Xmin, Ymin, Xmax, Ymax X0 = 1.*reform(X0) & Y0 = 1.*reform(Y0) ; remove extraneous dimensions X1 = 1.*reform(X1) & Y1 = 1.*reform(Y1) ; remove extraneous dimensions Vsize = size(X0) if not ((Vsize[Vsize[0]+2] eq Zsize[1]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Xmin must be of same size as Z[*,0] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[1]) then Xmin = X0 else $ Xmin = rebin(X0,Zsize[1],Zsize[2],/sample) Vsize = size(Y0) if not ((Vsize[Vsize[0]+2] eq Zsize[2]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Ymin must be of same size as Z[0,*] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[2]) then Ymin = Y0 else $ Ymin = rebin(reform(Y0,1,Zsize[2],/overwrite),Zsize[1],Zsize[2],/sample) Vsize = size(X1) if not ((Vsize[Vsize[0]+2] eq Zsize[1]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Xmax must be of same size as Z[*,0] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[1]) then Xmax = X1 else $ Xmax = rebin(X1,Zsize[1],Zsize[2],/sample) Vsize = size(Y1) if not ((Vsize[Vsize[0]+2] eq Zsize[2]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Ymax must be of same size as Z[0,*] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[2]) then Ymax = Y1 else $ Ymax = rebin(reform(Y1,1,Zsize[2],/overwrite),Zsize[1],Zsize[2],/sample) end ; Z, Xmin, Ymin, Xmax, Ymax 7: begin ; Z, Xcenter, Ycenter, Xminus, Yminus, Xplus, Yplus X0 = 1.*reform(X0) & Y0 = 1.*reform(Y0) ; remove extraneous dimensions X1 = 1.*reform(X1) & Y1 = 1.*reform(Y1) ; remove extraneous dimensions X2 = 1.*reform(X2) & Y2 = 1.*reform(Y2) ; remove extraneous dimensions Vsize = size(X0) if not ((Vsize[Vsize[0]+2] eq Zsize[1]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Xcenter must be of same size as Z(*,0) or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[1]) then Xcenter = X0 else $ Xcenter = rebin(X0,Zsize[1],Zsize[2],/sample) Vsize = size(Y0) if not ((Vsize[Vsize[0]+2] eq Zsize[2]) or $ ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Ycenter must be of same size as Z[0,*] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[2]) then Ycenter = Y0 else $ Ycenter = rebin(reform(Y0,1,Zsize[2],/overwrite),Zsize[1],Zsize[2],/sample) Vsize = size(X1) if not ((Vsize[Vsize[0]+2] eq Zsize[1]) or $ (Vsize[Vsize[0]+2] eq 1) or $ ; allow scalar ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Xminus must be of same size as Z[*,0] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[1]) then Xminus = X1 else $ Xminus = rebin(X1,Zsize[1],Zsize[2],/sample) Vsize = size(Y1) if not ((Vsize[Vsize[0]+2] eq Zsize[2]) or $ (Vsize[Vsize[0]+2] eq 1) or $ ; allow scalar ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Yminus must be of same size as Z[0,*] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[2]) then Yminus = Y1 else $ Yminus = rebin(reform(Y1,1,Zsize[2],/overwrite),Zsize[1],Zsize[2],/sample) Vsize = size(X2) if not ((Vsize[Vsize[0]+2] eq Zsize[1]) or $ (Vsize[Vsize[0]+2] eq 1) or $ ; allow scalar ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Xplus must be of same size as Z[*,0] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[1]) then Xplus = X2 else $ Xplus = rebin(X2,Zsize[1],Zsize[2],/sample) Vsize = size(Y2) if not ((Vsize[Vsize[0]+2] eq Zsize[2]) or $ (Vsize[Vsize[0]+2] eq 1) or $ ; allow scalar ((Vsize[1] eq Zsize[1]) and (Vsize[2] eq Zsize[2]))) then begin msgText = 'Yplus must be of same size as Z[0,*] or Z[*,*]' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if not (Vsize[Vsize[0]+2] eq Zsize[2]) then Yplus = Y2 else $ Yplus = rebin(reform(Y2,1,Zsize[2],/overwrite),Zsize[1],Zsize[2],/sample) ; remember X/Yminus and X/Yplus can be scalar as well as 2-dim arrays Xmin = Xcenter - Xminus & Xmax = Xcenter + Xplus Ymin = Ycenter - Yminus & Ymax = Ycenter + Yplus end ; Z, Xcenter, Ycenter, Xminus, Yminus, Xplus, Yplus else: begin msgText = 'Wrong number of arguments' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText end ; else endcase ;##### remove "> 0." on next 30 lines for real Z < 0 ;if (n_elements(minValue) gt 0) then minZ = minValue[0] else minZ = min(Z,/nan) > 0. ;if (n_elements(maxValue) gt 0) then maxZ = maxValue[0] else maxZ = max(Z,/nan) > 0. if (n_elements(minValue) gt 0) then minZ = minValue[0] else minZ = min(Z,/nan) if (n_elements(maxValue) gt 0) then maxZ = maxValue[0] else maxZ = max(Z,/nan) if (n_elements(fillValue) gt 0) then begin fillZ = fillValue[0] wn = where(Z eq fillZ, wnc) if wnc gt 0 then Z[wn] = !values.d_nan ; set to NAN wn = where(finite(Z), wnc) ; find non-NANs including XfillVal's if (wnc gt 0) then begin if (n_elements(minValue) le 0) then minZ = min(Z[wn],/nan) if (n_elements(maxValue) le 0) then maxZ = max(Z[wn],/nan) endif ; RCJ 02/15/02 'minZ - 1' -> 'minZ - 1.' in case minZ is unsigned number. endif else fillZ = minZ - 1. ;isBad = (Z lt minZ) or (Z gt maxZ) or (Z eq fillZ) isBad = (Z lt minZ) or (Z gt maxZ) or (finite(Z) ne 1) wBad = where(isBad, wBadc) if (wBadc gt 0) then begin wGood = where(isBad ne 1, wGoodc) if (wGoodc le 0) then begin ; quit here msgText = 'No good values to display' if doStatus then begin ; RTB 11/96; check for ctitle first, BC 2001Mar7 if n_elements(ctitle) gt 0 then parts=str_sep(ctitle,'!C') else parts=[''] print,'ERROR= Instrument may be off ' print, 'STATUS= No good values to display for ',parts[0] ;status=-1L ;return if keyword_set(firstplot) then begin plot, [0,1], [0,1], ytype=logY, /nodata, _Extra=extra xyouts,(extra.position[2]-extra.position[0])/2,$ extra.position[1]+((extra.position[3]-extra.position[1])/2), $ 'No good values to display for '+parts[0],device=extra.device endif ; message, msgText, /info status = -1L & return endif else message, msgText endif ;if (n_elements(minValue) eq 0) then minZ=min(Z(wGood),/nan) > 0. ;if (n_elements(maxValue) eq 0) then maxZ=max(Z(wGood),/nan) > 0. if (n_elements(minValue) le 0) then minZ=min(Z[wGood],/nan) if (n_elements(maxValue) le 0) then maxZ=max(Z[wGood],/nan) ; RCJ 02/15/02 'minZ - 1' -> 'minZ - 1.' in case minZ is unsigned number. if (n_elements(fillValue) le 0) then fillZ = minZ - 1. endif doColorBar = 0 flipColorBar = 0 ; flip color bar if cScale is inverted if (n_elements(cscale) ne 0) then begin doColorBar = 1 ; check accuracy of cscale if n_elements(cscale) ne 2 then begin msgText = 'Error in cscale dimensions, no colorbar plotted' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif if logZ then begin ; check if cscale is less than 0 and minValue if (n_elements(minValue) ne 0) then minCscale = minValue[0] > 0 $ else minCscale = 0 wcs = where(cscale le minCscale, wcsc) if wcsc gt 0 then begin ws = where(Z gt minCscale, wsc) if wsc gt 0 then cscale[wcs] = min(Z[ws],/nan) else cscale[wcs] = minCscale endif ; bad cscale endif ; logZ doCheck = 0 if doCheck then begin ; check for exceeding maxValue or less than minValue if (n_elements(maxValue) ne 0) then begin wcs = where(cscale gt maxValue[0], wcsc) ; #### could be "ge" if wcsc gt 0 then begin ws = where(Z le maxValue[0], wsc) ; #### could be "lt" if wsc gt 0 then cscale[wcs] = max(Z[ws],/nan) else cscale[wcs] = maxValue[0] endif endif if (n_elements(minValue) ne 0) then begin wcs = where(cscale lt minValue[0], wcsc) ; #### could be "le" if wcsc gt 0 then begin ws = where(Z ge minValue[0], wsc) ; #### could be "gt" if wsc gt 0 then cscale[wcs] = min(Z[ws],/nan) else cscale[wcs] = minValue[0] endif endif endif ; doCheck min/max Values in cscale minZ = min(cscale) & maxZ = max(cscale) if (cscale[0] gt cscale[1]) then flipColorBar = 1 ; RCJ 02/15/02 'minZ - 1' -> 'minZ - 1.' in case minZ is unsigned number. if (n_elements(fillValue) le 0) then fillZ = minZ - 1. endif else begin; colorBar without cscale if keyword_set(colorbar) then begin doColorBar = 1 cscale = [minZ, maxZ] endif endelse ; RCJ 11/22/2013 Remove this. Testing showed that making linear scale did not work well for rbspa_efw-l2_fbk ;if (alog10(maxz)-alog10(minz)) lt 10 then begin ; logz=0 ; print,'WARNING: Logarithmic scale converted to linear because scale is too small.' ;endif minZ1 = minZ & maxZ1 = maxZ Ztemp = Z ;TJK following seems to be irrelevant, removed 9/30/99 ;if (Zsize(Zsize[0]+1) ne 1) then begin ; not Byte array if logZ then begin ;; ztype = size(z, /type) ; ;if integer or byte data then convert to float ;; ;so we don't loose precision. TJK 3/9/99, 9/30/99 (extended for byte) ;; if (ztype eq 1 or ztype eq 2 or ztype eq 12) then begin ;; Zt = float(Zt) & Z = Zt ;; endif wh = where((Ztemp le 0) or (finite(Ztemp) ne 1), wc) if (wc eq 0) then begin ;no 0's found in the data, convert whole array Ztemp = alog10(Ztemp) endif else begin ;some zero's found ; Zt = Z*0 ; all 0's ; wh = where(Z gt 0, wc) Ztemp[wh] = !values.d_nan ; set to NAN wh = where(finite(Ztemp), wc) if (wc gt 0) then Ztemp[wh] = alog10(Ztemp[wh]) endelse if (minZ le 0.) then minZ1 = 0. else minZ1 = alog10(minZ) if (maxZ le 0.) then maxZ1 = 0. else maxZ1 = alog10(maxZ) endif ;TJK port to IDL8.1 ;Zt = bytscl(Ztemp, min=minZ1, max=maxZ1, top=!d.n_colors-nResCol-1, /nan)+1B Zt = bytscl(Ztemp, min=minZ1, max=maxZ1, top=!d.table_size-nResCol-1, /nan)+1B ; reserve black and white at ends of colorscale ;TJK took out following line 9/30/99 ;endif if (wBadc gt 0) then Zt[wBad] = 0B ; minZ1 if (n_elements(deviceType) ne 0) then if (deviceType eq 2) then $ ; Zt = (!d.n_colors-1B) - Zt ; invert grayscale for Postscript Zt = (!d.color_table-1B) - Zt ; invert grayscale for Postscript ;if flipColorBar then Zt = (!d.n_colors-1B) - Zt ; invert for inverted cscale if flipColorBar then Zt = (!d.color_table-1B) - Zt ; invert for inverted cscale xmargin = !x.margin ;ymargin = !y.margin if doColorBar then if (!x.omargin[1]+!x.margin[1]) lt 14 then !x.margin[1] = 14 ;pPosition = !p.position ; save for later ;w = where(pPosition eq 0, wc) ;if (n_elements(position) ne 0) then positiont = position else $ ; if (wc ne 4) then positiont = pPosition else $ ; positiont = [0.1, 0.1, 0.88, 0.9] ;set up x- & y_ ranges to plot axis... Xminmax = [min([Xmin,Xmax], max=maxt,/nan), maxt] Yminmax = [min([Ymin,Ymax], max=maxt,/nan), maxt] ;Check for Y-fill values and screen prior to drawing axis... ;CGallap, 9/97, updated BC 2001Mar7 if n_elements(Xfillval) gt 0 then begin wn = where(Xmin eq Xfillval[0], wnc) if wnc gt 0 then Xmin[wn] = !values.d_nan ; set to NAN wn = where(finite(Xmin), wnc) ; find non-NANs including fillVal's if wnc le 0 then begin msgText = 'No valid Xmin data' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif ; wnc le 0 wx = where(Xmax eq Xfillval[0], wxc) if wxc gt 0 then Xmax[wx] = !values.d_nan ; set to NAN wx = where(finite(Xmax), wxc) ; find non-NANs including fillVal's if wxc le 0 then begin ; no valid Xmax data msgText = 'No valid Xmax data' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif ; wxc le 0 Xminmax = [min([Xmin[wn],Xmax[wx]], max=maxt,/nan), maxt] endif ; Xfillval if n_elements(Yfillval) gt 0 then begin wn = where(Ymin eq Yfillval[0], wnc) if wnc gt 0 then Ymin[wn] = !values.d_nan ; set to NAN wn = where(finite(Ymin), wnc) ; find non-NANs including fillVal's if wnc le 0 then begin ; no valid Ymin data msgText = 'No valid Ymin data' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif ; wnc le 0 wx = where(Ymax eq Yfillval[0], wxc) if wxc gt 0 then Ymax[wx] = !values.d_nan ; set to NAN wx = where(finite(Ymax), wxc) ; find non-NANs including fillVal's if wxc le 0 then begin ; no valid Ymax data msgText = 'No valid Ymax data' if doStatus then begin message, msgText, /info & status = -1L & return endif else message, msgText endif ; wxc le 0 Yminmax = [min([Ymin[wn],Ymax[wx]], max=maxt,/nan), maxt] endif ; Yfillval ;if keyword_set(Yfillval) then begin ; w = where(Ymin ne Yfillval, wc) ; y = where(Ymax ne Yfillval, yc) ; if (wc eq yc) then if (wc ne 0) then Yminmax[0] = min([Ymin[w], Ymax[y]],$ ; max=maxt) $ ; else Yminmax[0] = min([Ymin, Ymax], max=maxt) ;CAK Replaced lines above with lines below. ; wmin = where(Ymin ne Yfillval, i) & if (i eq 0) then wmin = [0] ; wmax = where(Ymax ne Yfillval, i) & if (i eq 0) then wmax = [0] ; Yminmax[0] = min([Ymin[wmin], Ymax[wmax]]) ;endif ; make any changes here also to plot command below polyfill ; rtb added 12/98 ;!p.charsize = 1.0 pmulti = !p.multi ; save so overwrite plot command will work ; if ymin has values < 0 then make logY=0 because shouldn't try to plot log of negative numbers: q=where(ymin lt 0) if (q[0] ne -1) then logY = 0 ; ; in order to have more tickmark labels when plotting in log scale, ; I removed the ytitle from the extra structure, then called loglevels ; (see further down) to create new tickmark labels. ; RCJ 09/19/00 <- at this date axlabel.pro was also called but in 08/2001 we added Bobby's ; modifications and removed the call to axlabel. ; check for extra.ytitle, BC 2001Mar7 ; removed section, BC 2001Aug9 ;TJK 8/16/2013 Make Y tickmarks point out so we can see then w/ dense data. !y.ticklen = -0.02 if logY and (n_elements(extra) gt 0) then begin extra_names = tag_names(extra) w = where(strupcase(extra_names) eq 'YTITLE', wc) if wc gt 0 then begin hold_ytitle=extra.(w[0]) extra.(w[0])=' ' plot, Xminmax, Yminmax, ytype=logY, /nodata, _Extra=extra, ytickformat='(A1)' endif else plot, Xminmax, Yminmax, ytype=logY, /nodata, _Extra=extra endif else plot, Xminmax, Yminmax, ytype=logY, /nodata, _Extra=extra if logY then crange = 10^!y.crange px=!x.window*!d.x_size py=!y.window*!d.y_size xWinsize=px[1]-px[0] yWinsize=py[1]-py[0] if keyword_set(quick) and ((!d.name eq 'X') or (!d.name eq 'Z') or $ (!d.name eq 'WIN') or (!d.name eq 'MAC') or (!d.name eq 'SUN')) then begin ; quick and dirty plotting tv,congrid(Zt,xWinsize,yWinsize),px[0],py[0] endif else begin skipX = 1L & avgDeltaX = 1 ; RCJ 11/02/2007 Changing this condition. It's causing data to disappear ; in gif plotting of tha_l2_sst data. ;if keyword_set(reduce) and not (!d.flags and 1L) then begin if keyword_set(reduce) then begin ; not scalable pixels (Postscript) gaps = findGaps(Xmin[*,0], 1.1, avg=avgDeltaX) ; #### uses only first row of Xmin and assumes no fill data in Xmin skipX = long((!x.crange[1]-!x.crange[0]) / avgDeltaX / xWinsize) $ ; -1? > 1L < (Zsize[1]/2) endif ; reduce if (n_elements(noclip) gt 0) then noclip = noclip[0] else noclip = 0 for i = 0L, Zsize[1]-1, skipX do begin for j = 0L, Zsize[2]-1 do begin doPixel = 1 ; plot all data (no maximum value limit or below limit) ;##### why not use minZ, maxZ? if (n_elements(maxValue) ne 0) then if (Z[i,j] gt maxValue[0]) then doPixel=0 if (n_elements(minValue) ne 0) then if (Z[i,j] lt minValue[0]) then doPixel=0 ;bc if (n_elements(fillValue) ne 0) then if (Z[i,j] eq fillZ) then doPixel=0 ;if (Ymin(i,j) lt 0) then doPixel=0 ;TJK changed 'le' to 'eq' 2/16/2001 if (n_elements(Yfillval) ne 0) then if (Ymin(i,j) le Yfillval) then doPixel=0 ;CAK change to below on 3/2/2001 if (n_elements(Yfillval) ne 0) then if (Ymin(i,j) eq Yfillval) then doPixel=0 ;CAK Added test against Ymax values equalling Yfillval. For at least the IM_k1_RPI data, fill data ; is occuring in different cells, so both the ymin and ymax array points must both be checked, otherwise ; fill data gets through and throws everything off... ; updated with [0] as well and added Xfillval, BC ; if (n_elements(Xfillval) gt 0) then doPixel = (Xmin[i,j] ne Xfillval[0] and Xmax[i,j] ne Xfillval[0]) ; if (n_elements(Yfillval) gt 0) then doPixel = (Ymin[i,j] ne Yfillval[0] and Ymax[i,j] ne Yfillval[0]) ;bc if (n_elements(Xfillval) gt 0) then $ ;bc if (Xmin[i,j] eq Xfillval[0]) or (Xmax[i,j] eq Xfillval[0]) then doPixel=0 ;bc if (n_elements(Yfillval) gt 0) then $ ;bc if (Ymin[i,j] eq Yfillval[0]) or (Ymax[i,j] eq Yfillval[0]) then doPixel=0 ; check for NAN values ; if (Z(i,j) ne Z(i,j)) or (Xmin[i,j] ne Xmin[i,j]) or (Xmax[i,j] ne Xmax[i,j]) or $ ; (Ymin[i,j] ne Ymin[i,j]) or (Ymax[i,j] ne Ymax[i,j]) then doPixel=0 ; ##### statement below may replace all checks above if (finite(Ztemp[i,j]) ne 1) or (finite(Xmin[i,j]) ne 1) or (finite(Xmax[i,j]) ne 1) or $ (finite(Ymin[i,j]) ne 1) or (finite(Ymax[i,j]) ne 1) then doPixel=0 if (doPixel) then begin ;don't assume that the y-axis starts with 0... x = [0,1,1,0] * ((Xmax[i,j]+(skipX-1L)*avgDeltaX) - Xmin[i,j]) + Xmin[i,j] y = [Ymin[i,j], Ymin[i,j], Ymax[i,j], Ymax[i,j]] polyfill, x, y, color = Zt[i,j], noclip=noclip ; #### problem when right on clip boundary? use noclip=1 for Z device endif endfor ; j endfor ; i endelse ; replot so the box gets put back over the filled area pmulti2 = !p.multi ; rtb added 12/98 ;!p.charsize=1.0 !p.multi = pmulti ; restore from before first plot command if logY then begin lblv=loglevels(crange) ; do not plot labels lt or gt crange. They tend to go over labels of other graphs. if (n_elements(lblv) ge 3) then begin ;TJK 6/27/2007 - check min being in the max position, which is legal ; and means the user wants the axis values from highest ; to lowest, etc. if (crange[0] lt crange[1]) then begin if lblv[0] lt crange[0] then lblv=lblv[1:*] if lblv[n_elements(lblv)-1] gt crange[1] then lblv=lblv[0:n_elements(lblv)-2] endif else begin ; crange values have been deliberately switched to plot the data upsidedown if lblv[0] gt crange[0] then lblv=lblv[1:*] if lblv[n_elements(lblv)-1] lt crange[1] then lblv=lblv[0:n_elements(lblv)-2] endelse endif extra.ytitle=hold_ytitle !y.ticklen = -0.02 plot,Xminmax, Yminmax, _Extra=extra, ytype=logY, /nodata, /noerase,$ yticks=n_elements(lblv)-1,ytickv=lblv ; don't want yticks to be 0 or 1 yticks=n_elements(lblv)-1,ytickv=lblv ; lblv=loglevels(Yminmax) <- this is not correct! We really want crange so we are still within ; specified validmin/max. RCJ ; RCJ. Ugly hack: ; if n_elements(lblv) ge 3 then begin ; ; try to delete labels that are overlaping with labels from other graphs. RCJ 11/00 ;; if lblv[0] le yminmax[0] then lblv=lblv[1:*] ; if lblv[0] lt crange[0] then lblv=lblv[1:*] ;; if yminmax[1] lt $ ;; (lblv(n_elements(lblv)-1)+(lblv(n_elements(lblv)-1)-lblv(n_elements(lblv)-2))/2) then $ ; if crange[1] lt $ ; (lblv(n_elements(lblv)-1)+(lblv(n_elements(lblv)-1)-lblv(n_elements(lblv)-2))/2) then $ ; lblv=lblv[0:n_elements(lblv)-2] ; endif ; if max(yminmax) ge 1000000 then fmt='(e7.0)' else fmt='(f7.0)' ; axlabel,lblv,format=fmt ; BC 2001Mar7 call plotlabel ; if (n_elements(extra.position) gt 0) and (n_elements(extra.device) gt 0) then begin ; xyouts,extra.position[0]-60,extra.position[1]+50,hold_ytitle,device=extra.device, $ ; charsize=extra.charsize, orientation=90, alignment=0.5 ; endif else plotlabel, hold_ytitle, /yaxis ;;;;;if n_elements(hold_ytitle) gt 0 then plotlabel, hold_ytitle, yaxis=0 ; plotlabel, ytitle, yaxis=0 endif else begin !y.ticklen = -0.02 plot,Xminmax, Yminmax, _Extra=extra, ytype=logY, /nodata, /noerase endelse !p.multi = pmulti2 ; restore from after first plot command !y.ticklen = 0.0 ; reset RCJ 10/24/2013 if doColorBar then begin if (n_elements(ctitle) le 0) then ctitle = '' if (n_elements(cCharSize) le 0) then cCharSize = 0. xwindow = !x.window offset = 0.01 colorbar, cscale, ctitle, logZ=logZ, cCharSize=cCharSize, nResCol=nResCol, $ position=[!x.window[1]+offset, !y.window[0],$ !x.window[1]+offset+0.03, !y.window[1]] !x.window = xwindow endif ; colorbar ;!p.Position = pPosition ; restore !x.margin = xmargin ;!y.margin = ymargin ; mask valid for idl5.3 but we run 5.2 on the web and this keyword is not allowed yet. RCJ ;c=check_math(mask=128) ; clear illegal floating point operand errors from where statements c=check_math() ; clear illegal floating point operand errors from where statements return end ; spectrogram