Source code for hats.pixel_math.sparse_histogram

"""Sparse 1-D histogram of healpix pixel counts."""

import numpy as np

import hats.pixel_math.healpix_shim as hp


[docs] class SparseHistogram: """Wrapper around a naive sparse array, that is just non-zero indexes and counts. e.g. for a dense 1-d numpy histogram of order 0, you might see:: [0, 4, 0, 0, 0, 0, 0, 0, 9, 0, 0] There are only elements at [1, 8], and they have respective values [4, 9]. You would create the sparse histogram like:: SparseHistogram([1, 8], [4, 9], 0) """ def __init__(self, indexes, counts, order): if len(indexes) != len(counts): raise ValueError("indexes and counts must be same length")
[docs] self.indexes = indexes
[docs] self.counts = counts
[docs] self.order = order
[docs] def to_array(self): """Convert the sparse array to a dense numpy array. Returns ------- np.ndarray dense 1-d numpy array. """ dense = np.zeros(hp.order2npix(self.order), dtype=np.int64) dense[self.indexes] = self.counts return dense
[docs] def to_file(self, file_name): """Persist the sparse array to disk. NB: this saves as a sparse array, and so will likely have lower space requirements than saving the corresponding dense 1-d numpy array. Parameters ---------- file_name : path-like intended file to save to """ np.savez(file_name, indexes=self.indexes, counts=self.counts, order=self.order)
[docs] def to_dense_file(self, file_name): """Persist the DENSE array to disk as a numpy array. Parameters ---------- file_name : path-like intended file to save to """ with open(file_name, "wb+") as file_handle: file_handle.write(self.to_array().data)
@classmethod
[docs] def from_file(cls, file_name): """Read sparse histogram from a file. Parameters ---------- file_name : path-like intended file to save read from Returns ------- SparseHistogram new sparse histogram """ npzfile = np.load(file_name) return cls(npzfile["indexes"], npzfile["counts"], npzfile["order"])
[docs] class HistogramAggregator: """Utility for aggregating sparse histograms.""" def __init__(self, order):
[docs] self.order = order
[docs] self.full_histogram = np.zeros(hp.order2npix(order), dtype=np.int64)
[docs] def add(self, other): """Add in another sparse histogram, updating this wrapper's array. Parameters ---------- other : SparseHistogram the wrapper containing the addend """ if not isinstance(other, SparseHistogram): raise ValueError("Both addends should be SparseHistogram.") if self.order != other.order: raise ValueError( "The histogram partials have incompatible sizes due to different healpix orders." ) if len(other.indexes) == 0: return self.full_histogram[other.indexes] += other.counts
[docs] def to_sparse(self): """Return a SparseHistogram, based on non-zero values in this aggregation.""" indexes = self.full_histogram.nonzero()[0] counts = self.full_histogram[indexes] return SparseHistogram(indexes, counts, self.order)