value_locate.pro
5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
;+
; NAME:
; VALUE_LOCATE
;
; AUTHOR:
; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
; craigm@lheamail.gsfc.nasa.gov
;
; PURPOSE:
;
; Locate one or more values in a reference array (IDL LE 5.2 compatibility)
;
; CALLING SEQUENCE:
;
; INDICES = VALUE_LOCATE(REF, VALUES)
;
; DESCRIPTION:
;
; VALUE_LOCATE locates the positions of given values within a
; reference array. The reference array need not be regularly
; spaced. This is useful for various searching, sorting and
; interpolation algorithms.
;
; The reference array should be a monotonically increasing or
; decreasing list of values which partition the real numbers. A
; reference array of NBINS numbers partitions the real number line
; into NBINS+1 regions, like so:
;
;
; REF: X[0] X[1] X[2] X[3] X[NBINS-1]
; <----------|-------------|------|---|----...---|--------------->
; INDICES: -1 0 1 2 3 NBINS-1
;
;
; VALUE_LOCATE returns which partition each of the VALUES falls
; into, according to the figure above. For example, a value between
; X[1] and X[2] would return a value of 1. Values below X[0] return
; -1, and above X[NBINS-1] return NBINS-1. Thus, besides the value
; of -1, the returned INDICES refer to the nearest reference value
; to the left of the requested value.
;
; If the reference array is monotonically decreasing then the
; partitions are numbered starting at -1 from the right instead (and
; the returned INDICES refer to the nearest reference value to the
; *right* of the requested value). If the reference array is
; neither monotonically increasing or decreasing the results of
; VALUE_LOCATE are undefined.
;
; VALUE_LOCATE appears as a built-in funcion in IDL v5.3 and later.
; This version of VALUE_LOCATE should work under IDL v4 and later,
; and is intended to provide a portable solution for users who do
; not have the latest version of IDL. The algrorithm in this file
; is slower but not terribly so, than the built-in version.
;
; Users should be able to place this file in their IDL path safely:
; under IDL 5.3 and later, the built-in function will take
; precedence; under IDL 5.2 and earlier, this function will be used.
;
; INPUTS:
;
; REF - the reference array of monotonically increasing or
; decreasing values.
;
; VALUES - a scalar value or array of values to be located in the
; reference array.
;
;
; KEYWORDS:
;
; L64 - (ignored) for compatibility with built-in version.
;
; NO_CROP - if set, and VALUES is outside of the region between X[0]
; and X[NBINS-1], then the returned indices may be *less
; than* -1 or *greater than* NBINS-1. The user is the
; responsible for cropping these values appropriately.
;
; RETURNS:
;
; An array of indices between -1L and NBINS-1. If VALUES is an
; array then the returned array will have the same dimensions.
;
;
; EXAMPLE:
;
; Cast random values into a histogram with bins from 1-10, 10-100,
; 100-1000, and 1000-10,000.
;
; ;; Make bin edges - this is the ref. array
; xbins = 10D^dindgen(5)
;
; ;; Make some random data that ranges from 1 to 10,000
; x = 10D^(randomu(seed,1000)*4)
;
; ;; Find the bin number of each random value
; ii = value_locate(xbins, x)
;
; ;; Histogram the data
; hh = histogram(ii)
;
;
; SEE ALSO:
;
; VALUE_LOCATE (IDL 5.3 and later), HISTOGRAM, CMHISTOGRAM
;
;
; MODIFICATION HISTORY:
; Written and documented, 21 Jan 2001
; Case of XBINS having only one element, CM, 29 Apr 2001
; Handle case of VALUES exactly hitting REF points, CM, 13 Oct 2001
;
; $Id: value_locate.pro,v 1.5 2001/10/13 17:59:34 craigm Exp $
;
;-
; Copyright (C) 2001, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-
function value_locate, xbins, x, l64=l64, no_crop=nocrop, _EXTRA=extra
on_error, 2
nbins = n_elements(xbins)
sz = size(xbins)
;; Error checking
if nbins EQ 0 then message, 'ERROR: XBINS must have at least one element'
if nbins EQ 1 then return, (x GE xbins(0)) - 1L
;; The values are computed by spline interpolation. Here is the "y"
;; value of the spline, which is just the bin position.
tp = sz(sz(0)+1)
if tp EQ 1 OR tp EQ 2 OR tp EQ 12 then begin
yy = findgen(nbins) - 0.5
eps = (machar()).eps
endif else begin
yy = dindgen(nbins) - 0.5D
eps = (machar(/double)).eps
endelse
;; Check if we are reversing.
if xbins(nbins-1) GT xbins(0) then rev = 0 else rev = 1
;; Compute the spline interpolation. Note here that we set the 2nd
;; derivative value to zero since the derivative computed by
;; SPL_INIT seems to be royally screwed up. Also we do separate
;; computations for the increasing and non-increasing cases, since
;; SPL_INTERP seems to choke on the later.
if rev EQ 0 then $
ii = round(spl_interp(xbins, yy, yy*0, x) + eps) $
else $
ii = round(spl_interp(reverse(xbins), yy, yy*0, x) + eps)
;; Crop the end values appropriately
if NOT keyword_set(nocrop) then begin
ii = ii > (-1L) < (nbins-1)
endif
;; Reverse the array
if rev EQ 0 then $
ret = temporary(ii) $
else $
ret = (nbins-2)-temporary(ii)
;; Reform the array to the correct dimensions (ie, add trailing
;; dimensions)
sz = size(x)
if sz(0) GT 0 then $
ret = reform(ret, sz(1:sz(0)), /overwrite)
return, ret
end