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
|
"""
Returns histogram bin counts for a given array of values.
"""
from __future__ import print_function
import numpy
import pyferret
# The following is just to circumvent to call to pyferret.get_axis_info for testing
DOING_UNIT_TEST = False
def ferret_init(id):
"""
Initialization for the stats_histogram Ferret PyEF
"""
axes_values = [ pyferret.AXIS_IMPLIED_BY_ARGS ] * pyferret.MAX_FERRET_NDIM
true_influences = [ True ] * pyferret.MAX_FERRET_NDIM
false_influences = [ False ] * pyferret.MAX_FERRET_NDIM
retdict = { "numargs": 2,
"descript": "Returns unweighted histogram bin counts for all defined data values",
"axes": axes_values,
"argnames": ("VALS", "BINS_TEMPLATE"),
"argdescripts": ("Values to put into bins and then count",
"Template argument whose one defined axis gives midpoints of bins"),
"argtypes": (pyferret.FLOAT_ARRAY, pyferret.FLOAT_ARRAY),
"influences": (false_influences, true_influences),
}
return retdict
def ferret_compute(id, result, resbdf, inputs, inpbdfs):
"""
Assigns result with histogram bin counts of data in inputs[0]. Bin
limits are defined using the values of the one defined non-singular
axis associated with inputs[1]. The argument inputs[1] is otherwise
unused. Undefined values in inputs[0] are eliminated before binning.
"""
# get the box limits of the one defined non-singular axis of the second argument
if DOING_UNIT_TEST:
limits_func = my_get_box_limits
else:
limits_func = pyferret.get_axis_box_limits
limits_tuple = None
axis_used = None
for axis_num in (pyferret.X_AXIS, pyferret.Y_AXIS, pyferret.Z_AXIS,
pyferret.T_AXIS, pyferret.E_AXIS, pyferret.F_AXIS):
this_tuple = limits_func(id, pyferret.ARG2, axis_num)
if (this_tuple != None) and (len(this_tuple[0]) > 1):
if limits_tuple != None:
raise ValueError("BINS_TEMPLATE has more than one defined non-singular axis")
limits_tuple = this_tuple
axis_used = axis_num
if limits_tuple is None:
raise ValueError("BINS_TEMPLATE does not have a defined non-singular axis")
# get the histogram bin limits from the axis box limits
if not numpy.allclose(limits_tuple[0][1:], limits_tuple[1][:-1]):
raise ValueError("Unexpected error: gaps exist between axis box limits")
bin_edges = numpy.empty( ( len(limits_tuple[1]) + 1, ), dtype=numpy.float64)
bin_edges[0] = limits_tuple[0][0]
bin_edges[1:] = limits_tuple[1]
# get the clean data as a flattened array
badmask = ( numpy.fabs(inputs[0] - inpbdfs[0]) < 1.0E-5 )
badmask = numpy.logical_or(badmask, numpy.isnan(inputs[0]))
goodmask = numpy.logical_not(badmask)
values = inputs[0][goodmask]
# compute the histogram and assign the counts to result
(hist, edges) = numpy.histogram(values, bins=bin_edges)
if axis_used == pyferret.X_AXIS:
result[:,0,0,0,0,0] = hist
elif axis_used == pyferret.Y_AXIS:
result[0,:,0,0,0,0] = hist
elif axis_used == pyferret.Z_AXIS:
result[0,0,:,0,0,0] = hist
elif axis_used == pyferret.T_AXIS:
result[0,0,0,:,0,0] = hist
elif axis_used == pyferret.E_AXIS:
result[0,0,0,0,:,0] = hist
elif axis_used == pyferret.F_AXIS:
result[0,0,0,0,0,:] = hist
else:
raise ValueError("Unexpected axis_used value: %d" % axis_used)
#
# The rest of this is just for testing this module at the command line
#
if __name__ == "__main__":
DOING_UNIT_TEST = True
# create the my_get_box_limits function for testing
def my_get_box_limits(id, argnum, axisnum):
if id != 0:
raise ValueError("Unexpected my_get_box_limits argnum; expected: 0, found: %d" % \
argnum)
if argnum != pyferret.ARG2:
raise ValueError("Unexpected my_get_box_limits argnum; expected: %d, found: %d" % \
(pyferret.ARG2, argnum))
if axisnum != pyferret.Z_AXIS:
return None
limits = numpy.array([1.0, 2.0, 3.0, 4.0, 6.0, 9.0], dtype=numpy.float64)
return (limits[:-1], limits[1:])
# create the input values array with values on the edges and outside
values = numpy.arange(0.0, 10.2, 0.1, dtype=numpy.float64).reshape((1,6,1,17,1,1), order='F')
# create the expected results array
expected = -1.0 * numpy.ones((1,1,5,1,1,1), dtype=numpy.float64, order='F')
expected[0,0,:,0,0,0] = (10.0, 10.0, 10.0, 20.0, 31.0)
# make sure no errors when ferret_init called
info = ferret_init(0)
# make the call to ferret_compute
result = 999.0 * expected
resbdf = numpy.array([-1.0], dtype=numpy.float64)
inpbdfs = numpy.array([-1.0, -1.0], dtype=numpy.float64)
ferret_compute(0, result, resbdf, (values, None), inpbdfs)
# verify the results
if not numpy.allclose(result, expected):
raise ValueError("Unexpected results; expected:\n%s\nfound:\n%s" % (str(expected), str(result)))
print("Success")
|