Skip to content

Commit 8f2afb9

Browse files
committed
refactor: rename variables for clarity and improve error handling in histogram processing
1 parent da741ec commit 8f2afb9

2 files changed

Lines changed: 34 additions & 58 deletions

File tree

src/khisto/array/histogram/api.py

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
def _select_histogram(
18-
results: list[HistogramResult],
18+
histogram_results: list[HistogramResult],
1919
max_bins: Optional[int] = None,
2020
) -> HistogramResult:
2121
"""Select the appropriate histogram from the list of results.
@@ -35,38 +35,20 @@ def _select_histogram(
3535
if max_bins is not None:
3636
# Find the finest granularity that respects max_bins
3737
selected = None
38-
for r in results:
38+
for r in histogram_results:
3939
if len(r) <= max_bins:
4040
selected = r
4141
else:
4242
break
4343
# If no histogram respects the constraint, use the coarsest one
44-
return selected if selected is not None else results[0]
44+
return selected if selected is not None else histogram_results[0]
4545
else:
4646
# Return the best (optimal) histogram
47-
for r in results:
47+
for r in reversed(histogram_results):
4848
if r.is_best:
4949
return r
5050
# Fallback to finest granularity if no best is marked
51-
return results[-1]
52-
53-
54-
def _apply_cumulative(
55-
hist_values: NDArray[np.float64],
56-
bin_edges: NDArray[np.float64],
57-
*,
58-
density: bool,
59-
reverse: bool = False,
60-
) -> NDArray[np.float64]:
61-
"""Accumulate histogram values using matplotlib-compatible semantics."""
62-
if density:
63-
source_values = hist_values * np.diff(bin_edges)
64-
else:
65-
source_values = hist_values
66-
67-
if reverse:
68-
return np.cumsum(source_values[::-1])[::-1]
69-
return np.cumsum(source_values)
51+
return histogram_results[-1]
7052

7153

7254
def histogram(
@@ -125,15 +107,20 @@ def histogram(
125107
"""
126108
arr = np.asarray(a, dtype=np.float64).flatten()
127109

110+
if max_bins is not None and max_bins <= 0:
111+
raise ValueError("max_bins must be a positive integer or None.")
112+
128113
# Filter values by range if specified
129114
if range is not None:
130115
min_val, max_val = range
131116
arr = arr[(arr >= min_val) & (arr <= max_val)]
132117

133-
results = compute_histograms(arr)
134-
result = _select_histogram(results, max_bins=max_bins)
118+
histogram_results = compute_histograms(arr)
119+
histogram_result = _select_histogram(histogram_results, max_bins=max_bins)
135120

136121
if density:
137-
return result.density.copy(), result.bin_edges.copy()
122+
return histogram_result.density.copy(), histogram_result.bin_edges.copy()
138123
else:
139-
return result.frequency.astype(np.float64), result.bin_edges.copy()
124+
return histogram_result.frequency.astype(
125+
np.float64
126+
), histogram_result.bin_edges.copy()

src/khisto/core/backend.py

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -167,54 +167,43 @@ def _parse_file_type(file_path: pathlib.Path) -> None:
167167
raise ValueError(f"Unrecognized histogram file name: {file_path.name}")
168168

169169

170-
def _best_index(
171-
series: _SeriesPayload, best: Optional[_HistogramPayload]
172-
) -> Optional[int]:
173-
"""Determine the best histogram index from the series."""
174-
if series.interpretableHistogramNumber > 0:
175-
return series.interpretableHistogramNumber - 1
176-
if best is not None:
177-
for i, h in enumerate(series.histograms):
178-
if h.lowerBounds == best.lowerBounds:
179-
return i
180-
return None
181-
182-
183170
def _process_histogram_files(temp_dir: str, base_name: str) -> list[HistogramResult]:
184171
"""Process exploratory JSON generated by khisto CLI."""
185172
output_file = pathlib.Path(temp_dir) / f"{base_name}.json"
186173
_parse_file_type(output_file)
187174

188175
with output_file.open("r", encoding="utf-8") as f:
189-
output: _KhistoOutput = _KhistoOutput.from_dict(json.load(f))
190-
191-
if not output.histogramSeries or not output.histogramSeries.histograms:
192-
if output.bestHistogram is None:
193-
raise ValueError("No histogram data found")
194-
return [_to_result(output.bestHistogram, is_best=True)]
176+
khisto_output: _KhistoOutput = _KhistoOutput.from_dict(json.load(f))
195177

196-
series = output.histogramSeries
197-
n = len(series.histograms)
198-
best_idx = _best_index(series, output.bestHistogram)
178+
histogram_series = khisto_output.histogramSeries
179+
n = len(histogram_series.histograms)
180+
best_idx = histogram_series.interpretableHistogramNumber - 1
199181
granularities = (
200-
series.granularities if len(series.granularities) == n else list(range(n))
182+
histogram_series.granularities
183+
if len(histogram_series.granularities) == n
184+
else list(range(n))
201185
)
202186

203-
def _get(lst: list, i: int, default=0):
204-
return lst[i] if i < len(lst) else default
187+
def _get(lst: list, i: int):
188+
if i < len(lst):
189+
return lst[i]
190+
else:
191+
raise ValueError(
192+
f"Expected at least {i + 1} values in list, got {len(lst)}"
193+
)
205194

206195
return [
207196
_to_result(
208197
h,
209198
is_best=(i == best_idx),
210199
granularity=granularities[i],
211-
level=_get(series.levels, i, 0.0),
212-
information_rate=_get(series.informationRates, i, 0.0),
213-
peak_interval_number=_get(series.peakIntervalNumbers, i),
214-
spike_interval_number=_get(series.spikeIntervalNumbers, i),
215-
empty_interval_number=_get(series.emptyIntervalNumbers, i),
200+
level=_get(histogram_series.levels, i),
201+
information_rate=_get(histogram_series.informationRates, i),
202+
peak_interval_number=_get(histogram_series.peakIntervalNumbers, i),
203+
spike_interval_number=_get(histogram_series.spikeIntervalNumbers, i),
204+
empty_interval_number=_get(histogram_series.emptyIntervalNumbers, i),
216205
)
217-
for i, h in enumerate(series.histograms)
206+
for i, h in enumerate(histogram_series.histograms)
218207
]
219208

220209

0 commit comments

Comments
 (0)