Skip to content

Commit 0c91545

Browse files
twalensbrugman
authored andcommitted
fix for issue #60 (invalid bin_edges for SparselyBin)
1 parent 6b8e240 commit 0c91545

2 files changed

Lines changed: 45 additions & 77 deletions

File tree

histogrammar/primitives/sparselybin.py

Lines changed: 30 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -672,41 +672,44 @@ def n_bins(self):
672672
"""Get number of filled bins, consistent with SparselyBin and Categorize """
673673
return len(self.bins)
674674

675-
def num_bins(self, low=None, high=None):
676-
"""
677-
Returns number of bins from low to high, including unfilled
678-
679-
Possible to set range with low and high params
680-
681-
:param low: lower edge of range, default is None
682-
:param high: higher edge of range, default is None
683-
:returns: number of bins in range
684-
:rtype: int
675+
def _bin_range(self, low=None, high=None):
676+
"""Utility function for calculating bins ranges and numbers for given constraints [low, high]
677+
:returns: (minBin, maxBin, numBins, minBinLeftEdge, maxBinRightEdge)
685678
"""
679+
if low is not None and high is not None and low > high:
680+
raise RuntimeError('low {low} greater than high {high}'.format(low=low, high=high))
686681
# sparse hist not filled
687682
if self.minBin is None or self.maxBin is None:
688-
return 0
689-
# trivial case
690-
if low is None and high is None:
691-
return (self.maxBin - self.minBin + 1)
692-
# catch weird cases
693-
elif low is not None and high is not None:
694-
if low > high:
695-
raise RuntimeError('low {low} greater than high {high}'.format(low=low, high=high))
696-
# lowest edge
683+
return 0, -1, 0, self.origin, self.origin+1
684+
697685
if low is None:
698686
minBin = self.minBin
699687
else:
700688
minBin = self.bin(low)
701-
# highest case
702689
if high is None:
703690
maxBin = self.maxBin
704691
else:
705692
maxBin = self.bin(high)
706693
if np.isclose(high, self.origin + self.bin_width() * maxBin):
707694
maxBin -= 1
708-
nbins = maxBin - minBin + 1
709-
return nbins
695+
numBins = maxBin + 1 - minBin
696+
minBinLeftEdge = self.origin + self.bin_width() * minBin
697+
maxBinRightEdge = self.origin + self.bin_width() * (maxBin + 1)
698+
return minBin, maxBin, numBins, minBinLeftEdge, maxBinRightEdge
699+
700+
def num_bins(self, low=None, high=None):
701+
"""
702+
Returns number of bins from low to high, including unfilled
703+
704+
Possible to set range with low and high params
705+
706+
:param low: lower edge of range, default is None
707+
:param high: higher edge of range, default is None
708+
:returns: number of bins in range
709+
:rtype: int
710+
"""
711+
_, _, numBins, _, _ = self._bin_range(low, high)
712+
return numBins
710713

711714
def bin_width(self):
712715
"""
@@ -725,37 +728,10 @@ def bin_edges(self, low=None, high=None):
725728
:returns: numpy array with bin edges for selected range
726729
:rtype: numpy.array
727730
"""
728-
# sparse hist not filled
729-
if self.minBin is None or self.maxBin is None:
730-
return np.array([self.origin, self.origin + 1])
731-
# trivial cases first
732-
if low is None and high is None:
733-
num_bins = self.maxBin - self.minBin + 1
734-
return np.linspace(self.low, self.high, num_bins + 1)
735-
# catch weird cases
736-
elif low is not None and high is not None:
737-
if low > high:
738-
raise RuntimeError('low {low} greater than high {high}'.format(low=low, high=high))
739-
# lowest edge
740-
if low is None:
741-
low = self.low
742-
else:
743-
minBin = self.bin(low)
744-
low = self.origin + self.bin_width() * minBin
745-
# highest edge
746-
if high is None:
747-
high = self.high
748-
else:
749-
maxBin = self.bin(high)
750-
if np.isclose(high, self.origin + self.bin_width() * maxBin):
751-
maxBin -= 1
752-
high = self.origin + self.bin_width() * (maxBin + 1)
753-
# number of bins, after low/high adjustments
754-
num_bins = self.num_bins(low + np.finfo(float).eps, high - np.finfo(float).eps)
755-
edges = np.linspace(low, high, num_bins + 1)
756-
return edges
731+
_, _, numBins, minBinLeftEdge, maxBinRightEdge = self._bin_range(low, high)
732+
return np.linspace(minBinLeftEdge, maxBinRightEdge, numBins + 1)
757733

758-
def bin_entries(self, low=None, high=None, xvalues=[]):
734+
def bin_entries(self, low=None, high=None, xvalues=None):
759735
"""
760736
Returns bin values
761737
@@ -767,33 +743,10 @@ def bin_entries(self, low=None, high=None, xvalues=[]):
767743
:returns: numpy array with numbers of entries for selected bins
768744
:rtype: numpy.array
769745
"""
770-
# sparse hist not filled
771-
if self.minBin is None or self.maxBin is None:
772-
return np.array([])
773-
# trivial cases first
774-
if low is None and high is None and len(xvalues) == 0:
775-
entries = [self.bins[i].entries if i in self.bins else 0.0 for i in range(self.minBin, self.maxBin + 1)]
776-
return np.array(entries)
777-
# catch weird cases
778-
elif low is not None and high is not None and len(xvalues) == 0:
779-
if low > high:
780-
raise RuntimeError('low {low} greater than high {high}'.format(low=low, high=high))
781-
# entries at request list of x-values
782-
elif len(xvalues) > 0:
746+
if xvalues is not None and len(xvalues) > 0:
783747
entries = [self.bins[self.bin(x)].entries if self.bin(x) in self.bins else 0.0 for x in xvalues]
784748
return np.array(entries)
785-
# lowest edge
786-
if low is None:
787-
minBin = self.minBin
788-
else:
789-
minBin = self.bin(low)
790-
# highest case
791-
if high is None:
792-
maxBin = self.maxBin
793-
else:
794-
maxBin = self.bin(high)
795-
if np.isclose(high, self.origin + self.bin_width() * maxBin):
796-
maxBin -= 1
749+
minBin, maxBin, _, _, _ = self._bin_range(low, high)
797750
entries = [self.bins[i].entries if i in self.bins else 0.0 for i in range(minBin, maxBin + 1)]
798751
return np.array(entries)
799752

tests/test_basic.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,21 @@ def testSparselyBin(self):
888888
self.checkPickle(two)
889889
self.checkName(two)
890890

891+
def testSparselyBinWithFloatBinWidth(self):
892+
binWidth = 10.1
893+
values = [0.114, 146.756, 302.333, 417.022, 720.324]
894+
low, high = 314.0, 332.0
895+
896+
hist = SparselyBin(binWidth=binWidth)
897+
for x in values:
898+
hist.fill(x)
899+
edges = hist.bin_edges(low=low, high=high)
900+
entries = hist.bin_entries(low=low, high=high)
901+
self.assertAlmostEqual(edges[1] - edges[0], binWidth)
902+
self.assertEqual(len(edges), 3)
903+
self.assertEqual(len(entries), 2)
904+
self.assertEqual(list(entries), [0, 0])
905+
891906
# CentrallyBin
892907

893908
def testCentrallyBin(self):

0 commit comments

Comments
 (0)