;+ ; NAME: ; GRIDPOSITIONS ; ; PURPOSE: ; ; Sets up a column-row grid in the current graphics window in a fashion ; similar to !P.MULTI, except that the grid can be confined to a portion ; of the window, leaving room for color bars and other annotations. ; ; AUTHOR: ; ; FANNING SOFTWARE CONSULTING ; David Fanning, Ph.D. ; 1645 Sheely Drive ; Fort Collins, CO 80526 USA ; Phone: 970-221-0438 ; E-mail: david@idlcoyote.com ; Coyote's Guide to IDL Programming: http://www.idlcoyote.com ; ; CATEGORY: ; Graphics ; ; CALLING SEQUENCE: ; ; positions = GridPositions(columns, rows) ; ; INPUT_PARAMETERS: ; ; columns: The number of columns in the grid. ; ; rows The number of rows in the grid. ; ; OUTPUT_PARAMETERS: ; ; positions: A 4xN array, where N=(columns*rows), giving the positions of the grid in ; normalized coordinates. ; ; KEYWORDS: ; ; INCHES: If calculating the position in the PostScript device, indicates whether ; the window size is given in centimeters (the default) or in inches. Set ; this keyword to 1 to indicate inches. Ignored for other devices. ; ; LANDSCAPE: If calculating the position in the PostScript device, set this keyword to ; indicate a landscript page. Ignored for other devices. ; ; ORDER: If this keyword is set to 0, the positions are calculated in row order. If ; set to 1, the positions are calculated in column order. ; ; PS_KEYWORDS: Rather than specifying individual PostScript keywords (e.g., XSIZE, YSIZE, ; LANDSCAPE, etc), it is much easier to pass a structure of PostScript keywords ; as collected by PSConfig or PS_Start. This keyword allows you to pass such ; a structure of PostScript keywords. For example, like this: ; ; PS_Start, 'myfile.ps', Keywords=keywordStruct ; positions = GridPositions(PS_Keywords=keywordStruct) ; ; XEXTENT: A one or two element array, with values from 0 to 1, giving the extent of ; the grid in the X direction. For example XEXTENT=[.2, .8] will position ; the X portion of the grid from 0.2 to 0.8 (normalized coordinates) in the ; window. If a scalar value, the XEXTENT will be assumed to be [0, value]. ; ; XMARGIN: A one or two element array, giving the plot margin outside the grid position. ; That is to say, the normal grid position will be reduced by this margin. This ; corresponds to a plot margin, and as such is expressed in character units. See ; the on-line help for graphics keywords for additional information. If a scalar, ; the margin is taken from both the left and right sides of the position. In other ; words, XMARGIN=[value, value]. By default, [0.05,0.05], which will cause grid ; positions to have just a bit of space between them. ; ; XSIZE: The X size of the window the positions are being calculated for. By ; default, !D.X_SIZE. ; ; XEXTENT: A one or two element array, with values from 0 to 1, giving the extent of ; the grid in the X direction. For example XEXTENT=[.2, .8] will position ; the X portion of the grid from 0.2 to 0.8 (normalized coordinates) in the ; window. If a scalar value, the XEXTENT will be assumed to be [0, value]. ; ; XMARGIN: A one or two element array, giving the plot margin outside the grid position. ; That is to say, the normal grid position will be reduced by this margin. This ; corresponds to a plot margin, and as such is expressed in character units. See ; the on-line help for graphics keywords for additional information. If a scalar, ; the margin is taken from both the left and right sides of the position. In other ; words, XMARGIN=[value, value]. By default, [0,0], which will cause grid ; positions to abut one another. ; ; XSIZE: The X size of the window the positions are being calculated for. By ; default, !D.X_SIZE. ; ; YEXTENT: A one or two element array, with values from 0 to 1, giving the extent of ; the grid in the X direction. For example YEXTENT=[.2, .8] will position ; the Y portion of the grid from 0.2 to 0.8 (normalized coordinates) in the ; window. If a scalar value, the YEXTENT will be assumed to be [0, value]. ; ; YMARGIN: A one or two element array, giving the plot margin outside the grid position. ; That is to say, the normal grid position will be reduced by this margin. This ; corresponds to a plot margin, and as such is expressed in character units. See ; the on-line help for graphics keywords for additional information. If a scalar, ; the margin is taken from both the bottom and top sides of the position. In other ; words, YMARGIN=[value, value]. By default, [0,0], which will cause grid ; positions to abut one another. ; ; YSIZE: The Y size of the window the positions are being calculated for. By ; default, !D.Y_SIZE. ; ; EXAMPLE: ; ; To display four images, scaled differently, in the center of the display, with room ; for a color bar: ; ; positions = GridPositions(2, 2, YEXTENT=[0.15,0.85], XEXTENT=[0.2,0.8]) ; image = cgDemoData(11) ; cgErase, 'rose' ; cgLoadCt, 25, /Brewer ; cgImage, image, POSITION=positions[*,0] ; cgImage, BytScl(Sobel(image)), POSITION=positions[*,1], /NoErase ; cgImage, BytScl(Hist_Equal(image)), POSITION=positions[*,2], /NoErase ; cgImage, BytScl(Median(image,7)), POSITION=positions[*,3], /NoErase ; ; To do the same thing in a PostScript file: ; ; PS_Start, 'test.ps', Keywords=psStruct ; positions = GridPositions(2, 2, YEXTENT=[0.15,0.85], $ ; XEXTENT=[0.2,0.8], PS_KEYWORDS=psStruct) ; image = cgDemoData(11) ; cgErase, 'rose' ; cgLoadCt, 25, /Brewer ; cgImage, image, POSITION=positions[*,0] ; cgImage, BytScl(Sobel(image)), POSITION=positions[*,1], /NoErase ; cgImage, BytScl(Hist_Equal(image)), POSITION=positions[*,2], /NoErase ; cgImage, BytScl(Median(image,7)), POSITION=positions[*,3], /NoErase ; PS_End ; /PNG, WIDTH=600 ; ; MODIFICATION HISTORY: ; ; Written by David W. Fanning, 17 March 2009. ; Fixed problems in calculating default window sizes in the Z and PS devices. 25 June 2011. DWF. ; Fixed the example code to work with Coyote Graphics routines. 27 June 2011. ; Although GridPositions was not intended to be used to configure the PostScript ; device, I find that people are using it to do just that. To that end, I am now ; allowing PostScript device keywords to be collected and passed along to the ; PostScript device through the GridPositions interface. This is strictly a ; convenience, and not the way I would recommend using the program, to be truthful. ; 29 Aug 2011. DWF ; Added PS_Keywords keyword to allow use of PSConfig and PS_Start with the program. 24 Apr 2012. DWF. ;- ;******************************************************************************************; ; Copyright (c) 2009, by Fanning Software Consulting, Inc. ; ; All rights reserved. ; ; ; ; Redistribution and use in source and binary forms, with or without ; ; modification, are permitted provided that the following conditions are met: ; ; ; ; * Redistributions of source code must retain the above copyright ; ; notice, this list of conditions and the following disclaimer. ; ; * Redistributions in binary form must reproduce the above copyright ; ; notice, this list of conditions and the following disclaimer in the ; ; documentation and/or other materials provided with the distribution. ; ; * Neither the name of Fanning Software Consulting, Inc. nor the names of its ; ; contributors may be used to endorse or promote products derived from this ; ; software without specific prior written permission. ; ; ; ; THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY ; ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ; ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT ; ; SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ; ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ; ; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ; ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ; ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ;******************************************************************************************; Function GridPositions, columns, rows, $ INCHES=inches, $ LANDSCAPE=landscape, $ ORDER=order, $ PS_Keywords=ps_keywords, $ XEXTENT=xextent, $ XMARGIN=xmargin, $ XSIZE=xsize, $ YEXTENT=yextent, $ YMARGIN=ymargin, $ YSIZE=ysize, $ _EXTRA=extra Compile_Opt idl2 ; Return to caller with an error. On_Error, 2 ; Check positional and keyword parameters. inches = Keyword_Set(inches) landscape = Keyword_Set(landscape) order = Keyword_Set(order) IF N_Elements(xsize) EQ 0 THEN BEGIN CASE !D.NAME OF 'PS': BEGIN CASE inches OF 0: xsize = !D.X_Size / Float(!D.X_PX_CM) 1: xsize = !D.X_Size / Float(!D.X_PX_CM) / 2.54 ENDCASE END 'Z': xsize = 640 ELSE: xsize = !D.X_Size ENDCASE ENDIF IF N_Elements(ysize) EQ 0 THEN BEGIN CASE !D.NAME OF 'PS': BEGIN CASE inches OF 0: ysize = !D.Y_Size / Float(!D.Y_PX_CM) 1: ysize = !D.Y_Size / Float(!D.Y_PX_CM) / 2.54 ENDCASE END 'Z': ysize = 512 ELSE: ysize = !D.Y_Size ENDCASE ENDIF IF N_Elements(xextent) EQ 0 THEN xextent = [0.0, 1.0] IF N_Elements(xextent) EQ 1 THEN xextent = [0, xextent] xextent = 0.0 > xextent < 1.0 IF N_Elements(yextent) EQ 0 THEN yextent = [0.0, 1.0] IF N_Elements(yextent) EQ 1 THEN yextent = [0, yextent] yextent = 0.0 > yextent < 1.0 IF N_Elements(columns) EQ 0 THEN columns = 2 IF N_Elements(rows) EQ 0 THEN rows = 2 IF N_Elements(xmargin) EQ 0 THEN xmargin = [0,0] IF N_Elements(xmargin) EQ 0 THEN xmargin = [xmargin, xmargin] IF N_Elements(ymargin) EQ 0 THEN ymargin = [0,0] IF N_Elements(ymargin) EQ 0 THEN ymargin = [ymargin, ymargin] ; Calculate window size. xs = xsize * (xextent[1] - xextent[0]) ys = ysize * (yextent[1] - yextent[0]) IF xs LE 0.0 THEN Message, 'X Extent results in a size of 0 length.' IF ys LE 0.0 THEN Message, 'Y Extent results in a size of 0 length.' ; Set up appropriately for the right device. CASE !D.NAME OF 'PS': BEGIN Print, 'Resolution: ', [xs,ys] Device, XSIZE=xs, YSIZE=ys, INCHES=inches, PORTRAIT=1-landscape, $ LANDSCAPE=landscape, _Extra=ps_keywords END 'Z': BEGIN Device, SET_RESOLUTION=[xs, ys] END ELSE: BEGIN thisWindow = !D.Window Window, /FREE, /PIXMAP, XSIZE=xs, YSIZE=ys END ENDCASE numpos = columns*rows thePositions = FltArr(4, numpos) !P.MULTI = [0, columns, rows, 0, order] FOR j=0,numpos-1 DO BEGIN Plot, Findgen(11), XStyle=4, YStyle=4, /NoData, XMargin=xmargin, YMargin=ymargin thePositions[*,j] = [!X.Window[0], !Y.Window[0], !X.Window[1], !Y.Window[1]] ENDFOR !P.MULTI =0 thePositions[[0,2], *] = thePositions[[0,2], *] * (xextent[1] - xextent[0]) + xextent[0] thePositions[[1,3], *] = thePositions[[1,3], *] * (yextent[1] - yextent[0]) + yextent[0] ; Clean up CASE !D.NAME OF 'PS': 'Z': ELSE: BEGIN WDelete, !D.Window IF thisWindow NE -1 THEN WSet, thisWindow END ENDCASE RETURN, thePositions END