To conserve memory, HealSparse uses a dual-map approach, where a low-resolution full-sky "coverage map" is combined with a high resolution map containing the pixel data where it is available. The resolution of the coverage map is controlled by the nside_coverage
parameter, and the resolution of the high-resolution map is controlled by the nside_sparse
parameter. Behind the scenes, HealSparse uses clever indexing to allow the user to treat these as contiguous maps with minimal overhead. All HealSparse maps use HEALPix nest indexing behind the scenes, should be treated as nest-indexed maps.
There are 3 basic ways to make a HealSparseMap
. First, one can read in an existing HEALPix map; second, one can read in an existing HealSparseMap
; and third, one can create a new map.
To set values in the map, you can use simple indexing or the explicit API:
To retrieve values from the map, you can use simple indexing or the explicit API via pixels or positions:
A HealSparseMap
has the concept of "valid pixels", the pixels over which the map is defined (as opposed to hpgeom.UNSEEN
in the case of floating point maps). You can retrieve the array of valid pixels or the associated positions of the valid pixels easily:
You can convert a HealSparseMap
to a healpy
map (numpy
array) either by using a full slice ([:]
) or with the generate_healpix_map()
method. Do watch out, at high resolution this can blow away your memory! In these cases, generate_healpix_map()
can degrade the map before conversion, using a reduction function (over valid pixels) of your choosing, including mean
, median
, std
, max
, min
, and
, or
, sum
, prod
(product), and wmean
(weighted mean).
In addition to floating-point maps, which are natively supported by healpy
, HealSparseMap
supports integer maps. The "sentinel" value of these maps (equivalent to hpgeom.UNSEEN
) is either -MAXINT
or 0
, depending on the desired use of the map (e.g., integer values or positive bitmasks). Note that these maps cannot be trivially converted to healpy
maps because HEALPix has no concept of sentinel values that are not hpgeom.UNSEEN
, which is a very large negative floating-point value.
HealSparseMap
also supports maps made up of numpy
record arrays. These recarray maps will have one field that is the "primary" field which is used to test if a pixel has a valid value or not. Therefore, these recarray maps should be used to describe associated values that share the exact same valid footprint. Each field in the recarray can be treated as its own HealSparseMap
. For example,
Note that the call map_rec['a'][0: 5000] = values
will work, but map_rec[0: 5000]['a'] = values
will not. Also note that using the fields of the recarray cannot be used to set new pixels, this construction can only be used to change pixel values.
HealSparse has support for "wide" bit masks with an arbitrary number of bits that are referred to by bit position rather than value. This is useful, for example, when constructing a coadd coverage map where every pixel can uniquely identify the set of input exposures that contributed at the location of that pixel. In the case of >64 input exposures you can no longer use a simple 64-bit integer bit mask. Wide mask bits are always specified by giving a list of integer positions rather than values (e.g., use 10
to set the 10th bit instead of 1024 = 2**10
).
Writing a HealSparseMap
is easy. To write a map in the default FITS format:
And to write a map in the Parquet format with pyarrow
:
You can also set key/value metadata to a map that will be stored in the fits header of the file and read back in. The keys must confirm to FITS header key standards (strings, upper case). The metadata will be stored as a Python dictionary, and can be accessed with the metadata
property.
A HealSparseMap
contains a coverage map that defines the coarse coverage over the sky. You can retrieve a boolean array describing which pixels are covered in the map with the coverage_mask
property:
It is also possible to read the coverage map of a HealSparseMap
on its own:
In some cases, you may be building a map and you already know the coverage when it will be finished. In this case, it can be faster to initialize the memory at the beginning. In this case, you can add cov_pixels
to the make_empty
call. Be aware this may make the map larger than your actual coverage.
One can compute the fractional detection map of a HealSparseMap
with the fracdet_map()
method. This method will compute the fractional area covered by the sparse map at an arbitrary resolution (not higher than the native resolution, and not lower than the coverage map nside_coverage
). This is a count of the fraction of "valid" sub-pixels (those that are not equal to the sentinel value) in the original map. These maps can be useful in conjunction with a degraded map to easily determine the coverage fraction of each degraded pixel.
In order to translate a fracdet_map
to lower resolution, the degrade()
method should be used with the default "mean" reduction operation. If one tries to compute the fracdet_map
of an existing fracdet_map
then you will not get the expected output, because this is the fractional coverage of the fracdet_map
itself, not of the original sparse map.
healsparse
does not provide any built-in visualization tools. However, it is possible to perform quick visualizations of a HealSparseMap
using the matplotlib
package. For example, we can take render our map as a collection of hexagonal cells using matplotlib.pyplot.hexbin
: