; docformat = 'rst' ; ; NAME: ; cgWindRose ; ; PURPOSE: ; This program draws a wind rose diagram. ; ;******************************************************************************************; ; ; ; Copyright (c) 2013, 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. ; ;******************************************************************************************; ; ;+ ; This program draws a wind rose diagram. A wind rose diagram shows the frequency, speed, and ; direction of winds over some defined period of time. It is widely used in meteorological ; applications (`see here: `). ; ; Data to test the program (in SAMPSON formatted data files) can be freely downloaded from ; the `Meteorological Resource Center `. ; ; Changes made to the program in Oct 2014 allow multiple windrose plots to be placed in ; a graphics window, but with a few reservations. Windrose plots normally have an aspect ; ratio of 1 (i.e., they are square). Unfortunately, this cannot be guaranteed if you use ; !P.Multi to create multiple plots. Therefore, it is recommened that you use cgLayout to ; obtain a multi-plot layout for multiple windrose plots, and give each plot a specific ; position in the graphics window with the `Position` keyword. ; ; :Categories: ; Graphics ; ; :Examples: ; An example of how to use the program can be found in the ; `Coyote Plot Gallery `. ; ; .. image:: cgwindrose.png ; ; To display multiple plots in the window, set the positions with `cgLayout`, like this:: ; ; pos = cgLayout([2,1], OXMargin=[5,5], OYMargin=[8, 5], XGap=10) ; cgDisplay, 900, 550 ; cgWindRose, SamFile='93058_90.sam', Position=pos[*,0], Title='Plot 1', /NoLegend ; cgWindRose, SamFile='94018_90.sam', Position=pos[*,1], Title='Plot 2', LegendPosition=[0.44, 0.325], /NoErase ; ; .. image:: cgwindrosetwo.png ; ; :Author: ; FANNING SOFTWARE CONSULTING:: ; David W. Fanning ; 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 ; ; :History: ; Change History:: ; Written, 7 March 2013 by David W. Fanning. ; Fixed error in which I was assuming some calm winds. 23 May 2013. DWF. ; Added LegendPosition, Position, CircleLabelSize, and NoLegend keywords and made changes ; that allow multiple windrose plots to be place in a graphics window. To better ; accommodate multiple plots, the cardinal directions are now indicated with a ; single letter and the default circle label font size is reduced. 22 Oct 2014. DWF. ; Fixed a couple of hardcoded number problems when using your own speed and direction vectors. 20 June 2015. DWF. ; Added an OUTPUT keyword so that the windrose output can be sent directly to an output file. 1 July 2016. DWF. ; ; :Copyright: ; Copyright (c) 2013-2016, Fanning Software Consulting, Inc. ;- ;+ ; This function returns 100 x and y points as a 2x100 array that forms an arc between two angles ; when plotted. The arc is created as if the 0 angle was to the North (top on drawings). ; ; :Params: ; xcenter: in, required ; The X center of the arc. ; ycenter: in, required ; The Y center of the arc. ; radius: in, required ; The radius of the desired arc. ; angle1: in, optional, type=float, default=0.0 ; The first angle. The arc is drawn between the first angle and the second angle. ; angle2: in, optional, type=float, default=360.0 ; The second angle. The arc is drawn between the first angle and the second angle. ;- FUNCTION cgWindRoseArc, xcenter, ycenter, radius, angle1, angle2 ; Return to caller on an error. On_Error, 2 ; Need angles? IF N_Elements(angle1) EQ 0 THEN angle1 = 0.0 IF N_Elements(angle2) EQ 0 THEN angle2 = 360.0 ; Scale 100 points between the first and second angle. points = cgScaleVector(Findgen(100), angle1, angle2) ; Calculate the X and Y values of these points. Do this so ; that the zero angle is North, not East as is normal in ; most IDL coordinate systems. x = xcenter + radius * Sin(points * !DtoR ) y = ycenter + radius * Cos(points * !DtoR) ; Return a 2-column array. X values are in the first column and Y values are in the second column. RETURN, Transpose([[x],[y]]) END ;+ ; This is a tick labeling function that prevents negative tick values. ; It also labels all tick values as precentages. Set this function as ; the name of either the XTickFormat or YTickFormat keyword on a Plot or ; Axis command. This is not called directly by a user. ; ; :Params: ; axis: in, required, type=integer ; The type of axis. 0 is X, 1 is Y, etc. ; index: in, required, type=integer ; The index of the tick label. ; value: in, required ; The tick value to be transformed by the function. ;- FUNCTION cgWindRose_PositiveLabel, axis, index, value IF value LT 0 THEN value = Abs(value) RETURN, String(value, Format='(F0.1)') + '%' END ;+ ; Read a SAMSON format meteorological data file to obtain the wind ; speed and direction arrays. ; ; :Params: ; filename: in, optional, type=string ; The path to a SAMSON (*.sam) format meteorological data file from which wind speed and wind ; direction can be obtained. ; ; :Keywords: ; speed: out, optional, type=float ; The wind speed as obtained from the file. ; direction: out, optional, type=float ; The direction of the wind as obtained from the file. ; ;- PRO cgWindRose_ReadSamFile, filename, SPEED=speed, DIRECTION=direction Compile_Opt idl2 ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() RETURN ENDIF ; Open the SAMSON format file and obtain the wind speed and direction values. OpenR, lun, filename, /Get_Lun header = StrArr(2) lines = File_Lines(filename) - 2 format = '(76x,I3,x,f0.1)' direction = IntArr(lines) speed = FltArr(lines) d=0 s = 0.0 ReadF, lun, header FOR j=0,lines-1 DO BEGIN ReadF, lun, d, s, Format=format direction[j] = d speed[j] = s ENDFOR Free_Lun, lun ; Find any missing data in the direction and speed arrays. missingIndices = Where((direction NE 999) AND (speed NE 999.0), missingCnt) IF missingCnt GT 0 THEN BEGIN direction = direction[missingIndices] speed = speed[missingIndices] ENDIF ; Make sure the direction array is a float. direction = Temporary(Float(direction)) END ;+ ; Draw a wind rose diagram from the input wind speed and wind direction parameters. ; The wind rose diagram treats a 0 angle as pointing to the North, or toward the top ; of the diagram. Note this is different from normal IDL coordinate systems, which treat the ; 0 angle as pointing to the right of the diagram or plot. ; ; :Params: ; ; speed: in, required, type=float ; The wind speed array. Note that missing values should be removed prior to passing the ; speed array to the program. This vector should have the same number of elements as the ; `direction` array. It is assumed there are no negative speed values in the array. Winds ; assumed to be measured in meters/second. ; direction: in, required, type=float ; The direction of the wind. This should have the same number of elements as the `speed` array. ; The wind directions are assumed to be in the range 0 to 360. ; ; :Keywords: ; calmsfreq: out, optional, type=float ; The frequency of calms measurements in the data. (Winds less than 1 meter/second.) ; circlelabelsize: in, optional, type=float, default=0.6 ; A multiplier of the default character size, used for labelling the circle percents. ; legendposition: in, optional, type=float ; A two-element array giving the X and Y position of the top-left corner of the legend box ; in normalized coordinates. By default, to the southwest of the windrose plot. Depending on ; window size, etc., the legend may not be visible or may be only partially visible. Adjust ; either the size of the window or the location of the legend for improved visibility. ; nolegend: in, optional, type=boolean, default=0 ; Set this keyword to prevent the windrose legend from being drawn with the windrose plot.; ; output: in, optional, type=string, default="" ; Set this keyword to the type of output desired. Possible values are these:: ; ; 'PS' - PostScript file ; 'EPS' - Encapsulated PostScript file ; 'PDF' - PDF file ; 'BMP' - BMP raster file ; 'GIF' - GIF raster file ; 'JPEG' - JPEG raster file ; 'PNG' - PNG raster file ; 'TIFF' - TIFF raster file ; ; Or, you can simply set this keyword to the name of the output file, and the type of ; file desired will be determined by the file extension. If you use this option, the ; user will not be prompted to supply the name of the output file. ; ; All raster file output is created through PostScript intermediate files (the ; PostScript files will be deleted), so ImageMagick and Ghostview MUST be installed ; to produce anything other than PostScript output. (See cgPS2PDF and cgPS_Close for ; details.) And also note that you should NOT use this keyword when doing multiple ; plots. The keyword is to be used as a convenient way to get PostScript or raster ; output for a single graphics command. Output parameters can be set with cgWindow_SetDefs. ; position: in, optional, type=float ; The usual four-element POSITION keyword giving the plot position of the windrose plot in ; normalized coordinates. ; samfile: in, optional, type=string ; The path to a SAMSON (*.sam) format meteorological data file from which wind speed and wind ; direction can be obtained. ; speedbinsize:, in, optional, type=float, default=3 ; The size of the bin when the speed is binned with the Histogram command. ; title: in, optional, type=string, default="" ; The plot title. Not displayed if a null string. ;- PRO cgWindRose, speed, direction, $ CALMSFREQ=calmsFreq, $ CIRCLELABELSIZE=circlelablesize, $ LEGENDPOSITION=legendposition, $ NOLEGEND=nolegend, $ OUTPUT=output, $ POSITION=position, $ SAMFILE=samFile, $ SPEEDBINSIZE=speedBinSize, $ TITLE=title, $ _EXTRA=extra Compile_Opt idl2 ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() IF (N_Elements(output) NE 0) THEN cgPS_Close, /NOFIX RETURN ENDIF ; We need speed and direction arrays. If we don't have them, maybe we have the ; name of a SAMPSON file that we can read to obtain these arrays. IF N_Params() NE 2 THEN BEGIN ; Do we have a SAMSON file? If not, ask the user to choose one. If that ; proves fruitless, then jump ship. SAMSON meteorological data files can be obtained for ; free here: http://www.webmet.com/State_pages/met_co.htm#samson. IF N_Elements(samFile) EQ 0 THEN BEGIN samFile = cgPickfile(Filter='*.sam', Title='Select a Meteorological SAMSON File...') IF samFile EQ "" THEN RETURN ENDIF ; Open the SAM file. It should be easy to add your own file reader to this program! cgWindRose_ReadSamFile, samFile, SPEED=speed, DIRECTION=direction ENDIF ; Do we have both speed and direction arrays? IF (N_Elements(speed) EQ 0) || (N_Elements(direction) EQ 0) THEN BEGIN Print, 'Calling Syntax: cgWindRose, speed, direction' RETURN ENDIF ; Set keyword default values. SetDefaultValue, circleLabelSize, 0.6 nolegend = Keyword_Set(nolegend) SetDefaultValue, speedBinSize, 3.0 SetDefaultValue, title, "" IF Total(!P.Multi) EQ 0 THEN BEGIN IF title EQ "" THEN BEGIN SetDefaultValue, position, [0.15, 0.15, 0.85, 0.85] ENDIF ELSE BEGIN SetDefaultValue, position, [0.15, 0.125, 0.85, 0.825] ENDELSE ENDIF ; Are these arrays the same size? IF N_Elements(speed) NE N_Elements(direction) THEN $ Message, 'Speed and Direction arrays must be the same size.' ; Make sure direction values of 360 are treated as 0. direction = direction MOD 360. ; How many elements of speed. Need to calculate frequency. speedCount = N_Elements(speed) ; How many calm measurements are there with winds less than 1.0. calms = Where(speed LT 1.0, count, Complement=winds) calmsFreq = count/Float(speedCount)*100 ; Remove the calms data from the data set. IF count GT 0 THEN BEGIN speed_final = speed[winds] direction_final = direction[winds] ENDIF ELSE BEGIN speed_final = speed direction_final = direction ENDELSE maxSpeed = Round(Max(speed)/10.)*10 IF maxSpeed EQ 0 THEN maxSpeed = Ceil(Max(speed)) ;maxSpeed = Ceil(Max(speed)) ; Compute the 2D matrix for speed and direction. matrix = Hist_ND(Transpose([[speed_final],[direction_final]]), [speedBinSize, 22.5], $ MIN=[1.0, -11.25], MAX=[maxSpeed, 360]) ; Combine the first and last direction bins and trim the matrix. s = Size(matrix, /Dimensions) matrix[*,0] = matrix[*,0] + matrix[*,s[1]-1] matrix = matrix[*,0:s[1]-2] ; Calculate the maximum frequency to plot. frequency = total(matrix,1)/N_Elements(speed_final)*100 maxFreq = Round(Max(frequency*1.1)*10)/10 IF maxFreq MOD 2 NE 0 THEN maxFreq = maxFreq + 1 ;Print, 'Maximum Frequency: ', maxFreq ; Open a display window, if needed IF Total(!P.Multi) GT 0 THEN BEGIN win_xsize = 400 * (!P.Multi[1] < 3) win_ysize = 400 * (!P.Multi[2] < 3) ENDIF ELSE BEGIN win_xsize = 700 win_ysize = 500 ENDELSE IF !D.Window LT 0 THEN cgDisplay, win_xsize, win_ysize ; Are we doing some kind of output? IF (N_Elements(output) NE 0) && (output NE "") THEN BEGIN ; If the output string has a dot character, then this must be a ; filename, and we will determine the type of file from the filename extension. IF StrPos(output, '.') NE -1 THEN BEGIN root_name = cgRootName(output, DIRECTORY=theDir, EXTENSION=ext) IF theDir EQ "" THEN CD, CURRENT=theDir outfilename = output outputSelection = StrUpCase(ext) ENDIF IF N_Elements(outputSelection) EQ 0 THEN outputSelection = StrUpCase(output) typeOfOutput = ['PS','EPS','PDF','BMP','GIF','JPEG','JPG','PNG','TIFF', 'TIF'] void = Where(typeOfOutput EQ outputSelection, count) IF count EQ 0 THEN Message, 'Cannot find ' + outputSelection + ' in allowed output types.' ; Set things up. CASE outputSelection OF 'PS': BEGIN ext = '.ps' delete_ps = 0 END 'EPS': BEGIN ext = '.eps' encapsulated = 1 delete_ps = 0 END 'PDF': BEGIN ext = '.pdf' pdf_flag = 1 delete_ps = 1 END 'BMP': BEGIN ext = '.bmp' bmp_flag = 1 delete_ps = 1 END 'GIF': BEGIN ext = '.gif' gif_flag = 1 delete_ps = 1 END 'JPEG': BEGIN ext = '.jpg' jpeg_flag = 1 delete_ps = 1 END 'JPG': BEGIN ext = '.jpg' jpeg_flag = 1 delete_ps = 1 END 'PNG': BEGIN ext = '.png' png_flag = 1 delete_ps = 1 END 'TIFF': BEGIN ext = '.tif' tiff_flag = 1 delete_ps = 1 END 'TIF': BEGIN ext = '.tif' tiff_flag = 1 delete_ps = 1 END ENDCASE ; Do you need a filename? IF ( (N_Elements(outfilename) EQ 0) || (outfilename EQ "") ) THEN BEGIN filename = 'cgplot' + ext outfilename = cgPickfile(FILE=filename, TITLE='Select Output File Name...', $ FILTER=ext, /WRITE) IF outfilename EQ "" THEN RETURN ENDIF ; We need to know the root name of the file, because we have to make a PostScript ; file of the same name. At least we do if the type is not PS or EPS. IF (outputSelection NE 'PS') && (outputSelection NE 'EPS') THEN BEGIN root_name = cgRootName(outfilename, DIRECTORY=theDir) IF theDir EQ "" THEN CD, CURRENT=theDir ps_filename = Filepath(ROOT_DIR=theDir, root_name + '.ps') ENDIF ELSE ps_filename = outfilename ; Get the output default values. cgWindow_GetDefs, $ PS_Charsize = ps_charsize, $ ; The PostScript character size. PS_FONT = ps_font, $ ; Select the font for PostScript output. PS_Decomposed = ps_decomposed, $ ; Sets the PostScript color mode. PS_Delete = ps_delete, $ ; Delete PS file when making IM raster. PS_Metric = ps_metric, $ ; Select metric measurements in PostScript output. PS_Scale_factor = ps_scale_factor, $ ; Select the scale factor for PostScript output. PS_TT_Font = ps_tt_font ; Select the true-type font to use for PostScript output. ; Set up the PostScript device. cgPS_Open, $ CHARSIZE=ps_charsize, $ DECOMPOSED=ps_decomposed, $ FILENAME=ps_filename, $ FONT=ps_font , $ ENCAPSULATED=encapsulated, $ METRIC=ps_metric, $ SCALE_FACTOR=ps_scale_factor, $ TT_FONT=ps_tt_font, $ QUIET=1 ENDIF ; Set up the data coordinate system. Nothing shown here. cgPlot, [-maxFreq, maxFreq],[-maxFreq, maxFreq], /NoData, $ ASPECT=1.0, XStyle=5, YStyle=5, Position=position, _STRICT_EXTRA=extra ; Draw four circles, last at maxFreq. radii = (Indgen(4)+1) *(maxFreq/4.0) FOR j=0,3 DO BEGIN pts = cgWindroseArc(0, 0, radii[j]) cgPlotS, pts, Linestyle=2 ENDFOR ; Create a blank space for writing axis labels. cgColorFill, [-maxFreq,-maxFreq, maxFreq, maxFreq, -maxFreq], [0,2.0,2.0,0,0],Color='white' ; Draw a vertical N-S line. cgPlots, [0,0], !Y.CRange, LineStyle=2 ; Draw a horizontal E-W axis. cgAxis, 0, 0, /XAxis, XTickformat='cgWindRose_PositiveLabel', $ XTicks=8, XRange=[-maxFreq, maxFreq], XStyle=1, Charsize=cgDefCharSize()*circleLabelSize ; Label the cardinal directions. xfudge = (!D.X_CH_SIZE * 3.5) / !D.X_Size yfudge = (!D.Y_CH_SIZE * 1.5) / !D.Y_Size cgText, !X.Window[0] - xfudge, (!Y.Window[1] - !Y.Window[0]) / 2.0 + !Y.Window[0], 'W', Alignment=1.0, /Normal cgText, !X.Window[1] + xfudge, (!Y.Window[1] - !Y.Window[0]) / 2.0 + !Y.Window[0], 'E', Alignment=0.0, /Normal cgText, (!X.Window[1] - !X.Window[0]) / 2.0 + !X.Window[0], !Y.Window[1] + yfudge, 'N', Alignment=0.5, /Normal cgText, (!X.Window[1] - !X.Window[0]) / 2.0 + !X.Window[0], !Y.Window[0] - (yfudge*1.75), 'S', Alignment=0.5, /Normal ; Draw the wind triangles. angles = (Indgen(16)*22.5) colors = Bindgen(s[0]) cgLoadCT, 1, /Brewer, NColors=s[0], Clip=[30, 250] FOR j=0,15 DO BEGIN FOR k=s[0]-1,0,-1 DO BEGIN radii = Total(matrix[0:k,*],1) / N_Elements(speed_final) * 100 radius = radii[j] xr1 = [ 0, radius * Sin((angles[j]-10)*!DtoR)] yr1 = [ 0, radius * Cos((angles[j]-10)*!DtoR)] xr2 = [ 0, radius * Sin((angles[j]+10)*!DtoR)] yr2 = [ 0, radius * Cos((angles[j]+10)*!DtoR)] pts = cgWindroseArc(0, 0, radius, (angles[j]-10), (angles[j]+10)) xr3 = [xr1, Reform(pts[0,*]), xr2] yr3 = [yr1, Reform(pts[1,*]), yr2] cgColorFill, xr3, yr3, Color=colors[k] cgPolygon, xr3, yr3, Color='black' ENDFOR ENDFOR ; Put a circle in the center of the plot. TVCircle, 0.5, 0, 0, /Data, Color='white', /Fill ; Add a legend unless requested not to. IF ~nolegend THEN BEGIN speeds = Indgen(s[0]-1) * speedBinSize + 1 sym = cgCheckForSymbols('$\geq$' + String(speeds[N_Elements(speeds)-1], Format='(F0.1)')) speedStr = StrArr(N_Elements(speeds)) speedStr[0] = '1.0-' + String(speeds[1], Format='(F0.1)') FOR j=2,N_Elements(speeds)-1 DO BEGIN speedStr[j-1] = String(speeds[j-1], Format='(F0.1)') + '-' + String(speeds[j], Format='(F0.1)') ENDFOR speedStr[N_Elements(speeds)-1] = sym IF N_Elements(legendPosition) EQ 0 THEN BEGIN xpos = !X.Window[0] - ((!D.X_CH_SIZE * 18.0) / !D.X_Size) ypos = !Y.Window[0] + ((!D.Y_CH_SIZE * 10.0) / !D.Y_Size) legendPosition = [xpos, ypos] ENDIF cgLegend, Title=speedStr, PSym=15, SymSize=1.5, Color=colors[0:N_Elements(speedStr)-1], Length=0.0, $ Location=legendPosition, VSpace=1.5, Charsize=cgDefCharsize()*0.75, /Box xtextpos = legendPosition[0] - ((!D.X_CH_SIZE * 1.5) / !D.X_Size) ytextpos = legendPosition[1] + ((!D.Y_CH_SIZE * 1.0) / !D.Y_Size) cgText, xtextpos, ytextpos, /Normal, 'Wind Speed (m/s)', Charsize=cgDefCharsize()*0.85 END ; Add a title to the plot. cgText, (!X.Window[1] - !X.Window[0]) / 2.0 + !X.Window[0], $ !Y.Window[1] + 3.5*(!D.Y_CH_SIZE)/!D.Y_Size, $ /Normal, title, Alignment=0.5, $ Charsize=cgDefCharsize()*1.25 ; Are we producing output? If so, we need to clean up here. IF (N_Elements(output) NE 0) && (output NE "") THEN BEGIN ; Get the output default values. cgWindow_GetDefs, $ IM_Density = im_density, $ ; Sets the density parameter on ImageMagick convert command. IM_Options = im_options, $ ; Sets extra ImageMagick options on the ImageMagick convert command. IM_Resize = im_resize, $ ; Sets the resize parameter on ImageMagick convert command. IM_Transparent = im_transparent, $ ; Sets the "alpha" keyword on ImageMagick convert command. IM_Width = im_width, $ ; Sets the width of raster file output created with ImageMagick. PDF_Unix_Convert_Cmd = pdf_unix_convert_cmd, $ ; Command to convert PS to PDF. PDF_Path = pdf_path ; The path to the Ghostscript conversion command. ; Close the PostScript file and create whatever output is needed. cgPS_Close, DELETE_PS=delete_ps, $ ALLOW_TRANSPARENT=im_transparent, $ BMP=bmp_flag, $ DENSITY=im_density, $ GIF=gif_flag, $ GS_PATH=pdf_path, $ IM_OPTIONS=im_options, $ JPEG=jpeg_flag, $ PDF=pdf_flag, $ PNG=png_flag, $ RESIZE=im_resize, $ TIFF=tiff_flag, $ UNIX_CONVERT_CMD=pdf_unix_convert_cmd, $ WIDTH=im_width basename = File_Basename(outfilename) dirname = File_Dirname(outfilename) IF dirname EQ "." THEN CD, CURRENT=dirname Print, 'Output File: ' + Filepath(ROOT_DIR=dirname, basename) ENDIF END