Search code examples
pythonplotastronomyhealpyhistogram2d

Make a 2D histogram with HEALPix pixellization using healpy


The data are coordinates of objects in the sky, for example as follows:

import pylab as plt
import numpy as np
l = np.random.uniform(-180, 180, 2000)
b = np.random.uniform(-90, 90, 2000)

I want to do a 2D histogram in order to plot a map of the density of some point with (l, b) coordinates in the sky, using HEALPix pixellization on Mollweide projection. How can I do this using healpy ?

The tutorial:

http://healpy.readthedocs.io/en/v1.9.0/tutorial.html

says how to plot a 1D array, or a fits file, but I don't find how to do a 2d histogram using this pixellization.

I also found this function, but it is not working , so I am stuck.

hp.projaxes.MollweideAxes.hist2d(l, b, bins=10)

I can do a plot of these points in Mollweide projection this way :

l_axis_name ='Latitude l (deg)'
b_axis_name = 'Longitude b (deg)'

fig = plt.figure(figsize=(12,9))
ax = fig.add_subplot(111, projection="mollweide")
ax.grid(True)

ax.scatter(np.array(l)*np.pi/180., np.array(b)*np.pi/180.)

plt.show()

Thank you very much in advance for your help.


Solution

  • Great question! I've written a short function to convert a catalogue into a HEALPix map of number counts:

    from astropy.coordinates import SkyCoord
    import healpy as hp
    import numpy as np
    
    def cat2hpx(lon, lat, nside, radec=True):
        """
        Convert a catalogue to a HEALPix map of number counts per resolution
        element.
    
        Parameters
        ----------
        lon, lat : (ndarray, ndarray)
            Coordinates of the sources in degree. If radec=True, assume input is in the icrs
            coordinate system. Otherwise assume input is glon, glat
    
        nside : int
            HEALPix nside of the target map
    
        radec : bool
            Switch between R.A./Dec and glon/glat as input coordinate system.
    
        Return
        ------
        hpx_map : ndarray
            HEALPix map of the catalogue number counts in Galactic coordinates
    
        """
    
        npix = hp.nside2npix(nside)
    
        if radec:
            eq = SkyCoord(lon, lat, 'icrs', unit='deg')
            l, b = eq.galactic.l.value, eq.galactic.b.value
        else:
            l, b = lon, lat
    
        # conver to theta, phi
        theta = np.radians(90. - b)
        phi = np.radians(l)
    
        # convert to HEALPix indices
        indices = hp.ang2pix(nside, theta, phi)
    
        idx, counts = np.unique(indices, return_counts=True)
    
        # fill the fullsky map
        hpx_map = np.zeros(npix, dtype=int)
        hpx_map[idx] = counts
    
        return hpx_map
    

    You can then use that to populate the HEALPix map:

    l = np.random.uniform(-180, 180, 20000)
    b = np.random.uniform(-90, 90, 20000)
    
    hpx_map = hpx.cat2hpx(l, b, nside=32, radec=False)
    

    Here, the nside determines how fine or coarse your pixel grid is.

    hp.mollview(np.log10(hpx_map+1))
    

    enter image description here

    Also note that by sampling uniformly in Galactic latitude, you'll prefer data points at the Galactic poles. If you want to avoid that, you can scale that down with a cosine.

    hp.orthview(np.log10(hpx_map+1), rot=[0, 90])
    hp.graticule(color='white')
    

    enter image description here