; docformat = 'rst' ;+ ; Find the histogram of a set of `n`-dimensional points. ; ; :History: ; 16 January 2008, written by Michael Galloy. ; ; Code adapted from `HIST_ND` from David Fanning and `HIST_ND_WEIGHT` by ; Jeremy Bailin. ; ; :Examples: ; Try:: ; ; IDL> q = transpose([[0.1 * findgen(40)], [0.2 * findgen(40)]]) ; IDL> print, mg_hist_nd(q, bin_size=1, weight=q, unweighted=unweighted) ; 0.500000 0.00000 0.00000 0.00000 ; 2.50000 0.00000 0.00000 0.00000 ; 0.00000 4.00000 0.00000 0.00000 ; 0.00000 6.50000 0.00000 0.00000 ; 0.00000 0.00000 7.50000 0.00000 ; 0.00000 0.00000 10.5000 0.00000 ; 0.00000 0.00000 0.00000 11.0000 ; 0.00000 0.00000 0.00000 14.5000 ; IDL> print, unweighted ; 5 0 0 0 ; 5 0 0 0 ; 0 5 0 0 ; 0 5 0 0 ; 0 0 5 0 ; 0 0 5 0 ; 0 0 0 5 ; 0 0 0 5 ; IDL> print, mg_hist_nd(q, nbins=[4, 8], max=[4.0, 8.0]) ; 5 0 0 0 ; 5 0 0 0 ; 0 5 0 0 ; 0 5 0 0 ; 0 0 5 0 ; 0 0 5 0 ; 0 0 0 5 ; 0 0 0 5 ; ; This example is in a main-level program at the end of this file. Run it ; with:: ; ; IDL> .run mg_hist_nd ; ; :Returns: ; histogram of size `n_1` by `n_2` by .... by `n_n` ; ; :Params: ; array : in, required, type=numeric array ; array to find histogram of; ndims by npoints array ; ; :Keywords: ; bin_size : in, optional, type=numeric ; the size of bin to use; either an n element vector or a scalar to use ; for all dimensions; either `BIN_SIZE` or `NBINS` must be set ; nbins : in, optional, type=long ; the number of bins to use; either an n element vector or a scalar to ; use for all dimensions; either `BIN_SIZE` or `NBINS` must be set ; minimum : in, optional, type=float/fltarr(n), default="min(array, dim=2)" ; set to either a scalar value to use for the minimum of each dimension ; or a vector of values; if not specified, will use the natural minimum ; in each dimension ; maximum : in, optional, type=float/fltarr(n), default="max(array, dim=2)" ; set to either a scalar value to use for the maximum of each dimension ; or a vector of values; if not specified, will use the natural maximum ; in each dimension ; omin : out, optional, type=float/fltarr(n) ; set to a named variable to return the minimum values used in computing ; the histogram ; omax : out, optional, type=float/fltarr(n) ; set to a named variable to return the maximum values used in computing ; the histogram ; reverse_indices : out, optional, type=lonarr ; set to a named variable to get 1-dimensional vector representing ; the indices of the points that fall in a particular bin; to find the ; indices of the points in bin [i, j, k], use the same formular as ; when using `REVERSE_INDICES` with `HISTOGRAM` (after converting to ; single dimensional indexing):: ; ; ijk = [i + nx * j + nx * ny * k] ; ind = ri[ri[ijk]:ri[ijk + 1] - 1] ; ; See `ARRAY_INDICES` for converting `ind` back to 3-dimensional ; indices. ; weights : in, optional, type=numeric array ; array with same dimensions as array containing a weight for each point ; unweighted : out, optional, type=same as return value ; set to a named variable to get the unweighted histogram ; l64 : in, optional, type=boolean ; set to return long64 results ;- function mg_hist_nd, array, $ bin_size=binsize, nbins=nbins, $ minimum=minimum, maximum=maximum, $ omin=_minimum, omax=_maximum, $ reverse_indices=ri, $ weights=weights, unweighted=unweighted, $ l64=l64 compile_opt strictarr dims = size(array, /dimensions) n = dims[0] if (n_elements(dims) ne 2L) then begin message, 'input must be 2-dimensional: dimensions by points' endif if (dims[0] gt 8L) then message, 'only up to 8 dimensions allowed' imx = max(array, dimension=2, min=imn) _maximum = n_elements(maximum) eq 0L ? imx : maximum _minimum = n_elements(minimum) eq 0L ? imn : minimum if (dims[0] gt 1L) then begin if (n_elements(_maximum) eq 1) then _maximum = replicate(_maximum, n) if (n_elements(_minimum) eq 1) then _minimum = replicate(_minimum, n) if (n_elements(binsize) eq 1) then binsize = replicate(binsize, n) if (n_elements(nbins) eq 1) then nbins = replicate(nbins, n) endif if (~array_equal(_minimum le _maximum, 1B)) then begin message, 'minimum must be less than or equal to maximum' endif if (n_elements(binsize) eq 0) then begin if (n_elements(nbins) ne 0) then begin nbins = long(nbins) binsize = float(_maximum - _minimum) / nbins endif else begin message, 'must pass either BIN_SIZE or NBINS' endelse endif else begin if (n_elements(nbins) eq 0) then begin nbins = long((_maximum - _minimum) / binsize + 1) endif else begin message, 'must pass either BIN_SIZE or NBINS' endelse endelse total_bins = product(nbins, /preserve_type) h = long((array[n - 1L, *] - _minimum[n - 1L]) / binsize[n - 1L]) for i = dims[0] - 2L, 0L, -1L do begin h = nbins[i] * h + long((array[i, *] - _minimum[i]) / binsize[i]) endfor out_of_range = [~array_equal(_minimum le imn, 1B), $ ~array_equal(_maximum ge imx, 1B)] if (~array_equal(out_of_range, 0B)) then begin in_range = 1B if (out_of_range[0]) then begin ; too low minArray = rebin(_minimum, dims, /sample) in_range = total(array ge minArray, 1, /preserve_type) eq n endif if (out_of_range[1]) then begin ; too high maxArray = rebin(_maximum, dims, /sample) in_range and= total(array le maxArray, 1, /preserve_type) eq n endif h = (temporary(h) + 1L) * in_range - 1L endif ; do the histogram, computing REVERSE_INDICES only if needed if (arg_present(ri) || n_elements(weights) gt 0L) then begin unweighted = histogram(h, min=0L, max=total_bins - 1L, $ reverse_indices=ri, l64=keyword_set(l64)) endif else begin unweighted = histogram(h, min=0L, max=total_bins - 1L, $ l64=keyword_set(l64)) endelse ; reform to correct dimensionality unweighted = reform(unweighted, nbins, /overwrite) ; handle weights, if present if (n_elements(weights) gt 0L) then begin weighted = replicate(weights[0], size(unweighted, /dimensions)) for i = 0L, n_elements(unweighted) - 1L do begin if (unweighted[i] gt 0) then begin q = ri[ri[i]:ri[i + 1L] - 1L] weighted[i] = total(weights[q]) endif endfor return, weighted endif return, unweighted end ; main-level example program q = transpose([[0.1 * findgen(40)], [0.2 * findgen(40)]]) print, mg_hist_nd(q, bin_size=1, weights=q, unweighted=unweighted), unweighted print, mg_hist_nd(q, nbins=[4, 8], max=[4.0, 8.0]) end