;+ ; NAME: ; PlotBars ; PURPOSE: ; Plots bar graph ; CALLING SEQUENCE: PRO PlotBars, xin, yin, nvalid , $ sigma = sigma , $ xrange = xrange , $ yaxis = yaxis , $ ynozero = ynozero , $ ylog = ylog , $ yrange = yrange , $ ystyle = ystyle , $ ycolor = ycolor , $ color = color , $ changecolor = changecolor , $ barwidth = barwidth , $ barname = barname , $ barpos = barpos , $ use_min_barwidth= use_min_barwidth , $ shade = shade , $ hatch = hatch , $ cdf = cdf , $ ccdf = ccdf , $ relative = relative , $ nojoin = nojoin , $ noline = noline , $ low_margin = low_margin , $ vertical = vertical , $ horizontal = horizontal , $ fill_sparse = fill_sparse , $ _extra = _extra ; INPUTS: ; xin, yin array[n]; one-dimensional arrays ; must have the same size ; nvalid identifies the array elements to be plotted as: ; - an array of indices e.g. [0,1,2,7,8,9,10] ; - a boolean array[n] (containing only values 0 or 1) ; of same size as xin and yin, e.g. [1,1,1,0,0,0,0,1,1,1,1] ; if nvalid is absent, all finite function values are plotted ; OPTIONAL INPUT PARAMETERS: ; /use_min_barwidth ; use a constant bar width based on the minimum distance ; between data points. ; barwidth scalar; type: float; default: 1 ; by default, bars are drawn with no intervening space, i.e. ; the right side of one bar coincides with the left side of ; its neighbour to the right; or, if /use_min_barwidth is set, ; the default barwidth is the minimum distance between ; neighbouring data points. ; Barwidth is used as a scaling ; factor for the bar width, e.g. barwidth=0.5 will leave ; a space in between bars, equal to the width of the bars. ; barname=barname ; array[n]; type: string; default: none ; string to be plotted alongside each bar at position ; specified in barpos ; barpos=barpos array[n]; type: numeric; default: 0.5*yin ; specifies the position along each bar where string ; barname is plotted. For vertical bars the string is ; plotted with orientation of 90 degrees, along the left ; side of the bar at the height indicated by barpos. ; By default, the string is plotted halfway along the height ; of the bar. ; vertical=vertical ; scalar; type: integer; default: 1 ; draw vertical bars (i.e. standard histogram style) ; horizontal=horizontal ; scalar; type: integer: default: 0 ; draw horizontal bars ; ; shade=shade 1- or 2-element array; type: float; default: none ; if set then the bars are shaded. ; shade[0] is used for bars with good values ; shade[1] is used for bars with bad values ; hatch=hatch 1- or 2-element array; type: float; default: none ; if set then the bars are hatched. The value determines ; the distance between the hatch lines. ; hatch[0] is used for bars with good values ; hatch[1] is used for bars with bad values ; /noline If either shade or hatch is set then this suppress ; the bounding line for each bar. ; This keyword is ignored if neither hatch nor shade is set. ; /nojoin If barwidth is set to one (the default), then the ; common boundaries between neighbouring bars in not drawn. ; This keyword is ignored if barwidth not equal 1. ; ; /cdf Plots a CDF (cumulative distribution function) ; i.e. the yin array is summed left to right. ; /ccdf Plots the CCDF (complementary cumulative distribution ; function (i.e. the yin array is summed right to left. ; ; /relative Plots a normalized CDF. The normalization factor is ; the last element in the CDF. ; INCLUDE @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, IsType, PlotPrep ; PROCEDURE: ; MODIFICATION HISTORY: ; OCT-2010, Paul Hick (UCSD/CASS) ; JUL-2012, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Added /use_min_barwidth ;- InitVar, changecolor , /key InitVar, cdf , /key InitVAr, ccdf , /key InitVar, vertical , /key InitVar, horizontal , /key InitVar, use_min_barwidth , /key InitVar, ylog , /key ; Make sure only one is set. Vertical is the default. IF vertical+horizontal NE 1 THEN BEGIN vertical = 1 horizontal = 0 ENDIF IF IsType(fill_sparse,/defined) THEN BEGIN IF NOT IsType(xin,/generic_int) THEN $ message, "xin_ must be integer if 'fill_sparse' is used" xmin = min(xin) xmax = max(xin) xin_ = gridgen( xmax-xmin+1, range=[xmin,xmax] ) ;yin_ = make_array( type=IsType(yin), dim=xmax-xmin+1, value=fill_sparse ) yin_ = make_array( type=IsType(yin), dim=xmax-xmin+1, value=0) IF IsType(barname,/string ) THEN barname_ = make_array( type=IsType(barname), dim=xmax-xmin+1, value='' ) IF IsType(barpos ,/defined) THEN barpos_ = make_array( type=IsType(barpos ), dim=xmax-xmin+1, value=0 ) FOR i=0L,n_elements(xin)-1 DO BEGIN n = where(xin_ EQ xin[i]) yin_[n] = yin[i] IF IsType(barname,/string ) THEN barname_[n] = barname[i] IF IsType(barpos ,/defined) THEN barpos_ [n] = barpos [i] ENDFOR ENDIF ELSE BEGIN xin_ = xin yin_ = yin IF IsType(barname,/string ) THEN barname_ = barname IF IsType(barpos ,/defined) THEN barpos_ = barpos ENDELSE IF ccdf THEN BEGIN xin_ = reverse(xin_) yin_ = reverse(yin_) IF IsType(barname_,/defined) THEN barname_ = reverse(barname_) IF IsType(barpos_ ,/defined) THEN barpos_ = reverse(barpos_ ) IF IsType(xrange,/undefined) THEN xrange = [xin_[0],xin_[n_elements(xin_)-1]] ENDIF IF cdf OR ccdf THEN BEGIN ny = n_elements(yin_) n = finite(yin_) yin__ = yin_ ysum = 0 FOR i=0L,ny-1 DO BEGIN IF n[i] THEN ysum += yin__[i] yin_[i] = ysum ENDFOR destroyvar, yin__ IF IsType(relative,/defined) THEN yin_ /= double(yin_[ny-1]) ENDIF n = PlotPrep( xin_, yin_, nvalid, $ xpnt = xpnt , $ ypnt = ypnt , $ npnt = npnt , $ yaxis = yaxis , $ xrange = xrange , $ yrange = yrange , $ ystyle = ystyle , $ ynozero = ynozero , $ ylog = ylog , $ ycolor = ycolor , $ changecolor = changecolor , $ _extra = _extra ) CASE vertical OF 0: BEGIN opnt = ypnt fpnt = xpnt END 1: BEGIN opnt = xpnt fpnt = ypnt END ENDCASE destroyvar, xpnt, ypnt badfpnt = BadValue(fpnt) InitVar, barwidth , 1 InitVar, nojoin , /key nojoin AND= barwidth EQ 1 shading = IsType(shade,/defined) IF shading THEN BEGIN goodshade = shade[0] badshade = shade[n_elements(shade)-1] ENDIF hatching = IsType(hatch,/defined) IF hatching THEN BEGIN goodhatch = hatch[0] badhatch = hatch[n_elements(hatch)-1] ENDIF InitVar, noline, /key noline AND= shading OR hatching goodcolor = !p.color badcolor = !d.n_colors/2 IF IsType(color,/defined) THEN BEGIN goodcolor = color[0] IF n_elements(color) GT 1 THEN badcolor = color[1] ENDIF nn = n_elements(opnt) d = (shift(opnt,-1)-opnt)[0:nn-2] ; Distance between points IF use_min_barwidth THEN BEGIN dmin = min(d) i = where(d NE dmin) IF i[0] NE -1 THEN d[i] = dmin ENDIF negative_side = opnt-0.5*barwidth*[d[0],d ] positive_side = opnt+0.5*barwidth*[d ,d[nn-2]] bsigma = n_elements(sigma) EQ nn m = 0L ; Add data points dlast = -1L ; Last good point processed CASE ylog OF 0: InitVar, low_margin, !y.crange[0]*vertical+!x.crange[0]*horizontal 1: InitVar, low_margin, 10^!y.crange[0]*vertical+!x.crange[0]*horizontal ENDCASE WHILE m LT n DO BEGIN ; While there are points left to process ; Pick up next sequence of valid points d = where ( npnt[m:n-1] EQ npnt[m]+indgen(n-m), i ) d = npnt[m+d] ; Indices of sequence of valid points ; Note that d is a list (without gaps) of indices into x,y ; i is number of good points in sequence ; d[0] .. d[i-1] are indices in opnt, fpnt, npnt (without gaps) ; of current list of good points ; dlast is last index of previous list of good points IF changecolor THEN BEGIN ; Handle leftover bad points between succesive sequences of valid points ; First shade and draw error bars (before drawing bounding lines) FOR j=dlast+1,d[0]-1 DO BEGIN IF finite(fpnt[j]) THEN BEGIN plotbars_shade, $ plotbars_boundary(j,dlast+1,d[0]-1, fpnt, negative_side, positive_side, low_margin), $ shading = shading , $ hatching = hatching , $ color = badshade , $ spacing = badhatch , $ horizontal = horizontal IF NOT noline AND bsigma THEN plotbars_sigma, opnt[j], fpnt[j], sigma[j], horizontal=horizontal ENDIF ENDFOR IF NOT noline THEN BEGIN ; Now collect all points on the bounding lines of all bars ; (still working with bad points) FOR j=dlast+1,d[0]-1 DO BEGIN CASE finite(fpnt[j]) OF 0: plotbars_plot , rr, color=badcolor, horizontal=horizontal, _extra=_extra 1: plotbars_collect, rr, plotbars_boundary(j,dlast+1,d[0]-1, fpnt, negative_side, positive_side, low_margin, nojoin=nojoin, /bad_sequence, cdf=cdf OR ccdf) ENDCASE ENDFOR plotbars_plot, rr, color=badcolor, horizontal=horizontal, _extra=_extra ENDIF ENDIF ; Plot the sequence of valid points as bars ; First do the shading/hashing (before drawing the bounding lines) ; and the error bars FOR j=d[0],d[i-1] DO BEGIN plotbars_shade, $ plotbars_boundary(j, d[0], d[i-1], fpnt, negative_side, positive_side, low_margin), $ shading = shading , $ hatching = hatching , $ color = goodshade , $ spacing = goodhatch , $ horizontal = horizontal ; Plot the error bar IF NOT noline AND bsigma THEN plotbars_sigma, opnt[j], fpnt[j], sigma[j], horizontal=horizontal ENDFOR ; Points for the bargraph are collected in rr and are plotted ; with a single oplot statement after the loop. IF NOT noline THEN BEGIN FOR j=d[0],d[i-1] DO plotbars_collect, rr, plotbars_boundary(j, d[0], d[i-1], fpnt, negative_side, positive_side, low_margin, nojoin=nojoin, cdf=cdf OR ccdf) plotbars_plot, rr, color=goodcolor, horizontal=horizontal, _extra=_extra ENDIF IF IsType(barname_,/defined) THEN BEGIN w = 1.3 FOR j=d[0],d[i-1] DO IF barname_[j] NE '' THEN xyouts, w*negative_side[j]+(1-w)*positive_side[j], IsType(barpos_,/defined) ? barpos_[j] : 0.5*fpnt[j], barname_[j], orientation=90*vertical, align=0.5 ENDIF m += i dlast = d[i-1] ; Last good point ENDWHILE IF changecolor THEN BEGIN ; Still bad points left after last good point FOR j=dlast+1,nn-1 DO BEGIN IF finite(fpnt[j]) THEN BEGIN plotbars_shade, $ plotbars_boundary(j, dlast+1, nn-1, fpnt, negative_side, positive_side, low_margin), $ shading = shading , $ hatching = hatching , $ color = badshade , $ spacing = badhatch , $ horizontal = horizontal IF NOT noline AND bsigma THEN plotbars_sigma, opnt[j], fpnt[j], sigma[j], horizontal=horizontal ENDIF ENDFOR IF NOT noline THEN BEGIN FOR j=dlast+1,nn-1 DO BEGIN CASE finite(fpnt[j]) OF 0: plotbars_plot , rr, color=badcolor, horizontal=horizontal, _extra=_extra 1: plotbars_collect, rr, plotbars_boundary(j, dlast+1, nn-1, fpnt, negative_side, positive_side, low_margin, nojoin=nojoin, /bad_sequence) ENDCASE ENDFOR plotbars_plot, rr, color=badcolor, horizontal=horizontal, _extra=_extra ENDIF ENDIF RETURN & END